diff options
846 files changed, 17682 insertions, 23724 deletions
diff --git a/api/current.txt b/api/current.txt index 95d1041e48a1..6c4904166ea6 100644 --- a/api/current.txt +++ b/api/current.txt @@ -1288,6 +1288,9 @@ package android { field public static final int thumbTint = 16843889; // 0x1010471 field public static final int thumbTintMode = 16843890; // 0x1010472 field public static final int thumbnail = 16843429; // 0x10102a5 + field public static final int tickMark = 16844043; // 0x101050b + field public static final int tickMarkTint = 16844044; // 0x101050c + field public static final int tickMarkTintMode = 16844045; // 0x101050d field public static final int tileMode = 16843265; // 0x1010201 field public static final int tileModeX = 16843895; // 0x1010477 field public static final int tileModeY = 16843896; // 0x1010478 @@ -2547,6 +2550,7 @@ package android { field public static final int Widget_Material_ScrollView = 16974462; // 0x103027e field public static final int Widget_Material_SearchView = 16974463; // 0x103027f field public static final int Widget_Material_SeekBar = 16974464; // 0x1030280 + field public static final int Widget_Material_SeekBar_Discrete = 16974553; // 0x10302d9 field public static final int Widget_Material_SegmentedButton = 16974465; // 0x1030281 field public static final int Widget_Material_Spinner = 16974467; // 0x1030283 field public static final int Widget_Material_Spinner_Underlined = 16974468; // 0x1030284 @@ -3638,6 +3642,9 @@ package android.app { method public void startActivity(android.content.Context, android.content.Intent, android.os.Bundle); } + public static abstract class ActivityManager.BugreportMode implements java.lang.annotation.Annotation { + } + public static class ActivityManager.MemoryInfo implements android.os.Parcelable { ctor public ActivityManager.MemoryInfo(); method public int describeContents(); @@ -4228,7 +4235,7 @@ package android.app { field public static final java.lang.String COLUMN_DESCRIPTION = "description"; field public static final java.lang.String COLUMN_ID = "_id"; field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp"; - field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename"; + field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename"; field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri"; field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri"; field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type"; @@ -5758,9 +5765,11 @@ package android.app.admin { method public java.lang.String getDeviceOwnerLockScreenInfo(); method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName); method public int getKeyguardDisabledFeatures(android.content.ComponentName); + method public java.lang.String getLongSupportMessage(android.content.ComponentName); method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String); + method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); method public long getPasswordExpirationTimeout(android.content.ComponentName); method public int getPasswordHistoryLength(android.content.ComponentName); @@ -5778,6 +5787,7 @@ package android.app.admin { method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName); method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName); method public boolean getScreenCaptureDisabled(android.content.ComponentName); + method public java.lang.String getShortSupportMessage(android.content.ComponentName); method public boolean getStorageEncryption(android.content.ComponentName); method public int getStorageEncryptionStatus(); method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy(); @@ -5819,6 +5829,7 @@ package android.app.admin { method public boolean setKeyguardDisabled(android.content.ComponentName, boolean); method public void setKeyguardDisabledFeatures(android.content.ComponentName, int); method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException; + method public void setLongSupportMessage(android.content.ComponentName, java.lang.String); method public void setMasterVolumeMuted(android.content.ComponentName, boolean); method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); @@ -5843,6 +5854,7 @@ package android.app.admin { method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName); method public void setScreenCaptureDisabled(android.content.ComponentName, boolean); method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); + method public void setShortSupportMessage(android.content.ComponentName, java.lang.String); method public boolean setStatusBarDisabled(android.content.ComponentName, boolean); method public int setStorageEncryption(android.content.ComponentName, boolean); method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy); @@ -7568,11 +7580,12 @@ package android.content { method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T); } - public class ContentProviderClient { + public class ContentProviderClient implements java.lang.AutoCloseable { method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException; method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException; method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException; method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException; + method public void close(); method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException; method public android.content.ContentProvider getLocalContentProvider(); method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException; @@ -7586,7 +7599,7 @@ package android.content { method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException; method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException; method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException; - method public boolean release(); + method public deprecated boolean release(); method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException; method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException; } @@ -9441,8 +9454,10 @@ package android.content.pm { method public abstract java.lang.String getNameForUid(int); method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int); method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInstaller getPackageInstaller(); + method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String[] getPackagesForUid(int); method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int); method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -9513,6 +9528,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice"; field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir"; field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin"; + field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet"; field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; @@ -10844,7 +10860,7 @@ package android.drm { field public final int statusCode; } - public class DrmManagerClient { + public class DrmManagerClient implements java.lang.AutoCloseable { ctor public DrmManagerClient(android.content.Context); method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest); method public int acquireRights(android.drm.DrmInfoRequest); @@ -10854,6 +10870,7 @@ package android.drm { method public int checkRightsStatus(android.net.Uri); method public int checkRightsStatus(java.lang.String, int); method public int checkRightsStatus(android.net.Uri, int); + method public void close(); method public android.drm.DrmConvertedStatus closeConvertSession(int); method public android.drm.DrmConvertedStatus convertData(int, byte[]); method public java.lang.String[] getAvailableDrmEngines(); @@ -10867,7 +10884,7 @@ package android.drm { method public java.lang.String getOriginalMimeType(android.net.Uri); method public int openConvertSession(java.lang.String); method public int processDrmInfo(android.drm.DrmInfo); - method public void release(); + method public deprecated void release(); method public int removeAllRights(); method public int removeRights(java.lang.String); method public int removeRights(android.net.Uri); @@ -11287,7 +11304,7 @@ package android.graphics { field public int inScreenDensity; field public int inTargetDensity; field public byte[] inTempStorage; - field public boolean mCancel; + field public deprecated boolean mCancel; field public int outHeight; field public java.lang.String outMimeType; field public int outWidth; @@ -22372,6 +22389,24 @@ package android.mtp { ctor public MtpConstants(); method public static boolean isAbstractObject(int); field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1 + field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001 + field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d + field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008 + field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006 + field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b + field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002 + field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007 + field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801 + field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802 + field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803 + field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003 + field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009 + field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c + field public static final int EVENT_STORE_ADDED = 16388; // 0x4004 + field public static final int EVENT_STORE_FULL = 16394; // 0x400a + field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005 + field public static final int EVENT_UNDEFINED = 16384; // 0x4000 + field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984 field public static final int FORMAT_AAC = 47363; // 0xb903 field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03 @@ -22428,6 +22463,41 @@ package android.mtp { field public static final int FORMAT_WMV = 47489; // 0xb981 field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10 field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82 + field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003 + field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a + field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b + field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f + field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001 + field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014 + field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015 + field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006 + field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009 + field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007 + field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008 + field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801 + field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802 + field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803 + field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810 + field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b + field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005 + field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004 + field public static final int OPERATION_GET_THUMB = 4106; // 0x100a + field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e + field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c + field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019 + field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002 + field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013 + field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010 + field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017 + field public static final int OPERATION_SELF_TEST = 4113; // 0x1011 + field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d + field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c + field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016 + field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804 + field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012 + field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811 + field public static final int OPERATION_SKIP = 38944; // 0x9820 + field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018 field public static final int PROTECTION_STATUS_NONE = 0; // 0x0 field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003 field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001 @@ -22445,6 +22515,7 @@ package android.mtp { method public int[] getObjectHandles(int, int, int); method public android.mtp.MtpObjectInfo getObjectInfo(int); method public long getParent(int); + method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException; method public long getStorageId(int); method public int[] getStorageIds(); method public android.mtp.MtpStorageInfo getStorageInfo(int); @@ -22460,6 +22531,7 @@ package android.mtp { public class MtpDeviceInfo { method public final java.lang.String getManufacturer(); method public final java.lang.String getModel(); + method public final int[] getOperationsSupported(); method public final java.lang.String getSerialNumber(); method public final java.lang.String getVersion(); } @@ -22467,24 +22539,6 @@ package android.mtp { public class MtpEvent { ctor public MtpEvent(); method public int getEventCode(); - field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001 - field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d - field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008 - field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006 - field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b - field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002 - field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007 - field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801 - field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802 - field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803 - field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003 - field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009 - field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c - field public static final int EVENT_STORE_ADDED = 16388; // 0x4004 - field public static final int EVENT_STORE_FULL = 16394; // 0x400a - field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005 - field public static final int EVENT_UNDEFINED = 16384; // 0x4000 - field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e } public final class MtpObjectInfo { @@ -28404,6 +28458,7 @@ package android.os { field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi"; field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows"; field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"; + field public static final java.lang.String DISALLOW_DATA_ROAMING = "no_data_roaming"; field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features"; field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset"; field public static final java.lang.String DISALLOW_FUN = "no_fun"; @@ -30771,7 +30826,7 @@ package android.provider { field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type"; field public static final java.lang.String COLUMN_SIZE = "_size"; field public static final java.lang.String COLUMN_SUMMARY = "summary"; - field public static final int FLAG_ARCHIVE = 2048; // 0x800 + field public static final int FLAG_ARCHIVE = 1024; // 0x400 field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10 field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20 field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8 @@ -30780,9 +30835,8 @@ package android.provider { field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 - field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 - field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400 + field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200 field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory"; } @@ -31226,6 +31280,7 @@ package android.provider { field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"; field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"; field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS"; + field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"; field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO"; field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS"; field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS"; @@ -33544,6 +33599,8 @@ package android.service.notification { method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); + method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException; + method public final void requestUnbind() throws android.os.RemoteException; method public final void setNotificationsShown(java.lang.String[]); field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications"; field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 @@ -36039,6 +36096,7 @@ package android.telephony { method public java.lang.String getSubscriberId(); method public java.lang.String getVoiceMailAlphaTag(); method public java.lang.String getVoiceMailNumber(); + method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); method public boolean hasCarrierPrivileges(); method public boolean hasIccCard(); method public boolean iccCloseLogicalChannel(int); @@ -36051,6 +36109,7 @@ package android.telephony { method public boolean isSmsCapable(); method public boolean isTtyModeSupported(); method public boolean isVoiceCapable(); + method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle); method public boolean isWorldPhone(); method public void listen(android.telephony.PhoneStateListener, int); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); @@ -36733,7 +36792,6 @@ package android.test.mock { method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public int getComponentEnabledSetting(android.content.ComponentName); method public android.graphics.drawable.Drawable getDefaultActivityIcon(); - method public java.lang.String getDefaultBrowserPackageName(int); method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); method public byte[] getEphemeralCookie(); method public int getEphemeralCookieMaxSizeBytes(); @@ -36745,8 +36803,10 @@ package android.test.mock { method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String); method public java.lang.String getNameForUid(int); method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; + method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInstaller getPackageInstaller(); + method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] getPackagesForUid(int); method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int); method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -36785,7 +36845,6 @@ package android.test.mock { method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method public void setApplicationEnabledSetting(java.lang.String, int, int); method public void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public boolean setDefaultBrowserPackageName(java.lang.String, int); method public boolean setEphemeralCookie(byte[]); method public void setInstallerPackageName(java.lang.String, java.lang.String); method public void verifyPendingInstall(int, int); @@ -39175,7 +39234,7 @@ package android.util { method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher); field public static final java.util.regex.Pattern DOMAIN_NAME; field public static final java.util.regex.Pattern EMAIL_ADDRESS; - field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; + field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; field public static final java.util.regex.Pattern IP_ADDRESS; field public static final java.util.regex.Pattern PHONE; field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN; @@ -40554,7 +40613,6 @@ package android.view { field public static final int AXIS_RX = 12; // 0xc field public static final int AXIS_RY = 13; // 0xd field public static final int AXIS_RZ = 14; // 0xe - field public static final int AXIS_SCROLL = 26; // 0x1a field public static final int AXIS_SIZE = 3; // 0x3 field public static final int AXIS_THROTTLE = 19; // 0x13 field public static final int AXIS_TILT = 25; // 0x19 @@ -44041,7 +44099,7 @@ package android.webkit { method public abstract deprecated void setEnableSmoothTransition(boolean); method public abstract void setFantasyFontFamily(java.lang.String); method public abstract void setFixedFontFamily(java.lang.String); - method public abstract void setGeolocationDatabasePath(java.lang.String); + method public abstract deprecated void setGeolocationDatabasePath(java.lang.String); method public abstract void setGeolocationEnabled(boolean); method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean); method public abstract void setJavaScriptEnabled(boolean); @@ -44483,12 +44541,18 @@ package android.widget { method public int getThumbOffset(); method public android.content.res.ColorStateList getThumbTintList(); method public android.graphics.PorterDuff.Mode getThumbTintMode(); + method public android.graphics.drawable.Drawable getTickMark(); + method public android.content.res.ColorStateList getTickMarkTintList(); + method public android.graphics.PorterDuff.Mode getTickMarkTintMode(); method public void setKeyProgressIncrement(int); method public void setSplitTrack(boolean); method public void setThumb(android.graphics.drawable.Drawable); method public void setThumbOffset(int); method public void setThumbTintList(android.content.res.ColorStateList); method public void setThumbTintMode(android.graphics.PorterDuff.Mode); + method public void setTickMark(android.graphics.drawable.Drawable); + method public void setTickMarkTintList(android.content.res.ColorStateList); + method public void setTickMarkTintMode(android.graphics.PorterDuff.Mode); } public abstract class AbsSpinner extends android.widget.AdapterView { diff --git a/api/removed.txt b/api/removed.txt index f12e61eea332..6b7961e9f1f6 100644 --- a/api/removed.txt +++ b/api/removed.txt @@ -199,6 +199,15 @@ package android.provider { } +package android.test.mock { + + public class MockPackageManager extends android.content.pm.PackageManager { + method public deprecated java.lang.String getDefaultBrowserPackageName(int); + method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int); + } + +} + package android.text.format { public class DateFormat { diff --git a/api/system-current.txt b/api/system-current.txt index 4dff8fc96c76..3ede80ac0d05 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -1386,6 +1386,9 @@ package android { field public static final int thumbTint = 16843889; // 0x1010471 field public static final int thumbTintMode = 16843890; // 0x1010472 field public static final int thumbnail = 16843429; // 0x10102a5 + field public static final int tickMark = 16844043; // 0x101050b + field public static final int tickMarkTint = 16844044; // 0x101050c + field public static final int tickMarkTintMode = 16844045; // 0x101050d field public static final int tileMode = 16843265; // 0x1010201 field public static final int tileModeX = 16843895; // 0x1010477 field public static final int tileModeY = 16843896; // 0x1010478 @@ -2648,6 +2651,7 @@ package android { field public static final int Widget_Material_ScrollView = 16974462; // 0x103027e field public static final int Widget_Material_SearchView = 16974463; // 0x103027f field public static final int Widget_Material_SeekBar = 16974464; // 0x1030280 + field public static final int Widget_Material_SeekBar_Discrete = 16974553; // 0x10302d9 field public static final int Widget_Material_SegmentedButton = 16974465; // 0x1030281 field public static final int Widget_Material_Spinner = 16974467; // 0x1030283 field public static final int Widget_Material_Spinner_Underlined = 16974468; // 0x1030284 @@ -3749,6 +3753,9 @@ package android.app { method public void startActivity(android.content.Context, android.content.Intent, android.os.Bundle); } + public static abstract class ActivityManager.BugreportMode implements java.lang.annotation.Annotation { + } + public static class ActivityManager.MemoryInfo implements android.os.Parcelable { ctor public ActivityManager.MemoryInfo(); method public int describeContents(); @@ -4348,7 +4355,7 @@ package android.app { field public static final java.lang.String COLUMN_DESCRIPTION = "description"; field public static final java.lang.String COLUMN_ID = "_id"; field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp"; - field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename"; + field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename"; field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri"; field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri"; field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type"; @@ -5886,9 +5893,11 @@ package android.app.admin { method public java.lang.String getDeviceOwnerLockScreenInfo(); method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName); method public int getKeyguardDisabledFeatures(android.content.ComponentName); + method public java.lang.String getLongSupportMessage(android.content.ComponentName); method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String); + method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); method public long getPasswordExpirationTimeout(android.content.ComponentName); method public int getPasswordHistoryLength(android.content.ComponentName); @@ -5910,6 +5919,7 @@ package android.app.admin { method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException; method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException; method public boolean getScreenCaptureDisabled(android.content.ComponentName); + method public java.lang.String getShortSupportMessage(android.content.ComponentName); method public boolean getStorageEncryption(android.content.ComponentName); method public int getStorageEncryptionStatus(); method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy(); @@ -5953,6 +5963,7 @@ package android.app.admin { method public boolean setKeyguardDisabled(android.content.ComponentName, boolean); method public void setKeyguardDisabledFeatures(android.content.ComponentName, int); method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException; + method public void setLongSupportMessage(android.content.ComponentName, java.lang.String); method public void setMasterVolumeMuted(android.content.ComponentName, boolean); method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); @@ -5977,6 +5988,7 @@ package android.app.admin { method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName); method public void setScreenCaptureDisabled(android.content.ComponentName, boolean); method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); + method public void setShortSupportMessage(android.content.ComponentName, java.lang.String); method public boolean setStatusBarDisabled(android.content.ComponentName, boolean); method public int setStorageEncryption(android.content.ComponentName, boolean); method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy); @@ -7811,11 +7823,12 @@ package android.content { method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T); } - public class ContentProviderClient { + public class ContentProviderClient implements java.lang.AutoCloseable { method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException; method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException; method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException; method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException; + method public void close(); method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException; method public android.content.ContentProvider getLocalContentProvider(); method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException; @@ -7829,7 +7842,7 @@ package android.content { method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException; method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException; method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException; - method public boolean release(); + method public deprecated boolean release(); method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException; method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException; } @@ -9742,8 +9755,10 @@ package android.content.pm { method public abstract java.lang.String getNameForUid(int); method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int); method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInstaller getPackageInstaller(); + method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String[] getPackagesForUid(int); method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int); method public abstract int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle); @@ -9823,6 +9838,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice"; field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir"; field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin"; + field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet"; field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; @@ -11198,7 +11214,7 @@ package android.drm { field public final int statusCode; } - public class DrmManagerClient { + public class DrmManagerClient implements java.lang.AutoCloseable { ctor public DrmManagerClient(android.content.Context); method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest); method public int acquireRights(android.drm.DrmInfoRequest); @@ -11208,6 +11224,7 @@ package android.drm { method public int checkRightsStatus(android.net.Uri); method public int checkRightsStatus(java.lang.String, int); method public int checkRightsStatus(android.net.Uri, int); + method public void close(); method public android.drm.DrmConvertedStatus closeConvertSession(int); method public android.drm.DrmConvertedStatus convertData(int, byte[]); method public java.lang.String[] getAvailableDrmEngines(); @@ -11221,7 +11238,7 @@ package android.drm { method public java.lang.String getOriginalMimeType(android.net.Uri); method public int openConvertSession(java.lang.String); method public int processDrmInfo(android.drm.DrmInfo); - method public void release(); + method public deprecated void release(); method public int removeAllRights(); method public int removeRights(java.lang.String); method public int removeRights(android.net.Uri); @@ -11641,7 +11658,7 @@ package android.graphics { field public int inScreenDensity; field public int inTargetDensity; field public byte[] inTempStorage; - field public boolean mCancel; + field public deprecated boolean mCancel; field public int outHeight; field public java.lang.String outMimeType; field public int outWidth; @@ -23918,6 +23935,24 @@ package android.mtp { ctor public MtpConstants(); method public static boolean isAbstractObject(int); field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1 + field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001 + field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d + field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008 + field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006 + field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b + field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002 + field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007 + field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801 + field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802 + field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803 + field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003 + field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009 + field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c + field public static final int EVENT_STORE_ADDED = 16388; // 0x4004 + field public static final int EVENT_STORE_FULL = 16394; // 0x400a + field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005 + field public static final int EVENT_UNDEFINED = 16384; // 0x4000 + field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984 field public static final int FORMAT_AAC = 47363; // 0xb903 field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03 @@ -23974,6 +24009,41 @@ package android.mtp { field public static final int FORMAT_WMV = 47489; // 0xb981 field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10 field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82 + field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003 + field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a + field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b + field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f + field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001 + field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014 + field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015 + field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006 + field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009 + field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007 + field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008 + field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801 + field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802 + field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803 + field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810 + field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b + field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005 + field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004 + field public static final int OPERATION_GET_THUMB = 4106; // 0x100a + field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e + field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c + field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019 + field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002 + field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013 + field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010 + field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017 + field public static final int OPERATION_SELF_TEST = 4113; // 0x1011 + field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d + field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c + field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016 + field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804 + field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012 + field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811 + field public static final int OPERATION_SKIP = 38944; // 0x9820 + field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018 field public static final int PROTECTION_STATUS_NONE = 0; // 0x0 field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003 field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001 @@ -23991,6 +24061,7 @@ package android.mtp { method public int[] getObjectHandles(int, int, int); method public android.mtp.MtpObjectInfo getObjectInfo(int); method public long getParent(int); + method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException; method public long getStorageId(int); method public int[] getStorageIds(); method public android.mtp.MtpStorageInfo getStorageInfo(int); @@ -24006,6 +24077,7 @@ package android.mtp { public class MtpDeviceInfo { method public final java.lang.String getManufacturer(); method public final java.lang.String getModel(); + method public final int[] getOperationsSupported(); method public final java.lang.String getSerialNumber(); method public final java.lang.String getVersion(); } @@ -24013,24 +24085,6 @@ package android.mtp { public class MtpEvent { ctor public MtpEvent(); method public int getEventCode(); - field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001 - field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d - field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008 - field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006 - field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b - field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002 - field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007 - field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801 - field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802 - field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803 - field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003 - field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009 - field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c - field public static final int EVENT_STORE_ADDED = 16388; // 0x4004 - field public static final int EVENT_STORE_FULL = 16394; // 0x400a - field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005 - field public static final int EVENT_UNDEFINED = 16384; // 0x4000 - field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e } public final class MtpObjectInfo { @@ -30407,6 +30461,7 @@ package android.os { field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi"; field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows"; field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"; + field public static final java.lang.String DISALLOW_DATA_ROAMING = "no_data_roaming"; field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features"; field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset"; field public static final java.lang.String DISALLOW_FUN = "no_fun"; @@ -32804,7 +32859,7 @@ package android.provider { field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type"; field public static final java.lang.String COLUMN_SIZE = "_size"; field public static final java.lang.String COLUMN_SUMMARY = "summary"; - field public static final int FLAG_ARCHIVE = 2048; // 0x800 + field public static final int FLAG_ARCHIVE = 1024; // 0x400 field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10 field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20 field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8 @@ -32813,9 +32868,8 @@ package android.provider { field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 - field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 - field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400 + field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200 field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory"; } @@ -33361,6 +33415,7 @@ package android.provider { field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"; field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"; field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS"; + field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"; field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO"; field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS"; field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS"; @@ -35683,6 +35738,8 @@ package android.service.notification { method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException; method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); + method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException; + method public final void requestUnbind() throws android.os.RemoteException; method public final void setNotificationsShown(java.lang.String[]); method public final void setOnNotificationPostedTrim(int); method public void unregisterAsSystemService() throws android.os.RemoteException; @@ -35798,6 +35855,7 @@ package android.service.quicksettings { method public int onTileAdded(); method public void onTileRemoved(); method public static final void requestListeningState(android.content.Context, android.content.ComponentName); + method public final void setStatusIcon(android.graphics.drawable.Icon, java.lang.String); method public final void showDialog(android.app.Dialog); field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE"; field public static final int TILE_MODE_ACTIVE = 2; // 0x2 @@ -38340,6 +38398,7 @@ package android.telephony { method public java.lang.String getSubscriberId(); method public java.lang.String getVoiceMailAlphaTag(); method public java.lang.String getVoiceMailNumber(); + method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); method public boolean handlePinMmi(java.lang.String); method public boolean handlePinMmiForSubscriber(int, java.lang.String); method public boolean hasCarrierPrivileges(); @@ -38361,6 +38420,7 @@ package android.telephony { method public boolean isTtyModeSupported(); method public boolean isVideoCallingEnabled(); method public boolean isVoiceCapable(); + method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle); method public boolean isWorldPhone(); method public void listen(android.telephony.PhoneStateListener, int); method public boolean needsOtaServiceProvisioning(); @@ -39074,7 +39134,6 @@ package android.test.mock { method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public int getComponentEnabledSetting(android.content.ComponentName); method public android.graphics.drawable.Drawable getDefaultActivityIcon(); - method public java.lang.String getDefaultBrowserPackageName(int); method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); method public byte[] getEphemeralCookie(); method public int getEphemeralCookieMaxSizeBytes(); @@ -39086,8 +39145,10 @@ package android.test.mock { method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String); method public java.lang.String getNameForUid(int); method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; + method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInstaller getPackageInstaller(); + method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] getPackagesForUid(int); method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int); method public int getPermissionFlags(java.lang.String, java.lang.String, android.os.UserHandle); @@ -39130,7 +39191,6 @@ package android.test.mock { method public void revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public void setApplicationEnabledSetting(java.lang.String, int, int); method public void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public boolean setDefaultBrowserPackageName(java.lang.String, int); method public boolean setEphemeralCookie(byte[]); method public void setInstallerPackageName(java.lang.String, java.lang.String); method public void updatePermissionFlags(java.lang.String, java.lang.String, int, int, android.os.UserHandle); @@ -41522,7 +41582,7 @@ package android.util { method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher); field public static final java.util.regex.Pattern DOMAIN_NAME; field public static final java.util.regex.Pattern EMAIL_ADDRESS; - field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; + field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; field public static final java.util.regex.Pattern IP_ADDRESS; field public static final java.util.regex.Pattern PHONE; field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN; @@ -42901,7 +42961,6 @@ package android.view { field public static final int AXIS_RX = 12; // 0xc field public static final int AXIS_RY = 13; // 0xd field public static final int AXIS_RZ = 14; // 0xe - field public static final int AXIS_SCROLL = 26; // 0x1a field public static final int AXIS_SIZE = 3; // 0x3 field public static final int AXIS_THROTTLE = 19; // 0x13 field public static final int AXIS_TILT = 25; // 0x19 @@ -46459,7 +46518,7 @@ package android.webkit { method public abstract deprecated void setEnableSmoothTransition(boolean); method public abstract void setFantasyFontFamily(java.lang.String); method public abstract void setFixedFontFamily(java.lang.String); - method public abstract void setGeolocationDatabasePath(java.lang.String); + method public abstract deprecated void setGeolocationDatabasePath(java.lang.String); method public abstract void setGeolocationEnabled(boolean); method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean); method public abstract void setJavaScriptEnabled(boolean); @@ -47146,12 +47205,18 @@ package android.widget { method public int getThumbOffset(); method public android.content.res.ColorStateList getThumbTintList(); method public android.graphics.PorterDuff.Mode getThumbTintMode(); + method public android.graphics.drawable.Drawable getTickMark(); + method public android.content.res.ColorStateList getTickMarkTintList(); + method public android.graphics.PorterDuff.Mode getTickMarkTintMode(); method public void setKeyProgressIncrement(int); method public void setSplitTrack(boolean); method public void setThumb(android.graphics.drawable.Drawable); method public void setThumbOffset(int); method public void setThumbTintList(android.content.res.ColorStateList); method public void setThumbTintMode(android.graphics.PorterDuff.Mode); + method public void setTickMark(android.graphics.drawable.Drawable); + method public void setTickMarkTintList(android.content.res.ColorStateList); + method public void setTickMarkTintMode(android.graphics.PorterDuff.Mode); } public abstract class AbsSpinner extends android.widget.AdapterView { diff --git a/api/system-removed.txt b/api/system-removed.txt index 642d2a8ac19c..90a5dc7c474f 100644 --- a/api/system-removed.txt +++ b/api/system-removed.txt @@ -190,6 +190,15 @@ package android.provider { } +package android.test.mock { + + public class MockPackageManager extends android.content.pm.PackageManager { + method public deprecated java.lang.String getDefaultBrowserPackageName(int); + method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int); + } + +} + package android.text.format { public class DateFormat { diff --git a/api/test-current.txt b/api/test-current.txt index 090644bd3dc6..306cf7362204 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1288,6 +1288,9 @@ package android { field public static final int thumbTint = 16843889; // 0x1010471 field public static final int thumbTintMode = 16843890; // 0x1010472 field public static final int thumbnail = 16843429; // 0x10102a5 + field public static final int tickMark = 16844043; // 0x101050b + field public static final int tickMarkTint = 16844044; // 0x101050c + field public static final int tickMarkTintMode = 16844045; // 0x101050d field public static final int tileMode = 16843265; // 0x1010201 field public static final int tileModeX = 16843895; // 0x1010477 field public static final int tileModeY = 16843896; // 0x1010478 @@ -2547,6 +2550,7 @@ package android { field public static final int Widget_Material_ScrollView = 16974462; // 0x103027e field public static final int Widget_Material_SearchView = 16974463; // 0x103027f field public static final int Widget_Material_SeekBar = 16974464; // 0x1030280 + field public static final int Widget_Material_SeekBar_Discrete = 16974553; // 0x10302d9 field public static final int Widget_Material_SegmentedButton = 16974465; // 0x1030281 field public static final int Widget_Material_Spinner = 16974467; // 0x1030283 field public static final int Widget_Material_Spinner_Underlined = 16974468; // 0x1030284 @@ -3638,6 +3642,9 @@ package android.app { method public void startActivity(android.content.Context, android.content.Intent, android.os.Bundle); } + public static abstract class ActivityManager.BugreportMode implements java.lang.annotation.Annotation { + } + public static class ActivityManager.MemoryInfo implements android.os.Parcelable { ctor public ActivityManager.MemoryInfo(); method public int describeContents(); @@ -4228,7 +4235,7 @@ package android.app { field public static final java.lang.String COLUMN_DESCRIPTION = "description"; field public static final java.lang.String COLUMN_ID = "_id"; field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp"; - field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename"; + field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename"; field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri"; field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri"; field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type"; @@ -5501,8 +5508,10 @@ package android.app { method public android.view.WindowAnimationFrameStats getWindowAnimationFrameStats(); method public android.view.WindowContentFrameStats getWindowContentFrameStats(int); method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows(); + method public boolean grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public boolean injectInputEvent(android.view.InputEvent, boolean); method public final boolean performGlobalAction(int); + method public boolean revokeRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle); method public void setOnAccessibilityEventListener(android.app.UiAutomation.OnAccessibilityEventListener); method public boolean setRotation(int); method public void setRunAsMonkey(boolean); @@ -5758,9 +5767,11 @@ package android.app.admin { method public java.lang.String getDeviceOwnerLockScreenInfo(); method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName); method public int getKeyguardDisabledFeatures(android.content.ComponentName); + method public java.lang.String getLongSupportMessage(android.content.ComponentName); method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName); method public long getMaximumTimeToLock(android.content.ComponentName); method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String); + method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName); method public long getPasswordExpiration(android.content.ComponentName); method public long getPasswordExpirationTimeout(android.content.ComponentName); method public int getPasswordHistoryLength(android.content.ComponentName); @@ -5778,6 +5789,7 @@ package android.app.admin { method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName); method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName); method public boolean getScreenCaptureDisabled(android.content.ComponentName); + method public java.lang.String getShortSupportMessage(android.content.ComponentName); method public boolean getStorageEncryption(android.content.ComponentName); method public int getStorageEncryptionStatus(); method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy(); @@ -5819,6 +5831,7 @@ package android.app.admin { method public boolean setKeyguardDisabled(android.content.ComponentName, boolean); method public void setKeyguardDisabledFeatures(android.content.ComponentName, int); method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException; + method public void setLongSupportMessage(android.content.ComponentName, java.lang.String); method public void setMasterVolumeMuted(android.content.ComponentName, boolean); method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int); method public void setMaximumTimeToLock(android.content.ComponentName, long); @@ -5843,6 +5856,7 @@ package android.app.admin { method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName); method public void setScreenCaptureDisabled(android.content.ComponentName, boolean); method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String); + method public void setShortSupportMessage(android.content.ComponentName, java.lang.String); method public boolean setStatusBarDisabled(android.content.ComponentName, boolean); method public int setStorageEncryption(android.content.ComponentName, boolean); method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy); @@ -7568,11 +7582,12 @@ package android.content { method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T); } - public class ContentProviderClient { + public class ContentProviderClient implements java.lang.AutoCloseable { method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException; method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException; method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException; method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException; + method public void close(); method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException; method public android.content.ContentProvider getLocalContentProvider(); method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException; @@ -7586,7 +7601,7 @@ package android.content { method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException; method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException; method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException; - method public boolean release(); + method public deprecated boolean release(); method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException; method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException; } @@ -7668,6 +7683,7 @@ package android.content { method public static java.util.List<android.content.PeriodicSync> getPeriodicSyncs(android.accounts.Account, java.lang.String); method public java.util.List<android.content.UriPermission> getPersistedUriPermissions(); method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String); + method public static java.lang.String[] getSyncAdapterPackagesForAuthorityAsUser(java.lang.String, int); method public static android.content.SyncAdapterType[] getSyncAdapterTypes(); method public static boolean getSyncAutomatically(android.accounts.Account, java.lang.String); method public final java.lang.String getType(android.net.Uri); @@ -7834,6 +7850,7 @@ package android.content { method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>); method public final java.lang.CharSequence getText(int); method public abstract android.content.res.Resources.Theme getTheme(); + method public abstract int getUserId(); method public abstract deprecated android.graphics.drawable.Drawable getWallpaper(); method public abstract deprecated int getWallpaperDesiredMinimumHeight(); method public abstract deprecated int getWallpaperDesiredMinimumWidth(); @@ -8016,6 +8033,7 @@ package android.content { method public java.lang.Object getSystemService(java.lang.String); method public java.lang.String getSystemServiceName(java.lang.Class<?>); method public android.content.res.Resources.Theme getTheme(); + method public int getUserId(); method public deprecated android.graphics.drawable.Drawable getWallpaper(); method public deprecated int getWallpaperDesiredMinimumHeight(); method public deprecated int getWallpaperDesiredMinimumWidth(); @@ -9068,6 +9086,8 @@ package android.content.pm { ctor public ApplicationInfo(android.content.pm.ApplicationInfo); method public int describeContents(); method public void dump(android.util.Printer, java.lang.String); + method public boolean isPrivilegedApp(); + method public boolean isSystemApp(); method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager); field public static final android.os.Parcelable.Creator<android.content.pm.ApplicationInfo> CREATOR; field public static final int FLAG_ALLOW_BACKUP = 32768; // 0x8000 @@ -9429,6 +9449,7 @@ package android.content.pm { method public abstract android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract int getComponentEnabledSetting(android.content.ComponentName); method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon(); + method public abstract java.lang.String getDefaultBrowserPackageNameAsUser(int); method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); method public abstract byte[] getEphemeralCookie(); method public abstract int getEphemeralCookieMaxSizeBytes(); @@ -9441,8 +9462,10 @@ package android.content.pm { method public abstract java.lang.String getNameForUid(int); method public android.content.pm.PackageInfo getPackageArchiveInfo(java.lang.String, int); method public abstract int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; + method public abstract int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract android.content.pm.PackageInstaller getPackageInstaller(); + method public abstract int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public abstract java.lang.String[] getPackagesForUid(int); method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int); method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -9513,6 +9536,7 @@ package android.content.pm { field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice"; field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir"; field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin"; + field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet"; field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct"; field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand"; @@ -10844,7 +10868,7 @@ package android.drm { field public final int statusCode; } - public class DrmManagerClient { + public class DrmManagerClient implements java.lang.AutoCloseable { ctor public DrmManagerClient(android.content.Context); method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest); method public int acquireRights(android.drm.DrmInfoRequest); @@ -10854,6 +10878,7 @@ package android.drm { method public int checkRightsStatus(android.net.Uri); method public int checkRightsStatus(java.lang.String, int); method public int checkRightsStatus(android.net.Uri, int); + method public void close(); method public android.drm.DrmConvertedStatus closeConvertSession(int); method public android.drm.DrmConvertedStatus convertData(int, byte[]); method public java.lang.String[] getAvailableDrmEngines(); @@ -10867,7 +10892,7 @@ package android.drm { method public java.lang.String getOriginalMimeType(android.net.Uri); method public int openConvertSession(java.lang.String); method public int processDrmInfo(android.drm.DrmInfo); - method public void release(); + method public deprecated void release(); method public int removeAllRights(); method public int removeRights(java.lang.String); method public int removeRights(android.net.Uri); @@ -11287,7 +11312,7 @@ package android.graphics { field public int inScreenDensity; field public int inTargetDensity; field public byte[] inTempStorage; - field public boolean mCancel; + field public deprecated boolean mCancel; field public int outHeight; field public java.lang.String outMimeType; field public int outWidth; @@ -18247,7 +18272,6 @@ package android.icu.util { method public static java.lang.String getCanonicalID(java.lang.String, boolean[]); method public int getDSTSavings(); method public static android.icu.util.TimeZone getDefault(); - method public static int getDefaultTimeZoneType(); method public final java.lang.String getDisplayName(); method public final java.lang.String getDisplayName(java.util.Locale); method public final java.lang.String getDisplayName(android.icu.util.ULocale); @@ -18271,8 +18295,6 @@ package android.icu.util { method public abstract boolean inDaylightTime(java.util.Date); method public boolean isFrozen(); method public boolean observesDaylightTime(); - method public static synchronized void setDefault(android.icu.util.TimeZone); - method public static synchronized void setDefaultTimeZoneType(int); method public void setID(java.lang.String); method public abstract void setRawOffset(int); method public abstract boolean useDaylightTime(); @@ -18285,8 +18307,6 @@ package android.icu.util { field public static final int SHORT_COMMONLY_USED = 6; // 0x6 field public static final int SHORT_GENERIC = 2; // 0x2 field public static final int SHORT_GMT = 4; // 0x4 - field public static final int TIMEZONE_ICU = 0; // 0x0 - field public static final int TIMEZONE_JDK = 1; // 0x1 field public static final android.icu.util.TimeZone UNKNOWN_ZONE; field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown"; } @@ -18382,8 +18402,6 @@ package android.icu.util { method public static java.lang.String getVariant(java.lang.String); method public boolean isRightToLeft(); method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale); - method public static synchronized void setDefault(android.icu.util.ULocale); - method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale); method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String); method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String); method public java.lang.String toLanguageTag(); @@ -22379,6 +22397,24 @@ package android.mtp { ctor public MtpConstants(); method public static boolean isAbstractObject(int); field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1 + field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001 + field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d + field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008 + field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006 + field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b + field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002 + field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007 + field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801 + field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802 + field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803 + field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003 + field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009 + field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c + field public static final int EVENT_STORE_ADDED = 16388; // 0x4004 + field public static final int EVENT_STORE_FULL = 16394; // 0x400a + field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005 + field public static final int EVENT_UNDEFINED = 16384; // 0x4000 + field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984 field public static final int FORMAT_AAC = 47363; // 0xb903 field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03 @@ -22435,6 +22471,41 @@ package android.mtp { field public static final int FORMAT_WMV = 47489; // 0xb981 field public static final int FORMAT_WPL_PLAYLIST = 47632; // 0xba10 field public static final int FORMAT_XML_DOCUMENT = 47746; // 0xba82 + field public static final int OPERATION_CLOSE_SESSION = 4099; // 0x1003 + field public static final int OPERATION_COPY_OBJECT = 4122; // 0x101a + field public static final int OPERATION_DELETE_OBJECT = 4107; // 0x100b + field public static final int OPERATION_FORMAT_STORE = 4111; // 0x100f + field public static final int OPERATION_GET_DEVICE_INFO = 4097; // 0x1001 + field public static final int OPERATION_GET_DEVICE_PROP_DESC = 4116; // 0x1014 + field public static final int OPERATION_GET_DEVICE_PROP_VALUE = 4117; // 0x1015 + field public static final int OPERATION_GET_NUM_OBJECTS = 4102; // 0x1006 + field public static final int OPERATION_GET_OBJECT = 4105; // 0x1009 + field public static final int OPERATION_GET_OBJECT_HANDLES = 4103; // 0x1007 + field public static final int OPERATION_GET_OBJECT_INFO = 4104; // 0x1008 + field public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 38913; // 0x9801 + field public static final int OPERATION_GET_OBJECT_PROP_DESC = 38914; // 0x9802 + field public static final int OPERATION_GET_OBJECT_PROP_VALUE = 38915; // 0x9803 + field public static final int OPERATION_GET_OBJECT_REFERENCES = 38928; // 0x9810 + field public static final int OPERATION_GET_PARTIAL_OBJECT = 4123; // 0x101b + field public static final int OPERATION_GET_STORAGE_INFO = 4101; // 0x1005 + field public static final int OPERATION_GET_STORAGE_I_DS = 4100; // 0x1004 + field public static final int OPERATION_GET_THUMB = 4106; // 0x100a + field public static final int OPERATION_INITIATE_CAPTURE = 4110; // 0x100e + field public static final int OPERATION_INITIATE_OPEN_CAPTURE = 4124; // 0x101c + field public static final int OPERATION_MOVE_OBJECT = 4121; // 0x1019 + field public static final int OPERATION_OPEN_SESSION = 4098; // 0x1002 + field public static final int OPERATION_POWER_DOWN = 4115; // 0x1013 + field public static final int OPERATION_RESET_DEVICE = 4112; // 0x1010 + field public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 4119; // 0x1017 + field public static final int OPERATION_SELF_TEST = 4113; // 0x1011 + field public static final int OPERATION_SEND_OBJECT = 4109; // 0x100d + field public static final int OPERATION_SEND_OBJECT_INFO = 4108; // 0x100c + field public static final int OPERATION_SET_DEVICE_PROP_VALUE = 4118; // 0x1016 + field public static final int OPERATION_SET_OBJECT_PROP_VALUE = 38916; // 0x9804 + field public static final int OPERATION_SET_OBJECT_PROTECTION = 4114; // 0x1012 + field public static final int OPERATION_SET_OBJECT_REFERENCES = 38929; // 0x9811 + field public static final int OPERATION_SKIP = 38944; // 0x9820 + field public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 4120; // 0x1018 field public static final int PROTECTION_STATUS_NONE = 0; // 0x0 field public static final int PROTECTION_STATUS_NON_TRANSFERABLE_DATA = 32771; // 0x8003 field public static final int PROTECTION_STATUS_READ_ONLY = 32769; // 0x8001 @@ -22452,6 +22523,7 @@ package android.mtp { method public int[] getObjectHandles(int, int, int); method public android.mtp.MtpObjectInfo getObjectInfo(int); method public long getParent(int); + method public int getPartialObject(int, int, int, byte[]) throws java.io.IOException; method public long getStorageId(int); method public int[] getStorageIds(); method public android.mtp.MtpStorageInfo getStorageInfo(int); @@ -22467,6 +22539,7 @@ package android.mtp { public class MtpDeviceInfo { method public final java.lang.String getManufacturer(); method public final java.lang.String getModel(); + method public final int[] getOperationsSupported(); method public final java.lang.String getSerialNumber(); method public final java.lang.String getVersion(); } @@ -22474,24 +22547,6 @@ package android.mtp { public class MtpEvent { ctor public MtpEvent(); method public int getEventCode(); - field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001 - field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d - field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008 - field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006 - field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b - field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002 - field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007 - field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801 - field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802 - field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803 - field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003 - field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009 - field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c - field public static final int EVENT_STORE_ADDED = 16388; // 0x4004 - field public static final int EVENT_STORE_FULL = 16394; // 0x400a - field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005 - field public static final int EVENT_UNDEFINED = 16384; // 0x4000 - field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e } public final class MtpObjectInfo { @@ -28366,6 +28421,7 @@ package android.os { public final class UserHandle implements android.os.Parcelable { ctor public UserHandle(android.os.Parcel); method public int describeContents(); + method public static int getAppId(int); method public static android.os.UserHandle readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); method public static void writeToParcel(android.os.UserHandle, android.os.Parcel); @@ -28411,6 +28467,7 @@ package android.os { field public static final java.lang.String DISALLOW_CONFIG_WIFI = "no_config_wifi"; field public static final java.lang.String DISALLOW_CREATE_WINDOWS = "no_create_windows"; field public static final java.lang.String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"; + field public static final java.lang.String DISALLOW_DATA_ROAMING = "no_data_roaming"; field public static final java.lang.String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features"; field public static final java.lang.String DISALLOW_FACTORY_RESET = "no_factory_reset"; field public static final java.lang.String DISALLOW_FUN = "no_fun"; @@ -30781,7 +30838,7 @@ package android.provider { field public static final java.lang.String COLUMN_MIME_TYPE = "mime_type"; field public static final java.lang.String COLUMN_SIZE = "_size"; field public static final java.lang.String COLUMN_SUMMARY = "summary"; - field public static final int FLAG_ARCHIVE = 2048; // 0x800 + field public static final int FLAG_ARCHIVE = 1024; // 0x400 field public static final int FLAG_DIR_PREFERS_GRID = 16; // 0x10 field public static final int FLAG_DIR_PREFERS_LAST_MODIFIED = 32; // 0x20 field public static final int FLAG_DIR_SUPPORTS_CREATE = 8; // 0x8 @@ -30790,9 +30847,8 @@ package android.provider { field public static final int FLAG_SUPPORTS_MOVE = 256; // 0x100 field public static final int FLAG_SUPPORTS_RENAME = 64; // 0x40 field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1 - field public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 512; // 0x200 field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2 - field public static final int FLAG_VIRTUAL_DOCUMENT = 1024; // 0x400 + field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200 field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory"; } @@ -31236,6 +31292,7 @@ package android.provider { field public static final java.lang.String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS"; field public static final java.lang.String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS"; field public static final java.lang.String ACTION_SETTINGS = "android.settings.SETTINGS"; + field public static final java.lang.String ACTION_SHOW_ADMIN_SUPPORT_DETAILS = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"; field public static final java.lang.String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO"; field public static final java.lang.String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS"; field public static final java.lang.String ACTION_SYNC_SETTINGS = "android.settings.SYNC_SETTINGS"; @@ -31390,6 +31447,7 @@ package android.provider { field public static final deprecated java.lang.String TTS_USE_DEFAULTS = "tts_use_defaults"; field public static final deprecated java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled"; field public static final deprecated java.lang.String USE_GOOGLE_MAIL = "use_google_mail"; + field public static final java.lang.String VOICE_INTERACTION_SERVICE = "voice_interaction_service"; field public static final deprecated java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count"; field public static final deprecated java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms"; field public static final deprecated java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on"; @@ -31773,6 +31831,7 @@ package android.provider { field public static final int RESULT_SMS_OUT_OF_MEMORY = 3; // 0x3 field public static final int RESULT_SMS_UNSUPPORTED = 4; // 0x4 field public static final java.lang.String SIM_FULL_ACTION = "android.provider.Telephony.SIM_FULL"; + field public static final java.lang.String SMS_CARRIER_PROVISION_ACTION = "android.provider.Telephony.SMS_CARRIER_PROVISION"; field public static final java.lang.String SMS_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_CB_RECEIVED"; field public static final java.lang.String SMS_DELIVER_ACTION = "android.provider.Telephony.SMS_DELIVER"; field public static final java.lang.String SMS_EMERGENCY_CB_RECEIVED_ACTION = "android.provider.Telephony.SMS_EMERGENCY_CB_RECEIVED"; @@ -33554,6 +33613,8 @@ package android.service.notification { method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap); method public final void requestInterruptionFilter(int); method public final void requestListenerHints(int); + method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException; + method public final void requestUnbind() throws android.os.RemoteException; method public final void setNotificationsShown(java.lang.String[]); field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications"; field public static final int HINT_HOST_DISABLE_EFFECTS = 1; // 0x1 @@ -36049,6 +36110,7 @@ package android.telephony { method public java.lang.String getSubscriberId(); method public java.lang.String getVoiceMailAlphaTag(); method public java.lang.String getVoiceMailNumber(); + method public android.net.Uri getVoicemailRingtoneUri(android.telecom.PhoneAccountHandle); method public boolean hasCarrierPrivileges(); method public boolean hasIccCard(); method public boolean iccCloseLogicalChannel(int); @@ -36061,6 +36123,7 @@ package android.telephony { method public boolean isSmsCapable(); method public boolean isTtyModeSupported(); method public boolean isVoiceCapable(); + method public boolean isVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle); method public boolean isWorldPhone(); method public void listen(android.telephony.PhoneStateListener, int); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); @@ -36617,6 +36680,7 @@ package android.test.mock { method public java.lang.Object getSystemService(java.lang.String); method public java.lang.String getSystemServiceName(java.lang.Class<?>); method public android.content.res.Resources.Theme getTheme(); + method public int getUserId(); method public android.graphics.drawable.Drawable getWallpaper(); method public int getWallpaperDesiredMinimumHeight(); method public int getWallpaperDesiredMinimumWidth(); @@ -36743,7 +36807,7 @@ package android.test.mock { method public android.graphics.drawable.Drawable getApplicationLogo(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; method public int getComponentEnabledSetting(android.content.ComponentName); method public android.graphics.drawable.Drawable getDefaultActivityIcon(); - method public java.lang.String getDefaultBrowserPackageName(int); + method public java.lang.String getDefaultBrowserPackageNameAsUser(int); method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo); method public byte[] getEphemeralCookie(); method public int getEphemeralCookieMaxSizeBytes(); @@ -36755,8 +36819,10 @@ package android.test.mock { method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String); method public java.lang.String getNameForUid(int); method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException; + method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public android.content.pm.PackageInstaller getPackageInstaller(); + method public int getPackageUid(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; method public java.lang.String[] getPackagesForUid(int); method public java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(java.lang.String[], int); method public android.content.pm.PermissionGroupInfo getPermissionGroupInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException; @@ -36795,7 +36861,6 @@ package android.test.mock { method public android.content.pm.ResolveInfo resolveService(android.content.Intent, int); method public void setApplicationEnabledSetting(java.lang.String, int, int); method public void setComponentEnabledSetting(android.content.ComponentName, int, int); - method public boolean setDefaultBrowserPackageName(java.lang.String, int); method public boolean setEphemeralCookie(byte[]); method public void setInstallerPackageName(java.lang.String, java.lang.String); method public void verifyPendingInstall(int, int); @@ -39185,7 +39250,7 @@ package android.util { method public static final java.lang.String digitsAndPlusOnly(java.util.regex.Matcher); field public static final java.util.regex.Pattern DOMAIN_NAME; field public static final java.util.regex.Pattern EMAIL_ADDRESS; - field public static final java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; + field public static final deprecated java.lang.String GOOD_IRI_CHAR = "a-zA-Z0-9\u00a0-\ud7ff\uf900-\ufdcf\ufdf0-\uffef"; field public static final java.util.regex.Pattern IP_ADDRESS; field public static final java.util.regex.Pattern PHONE; field public static final deprecated java.util.regex.Pattern TOP_LEVEL_DOMAIN; @@ -40564,7 +40629,6 @@ package android.view { field public static final int AXIS_RX = 12; // 0xc field public static final int AXIS_RY = 13; // 0xd field public static final int AXIS_RZ = 14; // 0xe - field public static final int AXIS_SCROLL = 26; // 0x1a field public static final int AXIS_SIZE = 3; // 0x3 field public static final int AXIS_THROTTLE = 19; // 0x13 field public static final int AXIS_TILT = 25; // 0x19 @@ -44051,7 +44115,7 @@ package android.webkit { method public abstract deprecated void setEnableSmoothTransition(boolean); method public abstract void setFantasyFontFamily(java.lang.String); method public abstract void setFixedFontFamily(java.lang.String); - method public abstract void setGeolocationDatabasePath(java.lang.String); + method public abstract deprecated void setGeolocationDatabasePath(java.lang.String); method public abstract void setGeolocationEnabled(boolean); method public abstract void setJavaScriptCanOpenWindowsAutomatically(boolean); method public abstract void setJavaScriptEnabled(boolean); @@ -44493,12 +44557,18 @@ package android.widget { method public int getThumbOffset(); method public android.content.res.ColorStateList getThumbTintList(); method public android.graphics.PorterDuff.Mode getThumbTintMode(); + method public android.graphics.drawable.Drawable getTickMark(); + method public android.content.res.ColorStateList getTickMarkTintList(); + method public android.graphics.PorterDuff.Mode getTickMarkTintMode(); method public void setKeyProgressIncrement(int); method public void setSplitTrack(boolean); method public void setThumb(android.graphics.drawable.Drawable); method public void setThumbOffset(int); method public void setThumbTintList(android.content.res.ColorStateList); method public void setThumbTintMode(android.graphics.PorterDuff.Mode); + method public void setTickMark(android.graphics.drawable.Drawable); + method public void setTickMarkTintList(android.content.res.ColorStateList); + method public void setTickMarkTintMode(android.graphics.PorterDuff.Mode); } public abstract class AbsSpinner extends android.widget.AdapterView { diff --git a/api/test-removed.txt b/api/test-removed.txt index f12e61eea332..6b7961e9f1f6 100644 --- a/api/test-removed.txt +++ b/api/test-removed.txt @@ -199,6 +199,15 @@ package android.provider { } +package android.test.mock { + + public class MockPackageManager extends android.content.pm.PackageManager { + method public deprecated java.lang.String getDefaultBrowserPackageName(int); + method public deprecated boolean setDefaultBrowserPackageName(java.lang.String, int); + } + +} + package android.text.format { public class DateFormat { diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index 6302d7418cd0..72e8c3b61027 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -1080,16 +1080,16 @@ public class Am extends BaseCommand { private void runBugReport() throws Exception { String opt; - boolean progress = false; + int bugreportType = ActivityManager.BUGREPORT_OPTION_FULL; while ((opt=nextOption()) != null) { if (opt.equals("--progress")) { - progress = true; + bugreportType = ActivityManager.BUGREPORT_OPTION_INTERACTIVE; } else { System.err.println("Error: Unknown option: " + opt); return; } } - mAm.requestBugReport(progress); + mAm.requestBugReport(bugreportType); System.out.println("Your lovely bug report is being created; please be patient."); } diff --git a/core/java/android/annotation/AppIdInt.java b/core/java/android/annotation/AppIdInt.java new file mode 100644 index 000000000000..29838dd5bd7c --- /dev/null +++ b/core/java/android/annotation/AppIdInt.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package android.annotation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Denotes that the annotated element is a multi-user application ID. This is + * <em>not</em> the same as a UID. + * + * @hide + */ +@Retention(SOURCE) +@Target({METHOD, PARAMETER, FIELD}) +public @interface AppIdInt { +} diff --git a/core/java/android/annotation/UserIdInt.java b/core/java/android/annotation/UserIdInt.java new file mode 100644 index 000000000000..7b9ce25e3f1a --- /dev/null +++ b/core/java/android/annotation/UserIdInt.java @@ -0,0 +1,36 @@ +/* + * 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. + */ + +package android.annotation; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.RetentionPolicy.SOURCE; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Denotes that the annotated element is a multi-user user ID. This is + * <em>not</em> the same as a UID. + * + * @hide + */ +@Retention(SOURCE) +@Target({METHOD, PARAMETER, FIELD}) +public @interface UserIdInt { +} diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index 8346161548aa..64642ac5122d 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -62,7 +62,6 @@ import android.database.Cursor; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.drawable.Drawable; -import android.graphics.Rect; import android.media.AudioManager; import android.media.session.MediaController; import android.net.Uri; @@ -2807,17 +2806,15 @@ public class Activity extends ContextThemeWrapper /** - * Called to move the window and its activity/task to a different stack container. - * For example, a window can move between - * {@link android.app.ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} stack and - * {@link android.app.ActivityManager.StackId#FREEFORM_WORKSPACE_STACK_ID} stack. + * Moves the activity from + * {@link android.app.ActivityManager.StackId#FREEFORM_WORKSPACE_STACK_ID} to + * {@link android.app.ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} stack. * - * @param stackId stack Id to change to. * @hide */ @Override - public void changeWindowStack(int stackId) throws RemoteException { - ActivityManagerNative.getDefault().moveActivityToStack(mToken, stackId); + public void exitFreeformMode() throws RemoteException { + ActivityManagerNative.getDefault().exitFreeformMode(mToken); } /** Returns the current stack Id for the window. diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 8637dde109d7..9540ae1cfbf3 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -17,6 +17,7 @@ package android.app; import android.Manifest; +import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; @@ -36,10 +37,12 @@ import com.android.internal.util.FastPrintWriter; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.UriPermission; import android.content.pm.ApplicationInfo; import android.content.pm.ConfigurationInfo; import android.content.pm.IPackageDataObserver; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; @@ -59,12 +62,15 @@ import android.text.TextUtils; import android.util.DisplayMetrics; import android.util.Size; import android.util.Slog; + import org.xmlpull.v1.XmlSerializer; import java.io.FileDescriptor; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -79,6 +85,36 @@ public class ActivityManager { private final Context mContext; private final Handler mHandler; + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + BUGREPORT_OPTION_FULL, + BUGREPORT_OPTION_INTERACTIVE, + BUGREPORT_OPTION_REMOTE + }) + /** + * Defines acceptable types of bugreports. + * @hide + */ + public @interface BugreportMode {} + /** + * Takes a bugreport without user interference (and hence causing less + * interference to the system), but includes all sections. + * @hide + */ + public static final int BUGREPORT_OPTION_FULL = 0; + /** + * Allows user to monitor progress and enter additional data; might not include all + * sections. + * @hide + */ + public static final int BUGREPORT_OPTION_INTERACTIVE = 1; + /** + * Takes a bugreport requested remotely by administrator of the Device Owner app, + * not the device's user. + * @hide + */ + public static final int BUGREPORT_OPTION_REMOTE = 2; + /** * <a href="{@docRoot}guide/topics/manifest/meta-data-element.html">{@code * <meta-data>}</a> name for a 'home' Activity that declares a package that is to be @@ -2256,6 +2292,45 @@ public class ActivityManager { return clearApplicationUserData(mContext.getPackageName(), null); } + + /** + * Permits an application to get the persistent URI permissions granted to another. + * + * <p>Typically called by Settings. + * + * @param packageName application to look for the granted permissions + * @return list of granted URI permissions + * + * @hide + */ + public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName) { + try { + return ActivityManagerNative.getDefault().getGrantedUriPermissions(packageName, + UserHandle.myUserId()); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't get granted URI permissions for :" + packageName, e); + return ParceledListSlice.emptyList(); + } + } + + /** + * Permits an application to clear the persistent URI permissions granted to another. + * + * <p>Typically called by Settings. + * + * @param packageName application to clear its granted permissions + * + * @hide + */ + public void clearGrantedUriPermissions(String packageName) { + try { + ActivityManagerNative.getDefault().clearGrantedUriPermissions(packageName, + UserHandle.myUserId()); + } catch (RemoteException e) { + Log.e(TAG, "Couldn't clear granted URI permissions for :" + packageName, e); + } + } + /** * Information you can retrieve about any processes that are in an error condition. */ diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index da21099eda2b..624131ee036f 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -1408,6 +1408,26 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM return true; } + case GET_GRANTED_URI_PERMISSIONS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final String packageName = data.readString(); + final int userId = data.readInt(); + final ParceledListSlice<UriPermission> perms = getGrantedUriPermissions(packageName, + userId); + reply.writeNoException(); + perms.writeToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE); + return true; + } + + case CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION: { + data.enforceInterface(IActivityManager.descriptor); + final String packageName = data.readString(); + final int userId = data.readInt(); + clearGrantedUriPermissions(packageName, userId); + reply.writeNoException(); + return true; + } + case SHOW_WAITING_FOR_DEBUGGER_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder b = data.readStrongBinder(); @@ -2286,8 +2306,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM case REQUEST_BUG_REPORT_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); - boolean progress = data.readInt() != 0; - requestBugReport(progress); + int bugreportType = data.readInt(); + requestBugReport(bugreportType); reply.writeNoException(); return true; } @@ -2752,11 +2772,10 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM reply.writeInt(stackId); return true; } - case MOVE_ACTIVITY_TO_STACK_TRANSACTION: { + case EXIT_FREEFORM_MODE_TRANSACTION: { data.enforceInterface(IActivityManager.descriptor); IBinder token = data.readStrongBinder(); - int stackId = data.readInt(); - moveActivityToStack(token, stackId); + exitFreeformMode(token); reply.writeNoException(); return true; } @@ -4612,6 +4631,25 @@ class ActivityManagerProxy implements IActivityManager data.writeInt(incoming ? 1 : 0); mRemote.transact(GET_PERSISTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0); reply.readException(); + @SuppressWarnings("unchecked") + final ParceledListSlice<UriPermission> perms = ParceledListSlice.CREATOR.createFromParcel( + reply); + data.recycle(); + reply.recycle(); + return perms; + } + + @Override + public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName, int userId) + throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(packageName); + data.writeInt(userId); + mRemote.transact(GET_GRANTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0); + reply.readException(); + @SuppressWarnings("unchecked") final ParceledListSlice<UriPermission> perms = ParceledListSlice.CREATOR.createFromParcel( reply); data.recycle(); @@ -4619,6 +4657,19 @@ class ActivityManagerProxy implements IActivityManager return perms; } + @Override + public void clearGrantedUriPermissions(String packageName, int userId) throws RemoteException { + Parcel data = Parcel.obtain(); + Parcel reply = Parcel.obtain(); + data.writeInterfaceToken(IActivityManager.descriptor); + data.writeString(packageName); + data.writeInt(userId); + mRemote.transact(CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION, data, reply, 0); + reply.readException(); + data.recycle(); + reply.recycle(); + } + public void showWaitingForDebugger(IApplicationThread who, boolean waiting) throws RemoteException { Parcel data = Parcel.obtain(); @@ -5769,11 +5820,12 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } - public void requestBugReport(boolean progress) throws RemoteException { + public void requestBugReport(@ActivityManager.BugreportMode int bugreportType) + throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); - data.writeInt(progress ? 1 : 0); + data.writeInt(bugreportType); mRemote.transact(REQUEST_BUG_REPORT_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); @@ -6457,13 +6509,12 @@ class ActivityManagerProxy implements IActivityManager } @Override - public void moveActivityToStack(IBinder token, int stackId) throws RemoteException { + public void exitFreeformMode(IBinder token) throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeInterfaceToken(IActivityManager.descriptor); data.writeStrongBinder(token); - data.writeInt(stackId); - mRemote.transact(MOVE_ACTIVITY_TO_STACK_TRANSACTION, data, reply, 0); + mRemote.transact(EXIT_FREEFORM_MODE_TRANSACTION, data, reply, 0); reply.readException(); data.recycle(); reply.recycle(); diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 177fabe2d25c..81e00ff80e11 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -101,6 +101,9 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.renderscript.RenderScriptCacheDir; import android.security.keystore.AndroidKeyStoreProvider; +import android.system.Os; +import android.system.OsConstants; +import android.system.ErrnoException; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IVoiceInteractor; @@ -820,48 +823,6 @@ public final class ActivityThread { setCoreSettings(coreSettings); - /* - * Two possible indications that this package could be - * sharing its runtime with other packages: - * - * 1.) the sharedUserId attribute is set in the manifest, - * indicating a request to share a VM with other - * packages with the same sharedUserId. - * - * 2.) the application element of the manifest has an - * attribute specifying a non-default process name, - * indicating the desire to run in another packages VM. - * - * If sharing is enabled we do not have a unique application - * in a process and therefore cannot rely on the package - * name inside the runtime. - */ - IPackageManager pm = getPackageManager(); - android.content.pm.PackageInfo pi = null; - try { - pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId()); - } catch (RemoteException e) { - } - if (pi != null) { - boolean sharedUserIdSet = (pi.sharedUserId != null); - boolean processNameNotDefault = - (pi.applicationInfo != null && - !appInfo.packageName.equals(pi.applicationInfo.processName)); - boolean sharable = (sharedUserIdSet || processNameNotDefault); - - // Tell the VMRuntime about the application, unless it is shared - // inside a process. - if (!sharable) { - final List<String> codePaths = new ArrayList<>(); - codePaths.add(appInfo.sourceDir); - if (appInfo.splitSourceDirs != null) { - Collections.addAll(codePaths, appInfo.splitSourceDirs); - } - VMRuntime.registerAppInfo(appInfo.packageName, appInfo.dataDir, - codePaths.toArray(new String[codePaths.size()])); - } - } - AppBindData data = new AppBindData(); data.processName = processName; data.appInfo = appInfo; @@ -1854,7 +1815,9 @@ public final class ActivityThread { ApplicationInfo ai = null; try { ai = getPackageManager().getApplicationInfo(packageName, - PackageManager.GET_SHARED_LIBRARY_FILES, userId); + PackageManager.GET_SHARED_LIBRARY_FILES + | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, + userId); } catch (RemoteException e) { // Ignore } @@ -4697,6 +4660,87 @@ public final class ActivityThread { } } + private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) { + final ApplicationInfo appInfo = loadedApk.getApplicationInfo(); + if (isSharingRuntime(appInfo)) { + // If sharing is enabled we do not have a unique application + // in a process and therefore cannot rely on the package + // name inside the runtime. + return; + } + final List<String> codePaths = new ArrayList<>(); + if ((appInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0) { + codePaths.add(appInfo.sourceDir); + } + if (appInfo.splitSourceDirs != null) { + Collections.addAll(codePaths, appInfo.splitSourceDirs); + } + + if (codePaths.isEmpty()) { + // If there are no code paths there's no need to setup a profile file and register with + // the runtime, + return; + } + + // Add an extension to the file name to better reveal its intended use. + // Keep in sync with BackgroundDexOptService. + final String profileExtension = ".prof"; + final File profileFile = new File(cacheDir, loadedApk.mPackageName + profileExtension); + if (!profileFile.exists()) { + FileDescriptor fd = null; + try { + final int permissions = 0600; // read-write for user. + fd = Os.open(profileFile.getAbsolutePath(), OsConstants.O_CREAT, permissions); + Os.fchmod(fd, permissions); + Os.fchown(fd, appInfo.uid, appInfo.uid); + } catch (ErrnoException e) { + Log.w(TAG, "Unable to create jit profile file " + profileFile, e); + try { + Os.unlink(profileFile.getAbsolutePath()); + } catch (ErrnoException unlinkErr) { + Log.v(TAG, "Unable to unlink jit profile file " + profileFile, unlinkErr); + } + return; + } finally { + IoUtils.closeQuietly(fd); + } + } + + VMRuntime.registerAppInfo(profileFile.getAbsolutePath(), appInfo.dataDir, + codePaths.toArray(new String[codePaths.size()])); + } + + /* + * Two possible indications that this package could be + * sharing its runtime with other packages: + * + * 1) the sharedUserId attribute is set in the manifest, + * indicating a request to share a VM with other + * packages with the same sharedUserId. + * + * 2) the application element of the manifest has an + * attribute specifying a non-default process name, + * indicating the desire to run in another packages VM. + */ + private static boolean isSharingRuntime(ApplicationInfo appInfo) { + IPackageManager pm = getPackageManager(); + android.content.pm.PackageInfo pi = null; + try { + pi = pm.getPackageInfo(appInfo.packageName, 0, UserHandle.myUserId()); + } catch (RemoteException e) { + } + if (pi != null) { + boolean sharedUserIdSet = (pi.sharedUserId != null); + boolean processNameNotDefault = (pi.applicationInfo != null) && + !appInfo.packageName.equals(pi.applicationInfo.processName); + boolean sharable = sharedUserIdSet || processNameNotDefault; + return sharable; + } + // We couldn't get information for the package. Be pessimistic and assume + // it's sharing the runtime. + return true; + } + private void updateDefaultDensity() { if (mCurDefaultDisplayDpi != Configuration.DENSITY_DPI_UNDEFINED && mCurDefaultDisplayDpi != DisplayMetrics.DENSITY_DEVICE @@ -4900,12 +4944,14 @@ public final class ActivityThread { + "due to missing cache directory"); } - // Use codeCacheDir to store generated/compiled graphics code + // Use codeCacheDir to store generated/compiled graphics code and jit profiling data. final File codeCacheDir = appContext.getCodeCacheDir(); if (codeCacheDir != null) { setupGraphicsSupport(data.info, codeCacheDir); + setupJitProfileSupport(data.info, codeCacheDir); } else { - Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory"); + Log.e(TAG, "Unable to setupGraphicsSupport and setupJitProfileSupport " + + "due to missing code-cache directory"); } } diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java index 38562dacbcfd..bf0bd795230e 100644 --- a/core/java/android/app/ActivityTransitionState.java +++ b/core/java/android/app/ActivityTransitionState.java @@ -206,7 +206,7 @@ class ActivityTransitionState { } private void startEnter() { - if (mEnterActivityOptions.isReturning()) { + if (mEnterTransitionCoordinator.isReturning()) { if (mExitingToView != null) { mEnterTransitionCoordinator.viewInstancesReady(mExitingFrom, mExitingTo, mExitingToView); @@ -238,6 +238,7 @@ class ActivityTransitionState { public void onResume() { restoreExitedViews(); + restoreReenteringViews(); } public void clear() { @@ -258,6 +259,15 @@ class ActivityTransitionState { } } + private void restoreReenteringViews() { + if (mEnterTransitionCoordinator != null && mEnterTransitionCoordinator.isReturning()) { + mEnterTransitionCoordinator.forceViewsToAppear(); + mExitingFrom = null; + mExitingTo = null; + mExitingToView = null; + } + } + public boolean startExitBackTransition(final Activity activity) { if (mEnteringNames == null) { return false; diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index a60fbf6374c9..42b18384c588 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -213,10 +213,15 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public int[] getPackageGids(String packageName) + public int[] getPackageGids(String packageName) throws NameNotFoundException { + return getPackageGids(packageName, 0); + } + + @Override + public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException { try { - int[] gids = mPM.getPackageGids(packageName, mContext.getUserId()); + int[] gids = mPM.getPackageGidsEtc(packageName, flags, mContext.getUserId()); if (gids != null) { return gids; } @@ -228,10 +233,20 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public int getPackageUid(String packageName, int userHandle) + public int getPackageUid(String packageName, int flags) throws NameNotFoundException { + return getPackageUidAsUser(packageName, flags, mContext.getUserId()); + } + + @Override + public int getPackageUidAsUser(String packageName, int userId) throws NameNotFoundException { + return getPackageUidAsUser(packageName, 0, userId); + } + + @Override + public int getPackageUidAsUser(String packageName, int flags, int userId) throws NameNotFoundException { try { - int uid = mPM.getPackageUid(packageName, userHandle); + int uid = mPM.getPackageUidEtc(packageName, flags, userId); if (uid >= 0) { return uid; } @@ -590,12 +605,12 @@ public class ApplicationPackageManager extends PackageManager { @SuppressWarnings("unchecked") @Override public List<PackageInfo> getInstalledPackages(int flags) { - return getInstalledPackages(flags, mContext.getUserId()); + return getInstalledPackagesAsUser(flags, mContext.getUserId()); } /** @hide */ @Override - public List<PackageInfo> getInstalledPackages(int flags, int userId) { + public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) { try { ParceledListSlice<PackageInfo> slice = mPM.getInstalledPackages(flags, userId); return slice.getList(); @@ -779,7 +794,7 @@ public class ApplicationPackageManager extends PackageManager { * @hide */ @Override - public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) { + public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) { try { return mPM.queryIntentReceivers( intent, @@ -793,7 +808,7 @@ public class ApplicationPackageManager extends PackageManager { @Override public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags) { - return queryBroadcastReceivers(intent, flags, mContext.getUserId()); + return queryBroadcastReceiversAsUser(intent, flags, mContext.getUserId()); } @Override @@ -1546,7 +1561,7 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public int getIntentVerificationStatus(String packageName, int userId) { + public int getIntentVerificationStatusAsUser(String packageName, int userId) { try { return mPM.getIntentVerificationStatus(packageName, userId); } catch (RemoteException e) { @@ -1556,7 +1571,7 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public boolean updateIntentVerificationStatus(String packageName, int status, int userId) { + public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) { try { return mPM.updateIntentVerificationStatus(packageName, status, userId); } catch (RemoteException e) { @@ -1586,7 +1601,7 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public String getDefaultBrowserPackageName(int userId) { + public String getDefaultBrowserPackageNameAsUser(int userId) { try { return mPM.getDefaultBrowserPackageName(userId); } catch (RemoteException e) { @@ -1596,7 +1611,7 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public boolean setDefaultBrowserPackageName(String packageName, int userId) { + public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) { try { return mPM.setDefaultBrowserPackageName(packageName, userId); } catch (RemoteException e) { @@ -1867,7 +1882,7 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public void getPackageSizeInfo(String packageName, int userHandle, + public void getPackageSizeInfoAsUser(String packageName, int userHandle, IPackageStatsObserver observer) { try { mPM.getPackageSizeInfo(packageName, userHandle, observer); @@ -1914,7 +1929,7 @@ public class ApplicationPackageManager extends PackageManager { } @Override - public void addPreferredActivity(IntentFilter filter, int match, + public void addPreferredActivityAsUser(IntentFilter filter, int match, ComponentName[] set, ComponentName activity, int userId) { try { mPM.addPreferredActivity(filter, match, set, activity, userId); diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java index 984a18615caf..a147cc87d465 100644 --- a/core/java/android/app/BackStackRecord.java +++ b/core/java/android/app/BackStackRecord.java @@ -719,7 +719,7 @@ final class BackStackRecord extends FragmentTransaction implements Fragment f = op.fragment; int containerId = f.mContainerId; if (mManager.mAdded != null) { - for (int i = 0; i < mManager.mAdded.size(); i++) { + for (int i = mManager.mAdded.size() - 1; i >= 0; i--) { Fragment old = mManager.mAdded.get(i); if (FragmentManagerImpl.DEBUG) { Log.v(TAG, diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java index fb0e79b849b2..ed4bb28427ae 100644 --- a/core/java/android/app/DownloadManager.java +++ b/core/java/android/app/DownloadManager.java @@ -27,6 +27,7 @@ import android.database.CursorWrapper; import android.net.ConnectivityManager; import android.net.NetworkPolicyManager; import android.net.Uri; +import android.os.Build; import android.os.Environment; import android.os.ParcelFileDescriptor; import android.provider.Downloads; @@ -105,8 +106,17 @@ public class DownloadManager { public final static String COLUMN_LOCAL_URI = "local_uri"; /** - * The pathname of the file where the download is stored. + * Path to the downloaded file on disk. + * <p> + * Note that apps may not have filesystem permissions to directly access + * this path. Instead of trying to open this path directly, apps should use + * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain access. + * + * @deprecated apps should transition to using + * {@link ContentResolver#openFileDescriptor(Uri, String)} + * instead. */ + @Deprecated public final static String COLUMN_LOCAL_FILENAME = "local_filename"; /** @@ -908,16 +918,22 @@ public class DownloadManager { } } - private ContentResolver mResolver; - private String mPackageName; + private final ContentResolver mResolver; + private final String mPackageName; + private Uri mBaseUri = Downloads.Impl.CONTENT_URI; + private boolean mAccessFilename; /** * @hide */ - public DownloadManager(ContentResolver resolver, String packageName) { - mResolver = resolver; - mPackageName = packageName; + public DownloadManager(Context context) { + mResolver = context.getContentResolver(); + mPackageName = context.getPackageName(); + + // Callers can access filename columns when targeting old platform + // versions; otherwise we throw telling them it's deprecated. + mAccessFilename = context.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N; } /** @@ -933,6 +949,11 @@ public class DownloadManager { } } + /** {@hide} */ + public void setAccessFilename(boolean accessFilename) { + mAccessFilename = accessFilename; + } + /** * Enqueue a new download. The download will start automatically once the download manager is * ready to execute it and connectivity is available. @@ -997,7 +1018,7 @@ public class DownloadManager { if (underlyingCursor == null) { return null; } - return new CursorTranslator(underlyingCursor, mBaseUri); + return new CursorTranslator(underlyingCursor, mBaseUri, mAccessFilename); } /** @@ -1265,11 +1286,13 @@ public class DownloadManager { * underlying data. */ private static class CursorTranslator extends CursorWrapper { - private Uri mBaseUri; + private final Uri mBaseUri; + private final boolean mAccessFilename; - public CursorTranslator(Cursor cursor, Uri baseUri) { + public CursorTranslator(Cursor cursor, Uri baseUri, boolean accessFilename) { super(cursor); mBaseUri = baseUri; + mAccessFilename = accessFilename; } @Override @@ -1290,8 +1313,19 @@ public class DownloadManager { @Override public String getString(int columnIndex) { - return (getColumnName(columnIndex).equals(COLUMN_LOCAL_URI)) ? getLocalUri() : - super.getString(columnIndex); + final String columnName = getColumnName(columnIndex); + switch (columnName) { + case COLUMN_LOCAL_URI: + return getLocalUri(); + case COLUMN_LOCAL_FILENAME: + if (!mAccessFilename) { + throw new IllegalArgumentException( + "COLUMN_LOCAL_FILENAME is deprecated;" + + " use ContentResolver.openFileDescriptor() instead"); + } + default: + return super.getString(columnIndex); + } } private String getLocalUri() { diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index c6cc452f5bb7..fe9cc8055262 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -30,6 +30,7 @@ import android.view.View; import android.view.ViewGroup; import android.view.ViewGroupOverlay; import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnPreDrawListener; import android.view.Window; import android.view.accessibility.AccessibilityEvent; @@ -57,6 +58,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { private boolean mAreViewsReady; private boolean mIsViewsTransitionStarted; private Transition mEnterViewsTransition; + private OnPreDrawListener mViewsReadyListener; public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver, ArrayList<String> sharedElementNames, boolean isReturning) { @@ -138,15 +140,16 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { (sharedElements.isEmpty() || !sharedElements.valueAt(0).isLayoutRequested()))) { viewsReady(sharedElements); } else { - decor.getViewTreeObserver() - .addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { - @Override - public boolean onPreDraw() { - decor.getViewTreeObserver().removeOnPreDrawListener(this); - viewsReady(sharedElements); - return true; - } - }); + mViewsReadyListener = new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + mViewsReadyListener = null; + decor.getViewTreeObserver().removeOnPreDrawListener(this); + viewsReady(sharedElements); + return true; + } + }; + decor.getViewTreeObserver().addOnPreDrawListener(mViewsReadyListener); } } @@ -241,6 +244,50 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } } + /** + * This is called onResume. If an Activity is resuming and the transitions + * haven't started yet, force the views to appear. This is likely to be + * caused by the top Activity finishing before the transitions started. + * In that case, we can finish any transition that was started, but we + * should cancel any pending transition and just bring those Views visible. + */ + public void forceViewsToAppear() { + if (!mIsReturning) { + return; + } + if (!mIsReadyForTransition) { + mIsReadyForTransition = true; + final ViewGroup decor = getDecor(); + if (decor != null && mViewsReadyListener != null) { + decor.getViewTreeObserver().removeOnPreDrawListener(mViewsReadyListener); + mViewsReadyListener = null; + } + showViews(mTransitioningViews, true); + mSharedElements.clear(); + mAllSharedElementNames.clear(); + mTransitioningViews.clear(); + mIsReadyForTransition = true; + viewsTransitionComplete(); + sharedElementTransitionComplete(); + } else { + if (!mSharedElementTransitionStarted) { + moveSharedElementsFromOverlay(); + mSharedElementTransitionStarted = true; + showViews(mSharedElements, true); + mSharedElements.clear(); + sharedElementTransitionComplete(); + } + if (!mIsViewsTransitionStarted) { + mIsViewsTransitionStarted = true; + showViews(mTransitioningViews, true); + mTransitioningViews.clear(); + viewsTransitionComplete(); + } + cancelPendingTransitions(); + } + mAreViewsReady = true; + } + private void cancel() { if (!mIsCanceled) { mIsCanceled = true; @@ -659,5 +706,4 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } }); } - } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index ceb14ad6d5d2..1ae91a65bba2 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -276,6 +276,15 @@ public interface IActivityManager extends IInterface { public ParceledListSlice<UriPermission> getPersistedUriPermissions( String packageName, boolean incoming) throws RemoteException; + // Gets the URI permissions granted to an arbitrary package. + // NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package + // granted to another packages (instead of those granted to it). + public ParceledListSlice<UriPermission> getGrantedUriPermissions(String packageName, int userId) + throws RemoteException; + + // Clears the URI permissions granted to an arbitrary package. + public void clearGrantedUriPermissions(String packageName, int userId) throws RemoteException; + public void showWaitingForDebugger(IApplicationThread who, boolean waiting) throws RemoteException; @@ -464,7 +473,7 @@ public interface IActivityManager extends IInterface { public void registerUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException; public void unregisterUserSwitchObserver(IUserSwitchObserver observer) throws RemoteException; - public void requestBugReport(boolean progress) throws RemoteException; + public void requestBugReport(int bugreportType) throws RemoteException; public long inputDispatchingTimedOut(int pid, boolean aboveSystem, String reason) throws RemoteException; @@ -564,7 +573,7 @@ public interface IActivityManager extends IInterface { public boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException; public int getActivityStackId(IBinder token) throws RemoteException; - public void moveActivityToStack(IBinder token, int stackId) throws RemoteException; + public void exitFreeformMode(IBinder token) throws RemoteException; public void suppressResizeConfigChanges(boolean suppress) throws RemoteException; @@ -933,7 +942,7 @@ public interface IActivityManager extends IInterface { int STOP_BINDER_TRACKING_AND_DUMP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 341; int POSITION_TASK_IN_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 342; int GET_ACTIVITY_STACK_ID_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 343; - int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344; + int EXIT_FREEFORM_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344; int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345; int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346; int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347; @@ -949,4 +958,6 @@ public interface IActivityManager extends IInterface { int GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 357; int RESIZE_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 358; int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 359; + int GET_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 360; + int CLEAR_GRANTED_URI_PERMISSIONS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 361; } diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl index e60cb0377e96..633f6995b986 100644 --- a/core/java/android/app/INotificationManager.aidl +++ b/core/java/android/app/INotificationManager.aidl @@ -68,6 +68,9 @@ interface INotificationManager void cancelNotificationFromListener(in INotificationListener token, String pkg, String tag, int id); void cancelNotificationsFromListener(in INotificationListener token, in String[] keys); + void requestBindListener(in ComponentName component); + void requestUnbindListener(in INotificationListener token); + void setNotificationsShownFromListener(in INotificationListener token, in String[] keys); ParceledListSlice getActiveNotificationsFromListener(in INotificationListener token, in String[] keys, int trim); diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java index 288a2cb5fa4f..89d52f248bde 100644 --- a/core/java/android/app/SystemServiceRegistry.java +++ b/core/java/android/app/SystemServiceRegistry.java @@ -247,7 +247,7 @@ final class SystemServiceRegistry { new CachedServiceFetcher<DownloadManager>() { @Override public DownloadManager createService(ContextImpl ctx) { - return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName()); + return new DownloadManager(ctx); }}); registerService(Context.BATTERY_SERVICE, BatteryManager.class, diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index f7848f98b006..8475840bbae2 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -22,6 +22,7 @@ import android.accessibilityservice.AccessibilityServiceInfo; import android.accessibilityservice.IAccessibilityServiceClient; import android.accessibilityservice.IAccessibilityServiceConnection; import android.annotation.NonNull; +import android.annotation.TestApi; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Point; @@ -856,6 +857,7 @@ public final class UiAutomation { * * @hide */ + @TestApi public boolean grantRuntimePermission(String packageName, String permission, UserHandle userHandle) { synchronized (mLock) { @@ -884,6 +886,7 @@ public final class UiAutomation { * * @hide */ + @TestApi public boolean revokeRuntimePermission(String packageName, String permission, UserHandle userHandle) { synchronized (mLock) { diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index eda098252aa0..08e9b1e897af 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -88,13 +88,15 @@ public class DevicePolicyManager { private final Context mContext; private final IDevicePolicyManager mService; + private boolean mParentInstance; private static final String REMOTE_EXCEPTION_MESSAGE = "Failed to talk with device policy manager service"; - private DevicePolicyManager(Context context) { + private DevicePolicyManager(Context context, boolean parentInstance) { this(context, IDevicePolicyManager.Stub.asInterface( ServiceManager.getService(Context.DEVICE_POLICY_SERVICE))); + mParentInstance = parentInstance; } /** @hide */ @@ -106,7 +108,7 @@ public class DevicePolicyManager { /** @hide */ public static DevicePolicyManager create(Context context) { - DevicePolicyManager me = new DevicePolicyManager(context); + DevicePolicyManager me = new DevicePolicyManager(context, false); return me.mService != null ? me : null; } @@ -1031,7 +1033,7 @@ public class DevicePolicyManager { public void setPasswordQuality(@NonNull ComponentName admin, int quality) { if (mService != null) { try { - mService.setPasswordQuality(admin, quality); + mService.setPasswordQuality(admin, quality, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1052,7 +1054,7 @@ public class DevicePolicyManager { public int getPasswordQuality(@Nullable ComponentName admin, int userHandle) { if (mService != null) { try { - return mService.getPasswordQuality(admin, userHandle); + return mService.getPasswordQuality(admin, userHandle, mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1622,7 +1624,7 @@ public class DevicePolicyManager { public boolean isActivePasswordSufficient() { if (mService != null) { try { - return mService.isActivePasswordSufficient(myUserId()); + return mService.isActivePasswordSufficient(myUserId(), mParentInstance); } catch (RemoteException e) { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); } @@ -1791,6 +1793,9 @@ public class DevicePolicyManager { * not acceptable for the current constraints or if the user has not been decrypted yet. */ public boolean resetPassword(String password, int flags) { + if (mParentInstance) { + throw new SecurityException("Reset password does not work across profiles."); + } if (mService != null) { try { return mService.resetPassword(password, flags); @@ -3060,6 +3065,8 @@ public class DevicePolicyManager { * * <p>If the device owner information is {@code null} or empty then the device owner info is * cleared and the user owner info is shown on the lock screen if it is set. + * <p>If the device owner information contains only whitespaces then the message on the lock + * screen will be blank and the user will not be allowed to change it. * * @param admin The name of the admin component to check. * @param info Device owner information which will be displayed instead of the user @@ -4802,4 +4809,148 @@ public class DevicePolicyManager { Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); } } + + /** + * Called by a device admin to set the short support message. This will + * be displayed to the user in settings screens where funtionality has + * been disabled by the admin. + * + * The message should be limited to a short statement such as + * "This setting is disabled by your administrator. Contact someone@example.com + * for support." + * If the message is longer than 200 characters it may be truncated. + * + * @see #setLongSupportMessage + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param message Short message to be displayed to the user in settings or null to + * clear the existing message. + */ + public void setShortSupportMessage(@NonNull ComponentName admin, + @Nullable String message) { + if (mService != null) { + try { + mService.setShortSupportMessage(admin, message); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + } + + /** + * Called by a device admin to get the short support message. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return The message set by {@link #setShortSupportMessage(ComponentName, String)} + * or null if no message has been set. + */ + public String getShortSupportMessage(@NonNull ComponentName admin) { + if (mService != null) { + try { + return mService.getShortSupportMessage(admin); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + return null; + } + + /** + * Called by a device admin to set the long support message. This will + * be displayed to the user in the device administators settings screen. + * + * @see #setShortSupportMessage + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param message Long message to be displayed to the user in settings or null to + * clear the existing message. + */ + public void setLongSupportMessage(@NonNull ComponentName admin, + @Nullable String message) { + if (mService != null) { + try { + mService.setLongSupportMessage(admin, message); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + } + + /** + * Called by a device admin to get the long support message. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return The message set by {@link #setLongSupportMessage(ComponentName, String)} + * or null if no message has been set. + */ + public String getLongSupportMessage(@NonNull ComponentName admin) { + if (mService != null) { + try { + return mService.getLongSupportMessage(admin); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + return null; + } + + /** + * Called by the system to get the short support message. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param userHandle user id the admin is running as. + * @return The message set by {@link #setShortSupportMessage(ComponentName, String)} + * + * @hide + */ + public String getShortSupportMessageForUser(@NonNull ComponentName admin, int userHandle) { + if (mService != null) { + try { + return mService.getShortSupportMessageForUser(admin, userHandle); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + return null; + } + + + /** + * Called by the system to get the long support message. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param userHandle user id the admin is running as. + * @return The message set by {@link #setLongSupportMessage(ComponentName, String)} + * + * @hide + */ + public String getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) { + if (mService != null) { + try { + return mService.getLongSupportMessageForUser(admin, userHandle); + } catch (RemoteException e) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e); + } + } + return null; + } + + /** + * Obtains a {@link DevicePolicyManager} whose calls act on the parent profile. + * + * <p> Note only some methods will work on the parent Manager. + * + * @return a new instance of {@link DevicePolicyManager} that acts on the parent profile. + */ + public DevicePolicyManager getParentProfileInstance(@NonNull ComponentName admin) { + try { + if (!mService.isManagedProfile(admin)) { + throw new SecurityException("The current user does not have a parent profile."); + } + return new DevicePolicyManager(mContext, true); + } catch (RemoteException re) { + Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re); + return null; + } + } } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 30ce682ef888..754cb432bf7c 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -35,8 +35,8 @@ import java.util.List; * {@hide} */ interface IDevicePolicyManager { - void setPasswordQuality(in ComponentName who, int quality); - int getPasswordQuality(in ComponentName who, int userHandle); + void setPasswordQuality(in ComponentName who, int quality, boolean parent); + int getPasswordQuality(in ComponentName who, int userHandle, boolean parent); void setPasswordMinimumLength(in ComponentName who, int length); int getPasswordMinimumLength(in ComponentName who, int userHandle); @@ -67,7 +67,7 @@ interface IDevicePolicyManager { long getPasswordExpiration(in ComponentName who, int userHandle); - boolean isActivePasswordSufficient(int userHandle); + boolean isActivePasswordSufficient(int userHandle, boolean parent); int getCurrentFailedPasswordAttempts(int userHandle); int getProfileWithMinimumFailedPasswordsForWipe(int userHandle); @@ -245,4 +245,12 @@ interface IDevicePolicyManager { boolean isSystemOnlyUser(in ComponentName admin); String getWifiMacAddress(); void reboot(in ComponentName admin); + + void setShortSupportMessage(in ComponentName admin, in String message); + String getShortSupportMessage(in ComponentName admin); + void setLongSupportMessage(in ComponentName admin, in String message); + String getLongSupportMessage(in ComponentName admin); + + String getShortSupportMessageForUser(in ComponentName admin, int userHandle); + String getLongSupportMessageForUser(in ComponentName admin, int userHandle); } diff --git a/core/java/android/app/job/JobScheduler.java b/core/java/android/app/job/JobScheduler.java index a1c11f335091..6e96da5b4667 100644 --- a/core/java/android/app/job/JobScheduler.java +++ b/core/java/android/app/job/JobScheduler.java @@ -50,18 +50,15 @@ public abstract class JobScheduler { */ public static final int RESULT_FAILURE = 0; /** - * Returned from {@link #schedule(JobInfo)} if this application has made too many requests for - * work over too short a time. + * Returned from {@link #schedule(JobInfo)} if this job has been successfully scheduled. */ - // TODO: Determine if this is necessary. public static final int RESULT_SUCCESS = 1; /** * @param job The job you wish scheduled. See * {@link android.app.job.JobInfo.Builder JobInfo.Builder} for more detail on the sorts of jobs * you can schedule. - * @return If >0, this int returns the jobId of the successfully scheduled job. - * Otherwise you have to compare the return value to the error codes defined in this class. + * @return An int representing ({@link #RESULT_SUCCESS} or {@link #RESULT_FAILURE}). */ public abstract int schedule(JobInfo job); diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java index d12595f7ac07..9221fbb50c96 100644 --- a/core/java/android/content/ContentProviderClient.java +++ b/core/java/android/content/ContentProviderClient.java @@ -19,6 +19,7 @@ package android.content; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.res.AssetFileDescriptor; +import android.database.CrossProcessCursorWrapper; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; @@ -32,27 +33,34 @@ import android.os.RemoteException; import android.util.Log; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import dalvik.system.CloseGuard; import java.io.FileNotFoundException; import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; /** - * The public interface object used to interact with a {@link ContentProvider}. This is obtained by - * calling {@link ContentResolver#acquireContentProviderClient}. This object must be released - * using {@link #release} in order to indicate to the system that the {@link ContentProvider} is - * no longer needed and can be killed to free up resources. - * - * <p>Note that you should generally create a new ContentProviderClient instance - * for each thread that will be performing operations. Unlike + * The public interface object used to interact with a specific + * {@link ContentProvider}. + * <p> + * Instances can be obtained by calling + * {@link ContentResolver#acquireContentProviderClient} or + * {@link ContentResolver#acquireUnstableContentProviderClient}. Instances must + * be released using {@link #close()} in order to indicate to the system that + * the underlying {@link ContentProvider} is no longer needed and can be killed + * to free up resources. + * <p> + * Note that you should generally create a new ContentProviderClient instance + * for each thread that will be performing operations. Unlike * {@link ContentResolver}, the methods here such as {@link #query} and - * {@link #openFile} are not thread safe -- you must not call - * {@link #release()} on the ContentProviderClient those calls are made from - * until you are finished with the data they have returned. + * {@link #openFile} are not thread safe -- you must not call {@link #close()} + * on the ContentProviderClient those calls are made from until you are finished + * with the data they have returned. */ -public class ContentProviderClient { +public class ContentProviderClient implements AutoCloseable { private static final String TAG = "ContentProviderClient"; @GuardedBy("ContentProviderClient.class") @@ -63,22 +71,23 @@ public class ContentProviderClient { private final String mPackageName; private final boolean mStable; - private final CloseGuard mGuard = CloseGuard.get(); + private final AtomicBoolean mClosed = new AtomicBoolean(); + private final CloseGuard mCloseGuard = CloseGuard.get(); private long mAnrTimeout; private NotRespondingRunnable mAnrRunnable; - private boolean mReleased; - /** {@hide} */ - ContentProviderClient( + @VisibleForTesting + public ContentProviderClient( ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) { mContentResolver = contentResolver; mContentProvider = contentProvider; mPackageName = contentResolver.mPackageName; + mStable = stable; - mGuard.open("release"); + mCloseGuard.open("close"); } /** {@hide} */ @@ -133,8 +142,18 @@ public class ContentProviderClient { remoteCancellationSignal = mContentProvider.createCancellationSignal(); cancellationSignal.setRemote(remoteCancellationSignal); } - return mContentProvider.query(mPackageName, url, projection, selection, selectionArgs, - sortOrder, remoteCancellationSignal); + final Cursor cursor = mContentProvider.query(mPackageName, url, projection, selection, + selectionArgs, sortOrder, remoteCancellationSignal); + if (cursor == null) { + return null; + } + + if ("com.google.android.gms".equals(mPackageName)) { + // They're casting to a concrete subclass, sigh + return cursor; + } else { + return new CursorWrapperInner(cursor); + } } catch (DeadObjectException e) { if (!mStable) { mContentResolver.unstableProviderDied(mContentProvider); @@ -446,29 +465,42 @@ public class ContentProviderClient { } /** - * Call this to indicate to the system that the associated {@link ContentProvider} is no - * longer needed by this {@link ContentProviderClient}. - * @return true if this was release, false if it was already released + * Closes this client connection, indicating to the system that the + * underlying {@link ContentProvider} is no longer needed. */ + @Override + public void close() { + closeInternal(); + } + + /** + * @deprecated replaced by {@link #close()}. + */ + @Deprecated public boolean release() { - synchronized (this) { - if (mReleased) { - throw new IllegalStateException("Already released"); - } - mReleased = true; - mGuard.close(); + return closeInternal(); + } + + private boolean closeInternal() { + mCloseGuard.close(); + if (mClosed.compareAndSet(false, true)) { if (mStable) { return mContentResolver.releaseProvider(mContentProvider); } else { return mContentResolver.releaseUnstableProvider(mContentProvider); } + } else { + return false; } } @Override protected void finalize() throws Throwable { - if (mGuard != null) { - mGuard.warnIfOpen(); + try { + mCloseGuard.warnIfOpen(); + close(); + } finally { + super.finalize(); } } @@ -502,4 +534,29 @@ public class ContentProviderClient { mContentResolver.appNotRespondingViaProvider(mContentProvider); } } + + private final class CursorWrapperInner extends CrossProcessCursorWrapper { + private final CloseGuard mCloseGuard = CloseGuard.get(); + + CursorWrapperInner(Cursor cursor) { + super(cursor); + mCloseGuard.open("close"); + } + + @Override + public void close() { + mCloseGuard.close(); + super.close(); + } + + @Override + protected void finalize() throws Throwable { + try { + mCloseGuard.warnIfOpen(); + close(); + } finally { + super.finalize(); + } + } + } } diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 9d0ebc20bdfb..684a85e52674 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -20,6 +20,8 @@ import android.accounts.Account; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.TestApi; +import android.annotation.UserIdInt; import android.app.ActivityManagerNative; import android.app.ActivityThread; import android.app.AppGlobals; @@ -47,11 +49,11 @@ import android.text.TextUtils; import android.util.EventLog; import android.util.Log; -import dalvik.system.CloseGuard; - import com.android.internal.util.ArrayUtils; import com.android.internal.util.Preconditions; +import dalvik.system.CloseGuard; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -59,9 +61,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; /** * This class provides applications access to the content model. @@ -514,8 +516,9 @@ public abstract class ContentResolver { maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder); // Wrap the cursor object into CursorWrapperInner object. - CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, - stableProvider != null ? stableProvider : acquireProvider(uri)); + final IContentProvider provider = (stableProvider != null) ? stableProvider + : acquireProvider(uri); + final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider); stableProvider = null; qCursor = null; return wrapper; @@ -1609,7 +1612,7 @@ public abstract class ContentResolver { /** @hide - designated user version */ public final void registerContentObserver(Uri uri, boolean notifyForDescendents, - ContentObserver observer, int userHandle) { + ContentObserver observer, @UserIdInt int userHandle) { try { getContentService().registerContentObserver(uri, notifyForDescendents, observer.getContentObserver(), userHandle); @@ -1683,7 +1686,7 @@ public abstract class ContentResolver { * @hide */ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork, - int userHandle) { + @UserIdInt int userHandle) { try { getContentService().notifyChange( uri, observer == null ? null : observer.getContentObserver(), @@ -1824,7 +1827,7 @@ public abstract class ContentResolver { * @see #requestSync(Account, String, Bundle) * @hide */ - public static void requestSyncAsUser(Account account, String authority, int userId, + public static void requestSyncAsUser(Account account, String authority, @UserIdInt int userId, Bundle extras) { if (extras == null) { throw new IllegalArgumentException("Must specify extras."); @@ -1921,7 +1924,7 @@ public abstract class ContentResolver { * @see #cancelSync(Account, String) * @hide */ - public static void cancelSyncAsUser(Account account, String authority, int userId) { + public static void cancelSyncAsUser(Account account, String authority, @UserIdInt int userId) { try { getContentService().cancelSyncAsUser(account, authority, null, userId); } catch (RemoteException e) { @@ -1944,7 +1947,7 @@ public abstract class ContentResolver { * @see #getSyncAdapterTypes() * @hide */ - public static SyncAdapterType[] getSyncAdapterTypesAsUser(int userId) { + public static SyncAdapterType[] getSyncAdapterTypesAsUser(@UserIdInt int userId) { try { return getContentService().getSyncAdapterTypesAsUser(userId); } catch (RemoteException e) { @@ -1956,8 +1959,9 @@ public abstract class ContentResolver { * @hide * Returns the package names of syncadapters that match a given user and authority. */ + @TestApi public static String[] getSyncAdapterPackagesForAuthorityAsUser(String authority, - int userId) { + @UserIdInt int userId) { try { return getContentService().getSyncAdapterPackagesForAuthorityAsUser(authority, userId); } catch (RemoteException e) { @@ -1987,7 +1991,7 @@ public abstract class ContentResolver { * @hide */ public static boolean getSyncAutomaticallyAsUser(Account account, String authority, - int userId) { + @UserIdInt int userId) { try { return getContentService().getSyncAutomaticallyAsUser(account, authority, userId); } catch (RemoteException e) { @@ -2013,7 +2017,7 @@ public abstract class ContentResolver { * @hide */ public static void setSyncAutomaticallyAsUser(Account account, String authority, boolean sync, - int userId) { + @UserIdInt int userId) { try { getContentService().setSyncAutomaticallyAsUser(account, authority, sync, userId); } catch (RemoteException e) { @@ -2172,7 +2176,8 @@ public abstract class ContentResolver { * @see #getIsSyncable(Account, String) * @hide */ - public static int getIsSyncableAsUser(Account account, String authority, int userId) { + public static int getIsSyncableAsUser(Account account, String authority, + @UserIdInt int userId) { try { return getContentService().getIsSyncableAsUser(account, authority, userId); } catch (RemoteException e) { @@ -2215,7 +2220,7 @@ public abstract class ContentResolver { * @see #getMasterSyncAutomatically() * @hide */ - public static boolean getMasterSyncAutomaticallyAsUser(int userId) { + public static boolean getMasterSyncAutomaticallyAsUser(@UserIdInt int userId) { try { return getContentService().getMasterSyncAutomaticallyAsUser(userId); } catch (RemoteException e) { @@ -2239,7 +2244,7 @@ public abstract class ContentResolver { * @see #setMasterSyncAutomatically(boolean) * @hide */ - public static void setMasterSyncAutomaticallyAsUser(boolean sync, int userId) { + public static void setMasterSyncAutomaticallyAsUser(boolean sync, @UserIdInt int userId) { try { getContentService().setMasterSyncAutomaticallyAsUser(sync, userId); } catch (RemoteException e) { @@ -2319,7 +2324,7 @@ public abstract class ContentResolver { * @see #getCurrentSyncs() * @hide */ - public static List<SyncInfo> getCurrentSyncsAsUser(int userId) { + public static List<SyncInfo> getCurrentSyncsAsUser(@UserIdInt int userId) { try { return getContentService().getCurrentSyncsAsUser(userId); } catch (RemoteException e) { @@ -2347,7 +2352,7 @@ public abstract class ContentResolver { * @hide */ public static SyncStatusInfo getSyncStatusAsUser(Account account, String authority, - int userId) { + @UserIdInt int userId) { try { return getContentService().getSyncStatusAsUser(account, authority, null, userId); } catch (RemoteException e) { @@ -2371,7 +2376,8 @@ public abstract class ContentResolver { * @see #requestSync(Account, String, Bundle) * @hide */ - public static boolean isSyncPendingAsUser(Account account, String authority, int userId) { + public static boolean isSyncPendingAsUser(Account account, String authority, + @UserIdInt int userId) { try { return getContentService().isSyncPendingAsUser(account, authority, null, userId); } catch (RemoteException e) { @@ -2503,41 +2509,31 @@ public abstract class ContentResolver { private final class CursorWrapperInner extends CrossProcessCursorWrapper { private final IContentProvider mContentProvider; - public static final String TAG="CursorWrapperInner"; + private final AtomicBoolean mProviderReleased = new AtomicBoolean(); private final CloseGuard mCloseGuard = CloseGuard.get(); - private boolean mProviderReleased; - CursorWrapperInner(Cursor cursor, IContentProvider icp) { + CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) { super(cursor); - mContentProvider = icp; + mContentProvider = contentProvider; mCloseGuard.open("close"); } @Override public void close() { + mCloseGuard.close(); super.close(); - ContentResolver.this.releaseProvider(mContentProvider); - mProviderReleased = true; - if (mCloseGuard != null) { - mCloseGuard.close(); + if (mProviderReleased.compareAndSet(false, true)) { + ContentResolver.this.releaseProvider(mContentProvider); } } @Override protected void finalize() throws Throwable { try { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - - if (!mProviderReleased && mContentProvider != null) { - // Even though we are using CloseGuard, log this anyway so that - // application developers always see the message in the log. - Log.w(TAG, "Cursor finalized without prior close()"); - ContentResolver.this.releaseProvider(mContentProvider); - } + mCloseGuard.warnIfOpen(); + close(); } finally { super.finalize(); } @@ -2546,7 +2542,7 @@ public abstract class ContentResolver { private final class ParcelFileDescriptorInner extends ParcelFileDescriptor { private final IContentProvider mContentProvider; - private boolean mProviderReleased; + private final AtomicBoolean mProviderReleased = new AtomicBoolean(); ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) { super(pfd); @@ -2555,9 +2551,8 @@ public abstract class ContentResolver { @Override public void releaseResources() { - if (!mProviderReleased) { + if (mProviderReleased.compareAndSet(false, true)) { ContentResolver.this.releaseProvider(mContentProvider); - mProviderReleased = true; } } } @@ -2584,7 +2579,9 @@ public abstract class ContentResolver { private static IContentService sContentService; private final Context mContext; + final String mPackageName; + private static final String TAG = "ContentResolver"; /** @hide */ diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 67bdad576af3..a6036bb87861 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -30,6 +30,8 @@ import android.annotation.StringRes; import android.annotation.StyleRes; import android.annotation.StyleableRes; import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.annotation.UserIdInt; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -3967,7 +3969,8 @@ public abstract class Context { * * @hide */ - public abstract int getUserId(); + @TestApi + public abstract @UserIdInt int getUserId(); /** * Return a new Context object for the current Context but whose resources diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index c3dfab48acf5..35cd2bef6093 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -3604,6 +3604,15 @@ public class Intent implements Parcelable, Cloneable { public static final String EXTRA_USER_ID = "android.intent.extra.USER_ID"; /** + * An int representing the task id to be retrieved. This is used when a launch from recents is + * intercepted by another action such as credentials confirmation to remember which task should + * be resumed when complete. + * + * @hide + */ + public static final String EXTRA_TASK_ID = "android.intent.extra.TASK_ID"; + + /** * An Intent[] describing additional, alternate choices you would like shown with * {@link #ACTION_CHOOSER}. * diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java index fe279d1d9b6f..01689087043f 100644 --- a/core/java/android/content/pm/ApplicationInfo.java +++ b/core/java/android/content/pm/ApplicationInfo.java @@ -16,6 +16,7 @@ package android.content.pm; +import android.annotation.TestApi; import android.content.pm.PackageManager.NameNotFoundException; import android.content.res.Resources; import android.graphics.drawable.Drawable; @@ -803,7 +804,12 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { public boolean hasRtlSupport() { return (flags & FLAG_SUPPORTS_RTL) == FLAG_SUPPORTS_RTL; } - + + /** {@hide} */ + public boolean hasCode() { + return (flags & FLAG_HAS_CODE) != 0; + } + public static class DisplayNameComparator implements Comparator<ApplicationInfo> { public DisplayNameComparator(PackageManager pm) { @@ -1069,6 +1075,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** * @hide */ + @TestApi public boolean isSystemApp() { return (flags & ApplicationInfo.FLAG_SYSTEM) != 0; } @@ -1076,6 +1083,7 @@ public class ApplicationInfo extends PackageItemInfo implements Parcelable { /** * @hide */ + @TestApi public boolean isPrivilegedApp() { return (privateFlags & ApplicationInfo.PRIVATE_FLAG_PRIVILEGED) != 0; } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index bccc3d95c4ea..a364c18b5390 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -27,6 +27,8 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.StringRes; import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.annotation.UserIdInt; import android.annotation.XmlRes; import android.app.PackageDeleteObserver; import android.app.PackageInstallObserver; @@ -48,6 +50,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.storage.VolumeInfo; import android.util.AndroidException; +import android.util.Log; import com.android.internal.util.ArrayUtils; @@ -63,6 +66,7 @@ import java.util.List; * You can find this class through {@link Context#getPackageManager}. */ public abstract class PackageManager { + private static final String TAG = "PackageManager"; /** * This exception is thrown when a given package, application, or component @@ -106,21 +110,22 @@ public abstract class PackageManager { /** @hide */ @IntDef(flag = true, value = { GET_ACTIVITIES, - GET_RECEIVERS, - GET_SERVICES, - GET_PROVIDERS, + GET_CONFIGURATIONS, + GET_GIDS, GET_INSTRUMENTATION, GET_INTENT_FILTERS, - GET_SIGNATURES, GET_META_DATA, - GET_GIDS, + GET_PERMISSIONS, + GET_PROVIDERS, + GET_RECEIVERS, + GET_SERVICES, GET_SHARED_LIBRARY_FILES, + GET_SIGNATURES, GET_URI_PERMISSION_PATTERNS, - GET_PERMISSIONS, - GET_CONFIGURATIONS, MATCH_UNINSTALLED_PACKAGES, MATCH_DISABLED_COMPONENTS, MATCH_DISABLED_UNTIL_USED_COMPONENTS, + MATCH_SYSTEM_ONLY, MATCH_DEBUG_TRIAGED_MISSING, }) @Retention(RetentionPolicy.SOURCE) @@ -141,16 +146,16 @@ public abstract class PackageManager { @IntDef(flag = true, value = { GET_META_DATA, GET_SHARED_LIBRARY_FILES, - MATCH_UNINSTALLED_PACKAGES, - MATCH_DISABLED_COMPONENTS, - MATCH_DISABLED_UNTIL_USED_COMPONENTS, MATCH_ALL, + MATCH_DEBUG_TRIAGED_MISSING, MATCH_DEFAULT_ONLY, + MATCH_DISABLED_COMPONENTS, + MATCH_DISABLED_UNTIL_USED_COMPONENTS, MATCH_ENCRYPTION_AWARE, MATCH_ENCRYPTION_AWARE_AND_UNAWARE, MATCH_ENCRYPTION_UNAWARE, MATCH_SYSTEM_ONLY, - MATCH_DEBUG_TRIAGED_MISSING, + MATCH_UNINSTALLED_PACKAGES, }) @Retention(RetentionPolicy.SOURCE) public @interface ComponentInfoFlags {} @@ -158,18 +163,18 @@ public abstract class PackageManager { /** @hide */ @IntDef(flag = true, value = { GET_META_DATA, - GET_SHARED_LIBRARY_FILES, GET_RESOLVED_FILTER, - MATCH_UNINSTALLED_PACKAGES, + GET_SHARED_LIBRARY_FILES, + MATCH_ALL, + MATCH_DEBUG_TRIAGED_MISSING, MATCH_DISABLED_COMPONENTS, MATCH_DISABLED_UNTIL_USED_COMPONENTS, - MATCH_ALL, MATCH_DEFAULT_ONLY, MATCH_ENCRYPTION_AWARE, MATCH_ENCRYPTION_AWARE_AND_UNAWARE, MATCH_ENCRYPTION_UNAWARE, MATCH_SYSTEM_ONLY, - MATCH_DEBUG_TRIAGED_MISSING, + MATCH_UNINSTALLED_PACKAGES, }) @Retention(RetentionPolicy.SOURCE) public @interface ResolveInfoFlags {} @@ -1947,7 +1952,6 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: This device supports ethernet. - * @hide */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_ETHERNET = "android.hardware.ethernet"; @@ -2228,36 +2232,46 @@ public abstract class PackageManager { /** * Retrieve overall information about an application package that is * installed on the system. - * <p> - * Throws {@link NameNotFoundException} if a package with the given name can - * not be found on the system. * * @param packageName The full name (i.e. com.google.apps.contacts) of the - * desired package. + * desired package. * @param flags Additional option flags. Use any combination of - * {@link #GET_ACTIVITIES}, {@link #GET_GIDS}, - * {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION}, - * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, - * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, - * {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to - * modify the data returned. + * {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS}, + * {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES}, + * {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * * @return A PackageInfo object containing information about the - * package. If flag GET_UNINSTALLED_PACKAGES is set and if the + * package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the * package is not found in the list of installed applications, the * package information is retrieved from the list of uninstalled * applications (which includes installed applications as well as * applications with data directory i.e. applications which had been * deleted with {@code DONT_DELETE_DATA} flag set). + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. * @see #GET_ACTIVITIES - * @see #GET_GIDS * @see #GET_CONFIGURATIONS + * @see #GET_GIDS * @see #GET_INSTRUMENTATION + * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_PERMISSIONS * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES + * @see #GET_SHARED_LIBRARY_FILES * @see #GET_SIGNATURES - * @see #GET_UNINSTALLED_PACKAGES + * @see #GET_URI_PERMISSION_PATTERNS + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags) throws NameNotFoundException; @@ -2266,41 +2280,51 @@ public abstract class PackageManager { * @hide * Retrieve overall information about an application package that is * installed on the system. - * <p> - * Throws {@link NameNotFoundException} if a package with the given name can - * not be found on the system. * * @param packageName The full name (i.e. com.google.apps.contacts) of the - * desired package. + * desired package. * @param flags Additional option flags. Use any combination of - * {@link #GET_ACTIVITIES}, {@link #GET_GIDS}, - * {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION}, - * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, - * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, - * {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to - * modify the data returned. + * {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS}, + * {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES}, + * {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. * @param userId The user id. + * * @return A PackageInfo object containing information about the - * package. If flag GET_UNINSTALLED_PACKAGES is set and if the + * package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the * package is not found in the list of installed applications, the * package information is retrieved from the list of uninstalled * applications (which includes installed applications as well as * applications with data directory i.e. applications which had been * deleted with {@code DONT_DELETE_DATA} flag set). + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. * @see #GET_ACTIVITIES - * @see #GET_GIDS * @see #GET_CONFIGURATIONS + * @see #GET_GIDS * @see #GET_INSTRUMENTATION + * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_PERMISSIONS * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES + * @see #GET_SHARED_LIBRARY_FILES * @see #GET_SIGNATURES - * @see #GET_UNINSTALLED_PACKAGES + * @see #GET_URI_PERMISSION_PATTERNS + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_UNINSTALLED_PACKAGES */ @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS) public abstract PackageInfo getPackageInfoAsUser(String packageName, - @PackageInfoFlags int flags, int userId) throws NameNotFoundException; + @PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException; /** * Map from the current package names in use on the device to whatever @@ -2342,9 +2366,6 @@ public abstract class PackageManager { * through packages. The current implementation will look for a main * activity in the category {@link Intent#CATEGORY_LEANBACK_LAUNCHER}, or * return null if no main leanback activities are found. - * <p> - * Throws {@link NameNotFoundException} if a package with the given name - * cannot be found on the system. * * @param packageName The name of the package to inspect. * @return Returns either a fully-qualified Intent that can be used to launch @@ -2356,47 +2377,85 @@ public abstract class PackageManager { /** * Return an array of all of the secondary group-ids that have been assigned * to a package. - * <p> - * Throws {@link NameNotFoundException} if a package with the given name - * cannot be found on the system. * * @param packageName The full name (i.e. com.google.apps.contacts) of the - * desired package. + * desired package. * @return Returns an int array of the assigned gids, or null if there are * none. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. */ public abstract int[] getPackageGids(String packageName) throws NameNotFoundException; /** - * @hide Return the uid associated with the given package name for the - * given user. + * Return an array of all of the secondary group-ids that have been assigned + * to a package. * - * <p>Throws {@link NameNotFoundException} if a package with the given - * name can not be found on the system. + * @param packageName The full name (i.e. com.google.apps.contacts) of the + * desired package. + * @return Returns an int array of the assigned gids, or null if there are + * none. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. + */ + public abstract int[] getPackageGids(String packageName, @PackageInfoFlags int flags) + throws NameNotFoundException; + + /** + * Return the UID associated with the given package name. * * @param packageName The full name (i.e. com.google.apps.contacts) of the - * desired package. - * @param userHandle The user handle identifier to look up the package under. + * desired package. + * @return Returns an integer UID who owns the given package name. + * @throws NameNotFoundException if a package with the given name can not be + * found on the system. + */ + public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags) + throws NameNotFoundException; + + /** + * Return the UID associated with the given package name. * - * @return Returns an integer uid who owns the given package name. + * @param packageName The full name (i.e. com.google.apps.contacts) of the + * desired package. + * @param userId The user handle identifier to look up the package under. + * @return Returns an integer UID who owns the given package name. + * @throws NameNotFoundException if a package with the given name can not be + * found on the system. + * @hide */ - public abstract int getPackageUid(String packageName, int userHandle) + public abstract int getPackageUidAsUser(String packageName, @UserIdInt int userId) throws NameNotFoundException; /** - * Retrieve all of the information we know about a particular permission. + * Return the UID associated with the given package name. * - * <p>Throws {@link NameNotFoundException} if a permission with the given - * name cannot be found on the system. + * @param packageName The full name (i.e. com.google.apps.contacts) of the + * desired package. + * @param userId The user handle identifier to look up the package under. + * @return Returns an integer UID who owns the given package name. + * @throws NameNotFoundException if a package with the given name can not be + * found on the system. + * @hide + */ + public abstract int getPackageUidAsUser(String packageName, @PackageInfoFlags int flags, + @UserIdInt int userId) throws NameNotFoundException; + + /** + * Retrieve all of the information we know about a particular permission. * * @param name The fully qualified name (i.e. com.google.permission.LOGIN) - * of the permission you are interested in. + * of the permission you are interested in. * @param flags Additional option flags. Use {@link #GET_META_DATA} to - * retrieve any meta-data associated with the permission. + * retrieve any meta-data associated with the permission. * * @return Returns a {@link PermissionInfo} containing information about the * permission. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. + * + * @see #GET_META_DATA */ public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags) throws NameNotFoundException; @@ -2404,17 +2463,18 @@ public abstract class PackageManager { /** * Query for all of the permissions associated with a particular group. * - * <p>Throws {@link NameNotFoundException} if the given group does not - * exist. - * * @param group The fully qualified name (i.e. com.google.permission.LOGIN) - * of the permission group you are interested in. Use null to - * find all of the permissions not associated with a group. + * of the permission group you are interested in. Use null to + * find all of the permissions not associated with a group. * @param flags Additional option flags. Use {@link #GET_META_DATA} to - * retrieve any meta-data associated with the permissions. + * retrieve any meta-data associated with the permissions. * * @return Returns a list of {@link PermissionInfo} containing information - * about all of the permissions in the given group. + * about all of the permissions in the given group. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. + * + * @see #GET_META_DATA */ public abstract List<PermissionInfo> queryPermissionsByGroup(String group, @PermissionInfoFlags int flags) throws NameNotFoundException; @@ -2423,16 +2483,17 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular group of * permissions. * - * <p>Throws {@link NameNotFoundException} if a permission group with the given - * name cannot be found on the system. - * * @param name The fully qualified name (i.e. com.google.permission_group.APPS) - * of the permission you are interested in. + * of the permission you are interested in. * @param flags Additional option flags. Use {@link #GET_META_DATA} to - * retrieve any meta-data associated with the permission group. + * retrieve any meta-data associated with the permission group. * * @return Returns a {@link PermissionGroupInfo} containing information - * about the permission. + * about the permission. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. + * + * @see #GET_META_DATA */ public abstract PermissionGroupInfo getPermissionGroupInfo(String name, @PermissionGroupInfoFlags int flags) throws NameNotFoundException; @@ -2441,10 +2502,12 @@ public abstract class PackageManager { * Retrieve all of the known permission groups in the system. * * @param flags Additional option flags. Use {@link #GET_META_DATA} to - * retrieve any meta-data associated with the permission group. + * retrieve any meta-data associated with the permission group. * * @return Returns a list of {@link PermissionGroupInfo} containing - * information about all of the known permission groups. + * information about all of the known permission groups. + * + * @see #GET_META_DATA */ public abstract List<PermissionGroupInfo> getAllPermissionGroups( @PermissionGroupInfoFlags int flags); @@ -2453,28 +2516,27 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular * package/application. * - * <p>Throws {@link NameNotFoundException} if an application with the given - * package name cannot be found on the system. - * * @param packageName The full name (i.e. com.google.apps.contacts) of an - * application. + * application. * @param flags Additional option flags. Use any combination of - * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, - * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. - * - * @return {@link ApplicationInfo} Returns ApplicationInfo object containing - * information about the package. - * If flag GET_UNINSTALLED_PACKAGES is set and if the package is not - * found in the list of installed applications, - * the application information is retrieved from the - * list of uninstalled applications(which includes - * installed applications as well as applications - * with data directory ie applications which had been + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return An {@link ApplicationInfo} containing information about the + * package. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set and if the + * package is not found in the list of installed applications, the + * application information is retrieved from the list of uninstalled + * applications (which includes installed applications as well as + * applications with data directory i.e. applications which had been * deleted with {@code DONT_DELETE_DATA} flag set). + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. * * @see #GET_META_DATA * @see #GET_SHARED_LIBRARY_FILES - * @see #GET_UNINSTALLED_PACKAGES + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract ApplicationInfo getApplicationInfo(String packageName, @ApplicationInfoFlags int flags) throws NameNotFoundException; @@ -2483,21 +2545,34 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular activity * class. * - * <p>Throws {@link NameNotFoundException} if an activity with the given - * class name cannot be found on the system. - * * @param component The full component name (i.e. * com.google.apps.contacts/com.google.apps.contacts.ContactsList) of an Activity * class. * @param flags Additional option flags. Use any combination of - * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, - * to modify the data (in ApplicationInfo) returned. + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, + * {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY} + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return An {@link ActivityInfo} containing information about the activity. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. * - * @return {@link ActivityInfo} containing information about the activity. - * - * @see #GET_INTENT_FILTERS * @see #GET_META_DATA * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DEBUG_TRIAGED_MISSING + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract ActivityInfo getActivityInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException; @@ -2506,21 +2581,34 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular receiver * class. * - * <p>Throws {@link NameNotFoundException} if a receiver with the given - * class name cannot be found on the system. - * * @param component The full component name (i.e. * com.google.apps.calendar/com.google.apps.calendar.CalendarAlarm) of a Receiver * class. - * @param flags Additional option flags. Use any combination of - * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, - * to modify the data returned. - * - * @return {@link ActivityInfo} containing information about the receiver. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, + * {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY} + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return An {@link ActivityInfo} containing information about the receiver. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. * - * @see #GET_INTENT_FILTERS * @see #GET_META_DATA * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DEBUG_TRIAGED_MISSING + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract ActivityInfo getReceiverInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException; @@ -2529,20 +2617,34 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular service * class. * - * <p>Throws {@link NameNotFoundException} if a service with the given - * class name cannot be found on the system. - * * @param component The full component name (i.e. * com.google.apps.media/com.google.apps.media.BackgroundPlayback) of a Service * class. - * @param flags Additional option flags. Use any combination of - * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, - * to modify the data returned. - * - * @return ServiceInfo containing information about the service. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, + * {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY} + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return A {@link ServiceInfo} object containing information about the service. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. * * @see #GET_META_DATA * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DEBUG_TRIAGED_MISSING + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract ServiceInfo getServiceInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException; @@ -2551,20 +2653,34 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular content * provider class. * - * <p>Throws {@link NameNotFoundException} if a provider with the given - * class name cannot be found on the system. - * * @param component The full component name (i.e. * com.google.providers.media/com.google.providers.media.MediaProvider) of a * ContentProvider class. - * @param flags Additional option flags. Use any combination of - * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, - * to modify the data returned. - * - * @return ProviderInfo containing information about the service. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, + * {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY} + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return A {@link ProviderInfo} object containing information about the provider. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. * * @see #GET_META_DATA * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DEBUG_TRIAGED_MISSING + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract ProviderInfo getProviderInfo(ComponentName component, @ComponentInfoFlags int flags) throws NameNotFoundException; @@ -2574,34 +2690,42 @@ public abstract class PackageManager { * on the device. * * @param flags Additional option flags. Use any combination of - * {@link #GET_ACTIVITIES}, - * {@link #GET_GIDS}, - * {@link #GET_CONFIGURATIONS}, - * {@link #GET_INSTRUMENTATION}, - * {@link #GET_PERMISSIONS}, - * {@link #GET_PROVIDERS}, - * {@link #GET_RECEIVERS}, - * {@link #GET_SERVICES}, - * {@link #GET_SIGNATURES}, - * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. - * - * @return A List of PackageInfo objects, one for each package that is - * installed on the device. In the unlikely case of there being no - * installed packages, an empty list is returned. - * If flag GET_UNINSTALLED_PACKAGES is set, a list of all - * applications including those deleted with {@code DONT_DELETE_DATA} - * (partially installed apps with data directory) will be returned. + * {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS}, + * {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES}, + * {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return A List of PackageInfo objects, one for each installed package, + * containing information about the package. In the unlikely case + * there are no installed packages, an empty list is returned. If + * flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the package + * information is retrieved from the list of uninstalled + * applications (which includes installed applications as well as + * applications with data directory i.e. applications which had been + * deleted with {@code DONT_DELETE_DATA} flag set). * * @see #GET_ACTIVITIES - * @see #GET_GIDS * @see #GET_CONFIGURATIONS + * @see #GET_GIDS * @see #GET_INSTRUMENTATION + * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_PERMISSIONS * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES + * @see #GET_SHARED_LIBRARY_FILES * @see #GET_SIGNATURES - * @see #GET_UNINSTALLED_PACKAGES + * @see #GET_URI_PERMISSION_PATTERNS + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags); @@ -2610,30 +2734,43 @@ public abstract class PackageManager { * holding any of the given permissions. * * @param flags Additional option flags. Use any combination of - * {@link #GET_ACTIVITIES}, - * {@link #GET_GIDS}, - * {@link #GET_CONFIGURATIONS}, - * {@link #GET_INSTRUMENTATION}, - * {@link #GET_PERMISSIONS}, - * {@link #GET_PROVIDERS}, - * {@link #GET_RECEIVERS}, - * {@link #GET_SERVICES}, - * {@link #GET_SIGNATURES}, - * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. - * - * @return Returns a List of PackageInfo objects, one for each installed - * application that is holding any of the permissions that were provided. + * {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS}, + * {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES}, + * {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return A List of PackageInfo objects, one for each installed package + * that holds any of the permissions that were provided, containing + * information about the package. If no installed packages hold any + * of the permissions, an empty list is returned. If flag + * {@code MATCH_UNINSTALLED_PACKAGES} is set, the package information + * is retrieved from the list of uninstalled applications (which + * includes installed applications as well as applications with data + * directory i.e. applications which had been deleted with + * {@code DONT_DELETE_DATA} flag set). * * @see #GET_ACTIVITIES - * @see #GET_GIDS * @see #GET_CONFIGURATIONS + * @see #GET_GIDS * @see #GET_INSTRUMENTATION + * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_PERMISSIONS * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES + * @see #GET_SHARED_LIBRARY_FILES * @see #GET_SIGNATURES - * @see #GET_UNINSTALLED_PACKAGES + * @see #GET_URI_PERMISSION_PATTERNS + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<PackageInfo> getPackagesHoldingPermissions( String[] permissions, @PackageInfoFlags int flags); @@ -2642,40 +2779,50 @@ public abstract class PackageManager { * Return a List of all packages that are installed on the device, for a specific user. * Requesting a list of installed packages for another user * will require the permission INTERACT_ACROSS_USERS_FULL. + * * @param flags Additional option flags. Use any combination of - * {@link #GET_ACTIVITIES}, - * {@link #GET_GIDS}, - * {@link #GET_CONFIGURATIONS}, - * {@link #GET_INSTRUMENTATION}, - * {@link #GET_PERMISSIONS}, - * {@link #GET_PROVIDERS}, - * {@link #GET_RECEIVERS}, - * {@link #GET_SERVICES}, - * {@link #GET_SIGNATURES}, - * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. + * {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS}, + * {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES}, + * {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. * @param userId The user for whom the installed packages are to be listed * - * @return A List of PackageInfo objects, one for each package that is - * installed on the device. In the unlikely case of there being no - * installed packages, an empty list is returned. - * If flag GET_UNINSTALLED_PACKAGES is set, a list of all - * applications including those deleted with {@code DONT_DELETE_DATA} - * (partially installed apps with data directory) will be returned. + * @return A List of PackageInfo objects, one for each installed package, + * containing information about the package. In the unlikely case + * there are no installed packages, an empty list is returned. If + * flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the package + * information is retrieved from the list of uninstalled + * applications (which includes installed applications as well as + * applications with data directory i.e. applications which had been + * deleted with {@code DONT_DELETE_DATA} flag set). * * @see #GET_ACTIVITIES - * @see #GET_GIDS * @see #GET_CONFIGURATIONS + * @see #GET_GIDS * @see #GET_INSTRUMENTATION + * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_PERMISSIONS * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES + * @see #GET_SHARED_LIBRARY_FILES * @see #GET_SIGNATURES - * @see #GET_UNINSTALLED_PACKAGES + * @see #GET_URI_PERMISSION_PATTERNS + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_UNINSTALLED_PACKAGES * * @hide */ - public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags, int userId); + public abstract List<PackageInfo> getInstalledPackagesAsUser(@PackageInfoFlags int flags, + @UserIdInt int userId); /** * Check whether a particular package has been granted a particular @@ -2987,8 +3134,9 @@ public abstract class PackageManager { * shared user. * * @param sharedUserName The shared user name whose uid is to be retrieved. - * @return Returns the uid associated with the shared user, or NameNotFoundException - * if the shared user name is not being used by any installed packages + * @return Returns the UID associated with the shared user. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. * @hide */ public abstract int getUidForSharedUser(String sharedUserName) @@ -3002,18 +3150,21 @@ public abstract class PackageManager { * * @param flags Additional option flags. Use any combination of * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, - * {@link #GET_UNINSTALLED_PACKAGES} to modify the data returned. + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. * - * @return Returns a List of ApplicationInfo objects, one for each application that - * is installed on the device. In the unlikely case of there being - * no installed applications, an empty list is returned. - * If flag GET_UNINSTALLED_PACKAGES is set, a list of all - * applications including those deleted with {@code DONT_DELETE_DATA} - * (partially installed apps with data directory) will be returned. + * @return A List of ApplicationInfo objects, one for each installed application. + * In the unlikely case there are no installed packages, an empty list + * is returned. If flag {@code MATCH_UNINSTALLED_PACKAGES} is set, the + * application information is retrieved from the list of uninstalled + * applications (which includes installed applications as well as + * applications with data directory i.e. applications which had been + * deleted with {@code DONT_DELETE_DATA} flag set). * * @see #GET_META_DATA * @see #GET_SHARED_LIBRARY_FILES - * @see #GET_UNINSTALLED_PACKAGES + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags); @@ -3136,19 +3287,35 @@ public abstract class PackageManager { * * @param intent An intent containing all of the desired specification * (action, data, type, category, and/or component). - * @param flags Additional option flags. The most important is - * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only - * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. - * - * @return Returns a ResolveInfo containing the final activity intent that - * was determined to be the best action. Returns null if no + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. The most important is + * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only + * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. + * + * @return Returns a ResolveInfo object containing the final activity intent + * that was determined to be the best action. Returns null if no * matching activity was found. If multiple matching activities are - * found and there is no default set, returns a ResolveInfo + * found and there is no default set, returns a ResolveInfo object * containing something else, such as the activity resolver. * - * @see #MATCH_DEFAULT_ONLY - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags); @@ -3166,45 +3333,75 @@ public abstract class PackageManager { * * @param intent An intent containing all of the desired specification * (action, data, type, category, and/or component). - * @param flags Additional option flags. The most important is - * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only - * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. The most important is + * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only + * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. * @param userId The user id. * - * @return Returns a ResolveInfo containing the final activity intent that - * was determined to be the best action. Returns null if no + * @return Returns a ResolveInfo object containing the final activity intent + * that was determined to be the best action. Returns null if no * matching activity was found. If multiple matching activities are - * found and there is no default set, returns a ResolveInfo + * found and there is no default set, returns a ResolveInfo object * containing something else, such as the activity resolver. * - * @see #MATCH_DEFAULT_ONLY - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES * * @hide */ public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags, - int userId); + @UserIdInt int userId); /** * Retrieve all activities that can be performed for the given intent. * * @param intent The desired intent as per resolveActivity(). - * @param flags Additional option flags. The most important is - * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only - * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. - * - * You can also set {@link #MATCH_ALL} for preventing the filtering of the results. - * - * @return A List<ResolveInfo> containing one entry for each matching - * Activity. These are ordered from best to worst match -- that - * is, the first item in the list is what is returned by - * {@link #resolveActivity}. If there are no matching activities, an empty - * list is returned. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. The most important is + * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only + * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. + * Or, set {@link #MATCH_ALL} to prevent any filtering of the results. + * + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching activity, ordered from best to worst. In other words, the + * first item is what would be returned by {@link #resolveActivity}. + * If there are no matching activities, an empty list is returned. * - * @see #MATCH_DEFAULT_ONLY - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<ResolveInfo> queryIntentActivities(Intent intent, @ResolveInfoFlags int flags); @@ -3213,25 +3410,40 @@ public abstract class PackageManager { * Retrieve all activities that can be performed for the given intent, for a specific user. * * @param intent The desired intent as per resolveActivity(). - * @param flags Additional option flags. The most important is - * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only - * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. - * - * You can also set {@link #MATCH_ALL} for preventing the filtering of the results. - * - * @return A List<ResolveInfo> containing one entry for each matching - * Activity. These are ordered from best to worst match -- that - * is, the first item in the list is what is returned by - * {@link #resolveActivity}. If there are no matching activities, an empty - * list is returned. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. The most important is + * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only + * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. + * Or, set {@link #MATCH_ALL} to prevent any filtering of the results. + * + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching activity, ordered from best to worst. In other words, the + * first item is what would be returned by {@link #resolveActivity}. + * If there are no matching activities, an empty list is returned. * - * @see #MATCH_DEFAULT_ONLY - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES + * * @hide */ public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent, - @ResolveInfoFlags int flags, int userId); + @ResolveInfoFlags int flags, @UserIdInt int userId); /** * Retrieve a set of activities that should be presented to the user as @@ -3247,20 +3459,36 @@ public abstract class PackageManager { * @param specifics An array of Intents that should be resolved to the * first specific results. Can be null. * @param intent The desired intent as per resolveActivity(). - * @param flags Additional option flags. The most important is - * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only - * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. - * - * @return A List<ResolveInfo> containing one entry for each matching - * Activity. These are ordered first by all of the intents resolved + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. The most important is + * {@link #MATCH_DEFAULT_ONLY}, to limit the resolution to only + * those activities that support the {@link android.content.Intent#CATEGORY_DEFAULT}. + * + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching activity. The list is ordered first by all of the intents resolved * in <var>specifics</var> and then any additional activities that * can handle <var>intent</var> but did not get included by one of * the <var>specifics</var> intents. If there are no matching * activities, an empty list is returned. * - * @see #MATCH_DEFAULT_ONLY - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<ResolveInfo> queryIntentActivityOptions( ComponentName caller, Intent[] specifics, Intent intent, @ResolveInfoFlags int flags); @@ -3269,15 +3497,31 @@ public abstract class PackageManager { * Retrieve all receivers that can handle a broadcast of the given intent. * * @param intent The desired intent as per resolveActivity(). - * @param flags Additional option flags. - * - * @return A List<ResolveInfo> containing one entry for each matching - * Receiver. These are ordered from first to last in priority. If - * there are no matching receivers, an empty list is returned. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching receiver, ordered from best to worst. If there are no matching + * receivers, an empty list or null is returned. * - * @see #MATCH_DEFAULT_ONLY - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent, @ResolveInfoFlags int flags); @@ -3287,34 +3531,76 @@ public abstract class PackageManager { * user. * * @param intent The desired intent as per resolveActivity(). - * @param flags Additional option flags. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. * @param userId The userId of the user being queried. * - * @return A List<ResolveInfo> containing one entry for each matching - * Receiver. These are ordered from first to last in priority. If - * there are no matching receivers, an empty list or {@code null} is returned. + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching receiver, ordered from best to worst. If there are no matching + * receivers, an empty list or null is returned. * - * @see #MATCH_DEFAULT_ONLY - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES + * * @hide */ - public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent, - @ResolveInfoFlags int flags, int userId); + public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, + @ResolveInfoFlags int flags, @UserIdInt int userId); + + /** {@hide} */ + @Deprecated + public List<ResolveInfo> queryBroadcastReceivers(Intent intent, + @ResolveInfoFlags int flags, @UserIdInt int userId) { + Log.w(TAG, "STAHP USING HIDDEN APIS KTHX"); + return queryBroadcastReceiversAsUser(intent, flags, userId); + } /** * Determine the best service to handle for a given Intent. * * @param intent An intent containing all of the desired specification * (action, data, type, category, and/or component). - * @param flags Additional option flags. - * - * @return Returns a ResolveInfo containing the final service intent that - * was determined to be the best action. Returns null if no + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return Returns a ResolveInfo object containing the final service intent + * that was determined to be the best action. Returns null if no * matching service was found. * - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags); @@ -3322,16 +3608,32 @@ public abstract class PackageManager { * Retrieve all services that can match the given intent. * * @param intent The desired intent as per resolveService(). - * @param flags Additional option flags. - * - * @return A List<ResolveInfo> containing one entry for each matching - * ServiceInfo. These are ordered from best to worst match -- that - * is, the first item in the list is what is returned by - * resolveService(). If there are no matching services, an empty - * list or {@code null} is returned. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching service, ordered from best to worst. In other words, the first + * item is what would be returned by {@link #resoveService}. If there are + * no matching services, an empty list or null is returned. * - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<ResolveInfo> queryIntentServices(Intent intent, @ResolveInfoFlags int flags); @@ -3340,38 +3642,106 @@ public abstract class PackageManager { * Retrieve all services that can match the given intent for a given user. * * @param intent The desired intent as per resolveService(). - * @param flags Additional option flags. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. * @param userId The user id. * - * @return A List<ResolveInfo> containing one entry for each matching - * ServiceInfo. These are ordered from best to worst match -- that - * is, the first item in the list is what is returned by - * resolveService(). If there are no matching services, an empty - * list or {@code null} is returned. + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching service, ordered from best to worst. In other words, the first + * item is what would be returned by {@link #resoveService}. If there are + * no matching services, an empty list or null is returned. * - * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES * * @hide */ public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent, - @ResolveInfoFlags int flags, int userId); + @ResolveInfoFlags int flags, @UserIdInt int userId); - /** {@hide} */ + /** + * Retrieve all providers that can match the given intent. + * + * @param intent An intent containing all of the desired specification + * (action, data, type, category, and/or component). + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * @param userId The user id. + * + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching provider, ordered from best to worst. If there are no + * matching services, an empty list or null is returned. + * + * @see #GET_META_DATA + * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES + * + * @hide + */ public abstract List<ResolveInfo> queryIntentContentProvidersAsUser( - Intent intent, @ResolveInfoFlags int flags, int userId); + Intent intent, @ResolveInfoFlags int flags, @UserIdInt int userId); /** * Retrieve all providers that can match the given intent. * * @param intent An intent containing all of the desired specification * (action, data, type, category, and/or component). - * @param flags Additional option flags. - * @return A List<ResolveInfo> containing one entry for each matching - * ProviderInfo. These are ordered from best to worst match. If - * there are no matching providers, an empty list or {@code null} is returned. - * @see #GET_INTENT_FILTERS + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_RESOLVED_FILTER}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #MATCH_ALL}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_DEFAULT_ONLY}, {@link #MATCH_ENCRYPTION_AWARE}, + * {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, {@link #MATCH_ENCRYPTION_UNAWARE}, + * {@link #MATCH_SYSTEM_ONLY}, {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return Returns a List of ResolveInfo objects containing one entry for each + * matching provider, ordered from best to worst. If there are no + * matching services, an empty list or null is returned. + * + * @see #GET_META_DATA * @see #GET_RESOLVED_FILTER + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent, @ResolveInfoFlags int flags); @@ -3380,10 +3750,30 @@ public abstract class PackageManager { * Find a single content provider by its base path name. * * @param name The name of the provider to find. - * @param flags Additional option flags. Currently should always be 0. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, + * {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY} + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. * - * @return ContentProviderInfo Information about the provider, if found, - * else null. + * @return A {@link ProviderInfo} object containing information about the provider. + * If a provider was not found, returns null. + * + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DEBUG_TRIAGED_MISSING + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract ProviderInfo resolveContentProvider(String name, @ComponentInfoFlags int flags); @@ -3392,15 +3782,36 @@ public abstract class PackageManager { * Find a single content provider by its base path name. * * @param name The name of the provider to find. - * @param flags Additional option flags. Currently should always be 0. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, + * {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY} + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. * @param userId The user id. * - * @return ContentProviderInfo Information about the provider, if found, - * else null. + * @return A {@link ProviderInfo} object containing information about the provider. + * If a provider was not found, returns null. + * + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DEBUG_TRIAGED_MISSING + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES + * * @hide */ public abstract ProviderInfo resolveContentProviderAsUser(String name, - @ComponentInfoFlags int flags, int userId); + @ComponentInfoFlags int flags, @UserIdInt int userId); /** * Retrieve content provider information. @@ -3413,12 +3824,32 @@ public abstract class PackageManager { * all content providers are returned. * @param uid If <var>processName</var> is non-null, this is the required * uid owning the requested content providers. - * @param flags Additional option flags. Currently should always be 0. - * - * @return A List<ContentProviderInfo> containing one entry for each - * content provider either patching <var>processName</var> or, if + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA}, {@link #GET_SHARED_LIBRARY_FILES}, + * {@link #MATCH_ALL}, {@link #MATCH_DEFAULT_ONLY}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_ENCRYPTION_AWARE}, {@link #MATCH_ENCRYPTION_AWARE_AND_UNAWARE}, + * {@link #MATCH_ENCRYPTION_UNAWARE}, {@link #MATCH_SYSTEM_ONLY} + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return A list of {@link ProviderInfo} objects containing one entry for + * each provider either matching <var>processName</var> or, if * <var>processName</var> is null, all known content providers. * <em>If there are no matching providers, null is returned.</em> + * + * @see #GET_META_DATA + * @see #GET_SHARED_LIBRARY_FILES + * @see #MATCH_ALL + * @see #MATCH_DEBUG_TRIAGED_MISSING + * @see #MATCH_DEFAULT_ONLY + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_ENCRYPTION_AWARE + * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE + * @see #MATCH_ENCRYPTION_UNAWARE + * @see #MATCH_SYSTEM_ONLY + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<ProviderInfo> queryContentProviders( String processName, int uid, @ComponentInfoFlags int flags); @@ -3427,16 +3858,19 @@ public abstract class PackageManager { * Retrieve all of the information we know about a particular * instrumentation class. * - * <p>Throws {@link NameNotFoundException} if instrumentation with the - * given class name cannot be found on the system. - * * @param className The full name (i.e. * com.google.apps.contacts.InstrumentList) of an * Instrumentation class. - * @param flags Additional option flags. Currently should always be 0. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA} + * to modify the data returned. * - * @return InstrumentationInfo containing information about the + * @return An {@link InstrumentationInfo} object containing information about the * instrumentation. + * @throws NameNotFoundException if a package with the given name cannot be + * found on the system. + * + * @see #GET_META_DATA */ public abstract InstrumentationInfo getInstrumentationInfo(ComponentName className, @InstrumentationInfoFlags int flags) throws NameNotFoundException; @@ -3449,11 +3883,15 @@ public abstract class PackageManager { * @param targetPackage If null, all instrumentation is returned; only the * instrumentation targeting this package name is * returned. - * @param flags Additional option flags. Currently should always be 0. + * @param flags Additional option flags. Use any combination of + * {@link #GET_META_DATA} + * to modify the data returned. * - * @return A List<InstrumentationInfo> containing one entry for each - * matching available Instrumentation. Returns an empty list if - * there is no instrumentation available for the given package. + * @return A list of {@link InstrumentationInfo} objects containing one + * entry for each matching instrumentation. If there are no + * instrumentation available, returns and empty list. + * + * @see #GET_META_DATA */ public abstract List<InstrumentationInfo> queryInstrumentation(String targetPackage, @InstrumentationInfoFlags int flags); @@ -3859,8 +4297,8 @@ public abstract class PackageManager { throws NameNotFoundException; /** @hide */ - public abstract Resources getResourcesForApplicationAsUser(String appPackageName, int userId) - throws NameNotFoundException; + public abstract Resources getResourcesForApplicationAsUser(String appPackageName, + @UserIdInt int userId) throws NameNotFoundException; /** * Retrieve overall information about an application package defined @@ -3868,28 +4306,37 @@ public abstract class PackageManager { * * @param archiveFilePath The path to the archive file * @param flags Additional option flags. Use any combination of - * {@link #GET_ACTIVITIES}, - * {@link #GET_GIDS}, - * {@link #GET_CONFIGURATIONS}, - * {@link #GET_INSTRUMENTATION}, - * {@link #GET_PERMISSIONS}, - * {@link #GET_PROVIDERS}, - * {@link #GET_RECEIVERS}, - * {@link #GET_SERVICES}, - * {@link #GET_SIGNATURES}, to modify the data returned. - * - * @return Returns the information about the package. Returns - * null if the package could not be successfully parsed. + * {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS}, + * {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES}, + * {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return A PackageInfo object containing information about the + * package archive. If the package could not be parsed, + * returns null. * * @see #GET_ACTIVITIES - * @see #GET_GIDS * @see #GET_CONFIGURATIONS + * @see #GET_GIDS * @see #GET_INSTRUMENTATION + * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_PERMISSIONS * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES + * @see #GET_SHARED_LIBRARY_FILES * @see #GET_SIGNATURES + * @see #GET_URI_PERMISSION_PATTERNS + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_UNINSTALLED_PACKAGES * */ public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) { @@ -3932,7 +4379,6 @@ public abstract class PackageManager { * but the older observer interface will not get additional * failure details. */ - // @SystemApi public abstract void installPackage( Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName); @@ -3968,7 +4414,6 @@ public abstract class PackageManager { * continue to be supported but the older observer interface * will not get additional failure details. */ - // @SystemApi public abstract void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer, int flags, String installerPackageName, Uri verificationURI, @@ -4060,7 +4505,7 @@ public abstract class PackageManager { Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract void installPackageAsUser( Uri packageURI, PackageInstallObserver observer, int flags, - String installerPackageName, int userId); + String installerPackageName, @UserIdInt int userId); /** * Similar to @@ -4122,7 +4567,6 @@ public abstract class PackageManager { * on the system for other users, also install it for the calling user. * @hide */ - // @SystemApi public abstract int installExistingPackage(String packageName) throws NameNotFoundException; /** @@ -4133,7 +4577,7 @@ public abstract class PackageManager { @RequiresPermission(anyOf = { Manifest.permission.INSTALL_PACKAGES, Manifest.permission.INTERACT_ACROSS_USERS_FULL}) - public abstract int installExistingPackageAsUser(String packageName, int userId) + public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId) throws NameNotFoundException; /** @@ -4231,7 +4675,7 @@ public abstract class PackageManager { * * @hide */ - public abstract int getIntentVerificationStatus(String packageName, int userId); + public abstract int getIntentVerificationStatusAsUser(String packageName, @UserIdInt int userId); /** * Allow to change the status of a Intent Verification status for all IntentFilter of an App. @@ -4253,8 +4697,8 @@ public abstract class PackageManager { * * @hide */ - public abstract boolean updateIntentVerificationStatus(String packageName, int status, - int userId); + public abstract boolean updateIntentVerificationStatusAsUser(String packageName, int status, + @UserIdInt int userId); /** * Get the list of IntentFilterVerificationInfo for a specific package and User. @@ -4294,7 +4738,8 @@ public abstract class PackageManager { * * @hide */ - public abstract String getDefaultBrowserPackageName(int userId); + @TestApi + public abstract String getDefaultBrowserPackageNameAsUser(@UserIdInt int userId); /** * Set the default Browser package name for a specific user. @@ -4308,7 +4753,8 @@ public abstract class PackageManager { * * @hide */ - public abstract boolean setDefaultBrowserPackageName(String packageName, int userId); + public abstract boolean setDefaultBrowserPackageNameAsUser(String packageName, + @UserIdInt int userId); /** * Change the installer associated with a given package. There are limitations @@ -4367,7 +4813,7 @@ public abstract class PackageManager { Manifest.permission.DELETE_PACKAGES, Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract void deletePackageAsUser( - String packageName, IPackageDeleteObserver observer, int flags, int userId); + String packageName, IPackageDeleteObserver observer, int flags, @UserIdInt int userId); /** * Retrieve the package name of the application that installed a package. This identifies @@ -4480,7 +4926,7 @@ public abstract class PackageManager { * should have the {@link android.Manifest.permission#GET_PACKAGE_SIZE} permission. * * @param packageName The name of the package whose size information is to be retrieved - * @param userHandle The user whose size information should be retrieved. + * @param userId The user whose size information should be retrieved. * @param observer An observer callback to get notified when the operation * is complete. * {@link android.content.pm.IPackageStatsObserver#onGetStatsCompleted(PackageStats, boolean)} @@ -4491,17 +4937,17 @@ public abstract class PackageManager { * * @hide */ - public abstract void getPackageSizeInfo(String packageName, int userHandle, + public abstract void getPackageSizeInfoAsUser(String packageName, @UserIdInt int userId, IPackageStatsObserver observer); /** - * Like {@link #getPackageSizeInfo(String, int, IPackageStatsObserver)}, but + * Like {@link #getPackageSizeInfoAsUser(String, int, IPackageStatsObserver)}, but * returns the size for the calling user. * * @hide */ public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) { - getPackageSizeInfo(packageName, UserHandle.myUserId(), observer); + getPackageSizeInfoAsUser(packageName, UserHandle.myUserId(), observer); } /** @@ -4526,28 +4972,36 @@ public abstract class PackageManager { * least preferred. * * @param flags Additional option flags. Use any combination of - * {@link #GET_ACTIVITIES}, - * {@link #GET_GIDS}, - * {@link #GET_CONFIGURATIONS}, - * {@link #GET_INSTRUMENTATION}, - * {@link #GET_PERMISSIONS}, - * {@link #GET_PROVIDERS}, - * {@link #GET_RECEIVERS}, - * {@link #GET_SERVICES}, - * {@link #GET_SIGNATURES}, to modify the data returned. - * - * @return Returns a list of PackageInfo objects describing each - * preferred application, in order of preference. + * {@link #GET_ACTIVITIES}, {@link #GET_CONFIGURATIONS}, + * {@link #GET_GIDS}, {@link #GET_INSTRUMENTATION}, + * {@link #GET_INTENT_FILTERS}, {@link #GET_META_DATA}, + * {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS}, + * {@link #GET_RECEIVERS}, {@link #GET_SERVICES}, + * {@link #GET_SHARED_LIBRARY_FILES}, {@link #GET_SIGNATURES}, + * {@link #GET_URI_PERMISSION_PATTERNS}, {@link #GET_UNINSTALLED_PACKAGES}, + * {@link #MATCH_DISABLED_COMPONENTS}, {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}, + * {@link #MATCH_UNINSTALLED_PACKAGES} + * to modify the data returned. + * + * @return A List of PackageInfo objects, one for each preferred application, + * in order of preference. * * @see #GET_ACTIVITIES - * @see #GET_GIDS * @see #GET_CONFIGURATIONS + * @see #GET_GIDS * @see #GET_INSTRUMENTATION + * @see #GET_INTENT_FILTERS + * @see #GET_META_DATA * @see #GET_PERMISSIONS * @see #GET_PROVIDERS * @see #GET_RECEIVERS * @see #GET_SERVICES + * @see #GET_SHARED_LIBRARY_FILES * @see #GET_SIGNATURES + * @see #GET_URI_PERMISSION_PATTERNS + * @see #MATCH_DISABLED_COMPONENTS + * @see #MATCH_DISABLED_UNTIL_USED_COMPONENTS + * @see #MATCH_UNINSTALLED_PACKAGES */ public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags); @@ -4580,8 +5034,8 @@ public abstract class PackageManager { to. * @hide */ - public void addPreferredActivity(IntentFilter filter, int match, - ComponentName[] set, ComponentName activity, int userId) { + public void addPreferredActivityAsUser(IntentFilter filter, int match, + ComponentName[] set, ComponentName activity, @UserIdInt int userId) { throw new RuntimeException("Not implemented. Must override in a subclass."); } @@ -4615,7 +5069,7 @@ public abstract class PackageManager { */ @Deprecated public void replacePreferredActivityAsUser(IntentFilter filter, int match, - ComponentName[] set, ComponentName activity, int userId) { + ComponentName[] set, ComponentName activity, @UserIdInt int userId) { throw new RuntimeException("Not implemented. Must override in a subclass."); } @@ -4843,7 +5297,7 @@ public abstract class PackageManager { * @hide */ public abstract boolean setPackageSuspendedAsUser( - String packageName, boolean suspended, int userId); + String packageName, boolean suspended, @UserIdInt int userId); /** {@hide} */ public static boolean isMoveStatusFinished(int status) { diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index 236cf64ae8ce..134966248f94 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -37,7 +37,6 @@ import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.os.Build; import android.os.Bundle; -import android.os.Environment; import android.os.FileUtils; import android.os.PatternMatcher; import android.os.Trace; @@ -52,6 +51,7 @@ import android.util.Log; import android.util.Pair; import android.util.Slog; import android.util.TypedValue; +import android.util.jar.StrictJarFile; import android.view.Gravity; import com.android.internal.R; @@ -86,8 +86,6 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import java.util.zip.ZipEntry; -import android.util.jar.StrictJarFile; - /** * Parser for package files (APKs) on disk. This supports apps packaged either * as a single "monolithic" APK, or apps packaged as a "cluster" of multiple @@ -421,8 +419,7 @@ public class PackageParser { public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, Set<String> grantedPermissions, PackageUserState state, int userId) { - - if (!checkUseInstalledOrHidden(flags, state)) { + if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) { return null; } PackageInfo pi = new PackageInfo(); @@ -4623,6 +4620,13 @@ public class PackageParser { && !isForwardLocked() && !applicationInfo.isExternalAsec(); } + public boolean isMatch(int flags) { + if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { + return isSystemApp(); + } + return true; + } + public String toString() { return "Package{" + Integer.toHexString(System.identityHashCode(this)) @@ -4873,7 +4877,7 @@ public class PackageParser { public static ApplicationInfo generateApplicationInfo(Package p, int flags, PackageUserState state, int userId) { if (p == null) return null; - if (!checkUseInstalledOrHidden(flags, state)) { + if (!checkUseInstalledOrHidden(flags, state) || !p.isMatch(flags)) { return null; } if (!copyNeeded(flags, p, state, null, userId) diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java index d5d300760c8a..c9be6edab424 100644 --- a/core/java/android/content/pm/ResolveInfo.java +++ b/core/java/android/content/pm/ResolveInfo.java @@ -172,7 +172,8 @@ public class ResolveInfo implements Parcelable { */ public boolean handleAllWebDataURI; - private ComponentInfo getComponentInfo() { + /** {@hide} */ + public ComponentInfo getComponentInfo() { if (activityInfo != null) return activityInfo; if (serviceInfo != null) return serviceInfo; if (providerInfo != null) return providerInfo; diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java index ee6aec2910aa..7b0b98d4389c 100644 --- a/core/java/android/content/res/AssetManager.java +++ b/core/java/android/content/res/AssetManager.java @@ -16,6 +16,11 @@ package android.content.res; +import android.annotation.AnyRes; +import android.annotation.ArrayRes; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.StringRes; import android.os.ParcelFileDescriptor; import android.util.Log; import android.util.SparseArray; @@ -142,80 +147,95 @@ public final class AssetManager implements AutoCloseable { } /** - * Retrieve the string value associated with a particular resource - * identifier for the current configuration / skin. + * Retrieves the string value associated with a particular resource + * identifier for the current configuration. + * + * @param resId the resource identifier to load + * @return the string value, or {@code null} */ - /*package*/ final CharSequence getResourceText(int ident) { + @Nullable + final CharSequence getResourceText(@StringRes int resId) { synchronized (this) { - TypedValue tmpValue = mValue; - int block = loadResourceValue(ident, (short) 0, tmpValue, true); - if (block >= 0) { - if (tmpValue.type == TypedValue.TYPE_STRING) { - return mStringBlocks[block].get(tmpValue.data); - } - return tmpValue.coerceToString(); + final TypedValue outValue = mValue; + if (getResourceValue(resId, 0, outValue, true)) { + return outValue.coerceToString(); } + return null; } - return null; } /** - * Retrieve the string value associated with a particular resource - * identifier for the current configuration / skin. + * Retrieves the string value associated with a particular resource + * identifier for the current configuration. + * + * @param resId the resource identifier to load + * @param bagEntryId + * @return the string value, or {@code null} */ - /*package*/ final CharSequence getResourceBagText(int ident, int bagEntryId) { + @Nullable + final CharSequence getResourceBagText(@StringRes int resId, int bagEntryId) { synchronized (this) { - TypedValue tmpValue = mValue; - int block = loadResourceBagValue(ident, bagEntryId, tmpValue, true); - if (block >= 0) { - if (tmpValue.type == TypedValue.TYPE_STRING) { - return mStringBlocks[block].get(tmpValue.data); - } - return tmpValue.coerceToString(); + final TypedValue outValue = mValue; + final int block = loadResourceBagValue(resId, bagEntryId, outValue, true); + if (block < 0) { + return null; + } + if (outValue.type == TypedValue.TYPE_STRING) { + return mStringBlocks[block].get(outValue.data); } + return outValue.coerceToString(); } - return null; } /** - * Retrieve the string array associated with a particular resource - * identifier. - * @param id Resource id of the string array + * Retrieves the string array associated with a particular resource + * identifier for the current configuration. + * + * @param resId the resource identifier of the string array + * @return the string array, or {@code null} */ - /*package*/ final String[] getResourceStringArray(final int id) { - String[] retArray = getArrayStringResource(id); - return retArray; + @Nullable + final String[] getResourceStringArray(@ArrayRes int resId) { + return getArrayStringResource(resId); } - - /*package*/ final boolean getResourceValue(int ident, - int density, - TypedValue outValue, - boolean resolveRefs) - { - int block = loadResourceValue(ident, (short) density, outValue, resolveRefs); - if (block >= 0) { - if (outValue.type != TypedValue.TYPE_STRING) { - return true; - } + /** + * Populates {@code outValue} with the data associated a particular + * resource identifier for the current configuration. + * + * @param resId the resource identifier to load + * @param densityDpi the density bucket for which to load the resource + * @param outValue the typed value in which to put the data + * @param resolveRefs {@code true} to resolve references, {@code false} + * to leave them unresolved + * @return {@code true} if the data was loaded into {@code outValue}, + * {@code false} otherwise + */ + final boolean getResourceValue(@AnyRes int resId, int densityDpi, @NonNull TypedValue outValue, + boolean resolveRefs) { + final int block = loadResourceValue(resId, (short) densityDpi, outValue, resolveRefs); + if (block < 0) { + return false; + } + if (outValue.type == TypedValue.TYPE_STRING) { outValue.string = mStringBlocks[block].get(outValue.data); - return true; } - return false; + return true; } /** * Retrieve the text array associated with a particular resource * identifier. - * @param id Resource id of the string array + * + * @param resId the resource id of the string array */ - /*package*/ final CharSequence[] getResourceTextArray(final int id) { - int[] rawInfoArray = getArrayStringInfo(id); - int rawInfoArrayLen = rawInfoArray.length; + final CharSequence[] getResourceTextArray(@ArrayRes int resId) { + final int[] rawInfoArray = getArrayStringInfo(resId); + final int rawInfoArrayLen = rawInfoArray.length; final int infoArrayLen = rawInfoArrayLen / 2; int block; int index; - CharSequence[] retArray = new CharSequence[infoArrayLen]; + final CharSequence[] retArray = new CharSequence[infoArrayLen]; for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) { block = rawInfoArray[i]; index = rawInfoArray[i + 1]; @@ -223,32 +243,45 @@ public final class AssetManager implements AutoCloseable { } return retArray; } - - /*package*/ final boolean getThemeValue(long theme, int ident, - TypedValue outValue, boolean resolveRefs) { - int block = loadThemeAttributeValue(theme, ident, outValue, resolveRefs); - if (block >= 0) { - if (outValue.type != TypedValue.TYPE_STRING) { - return true; - } - StringBlock[] blocks = mStringBlocks; - if (blocks == null) { - ensureStringBlocks(); - blocks = mStringBlocks; - } + + /** + * Populates {@code outValue} with the data associated with a particular + * resource identifier for the current configuration. Resolves theme + * attributes against the specified theme. + * + * @param theme the native pointer of the theme + * @param resId the resource identifier to load + * @param outValue the typed value in which to put the data + * @param resolveRefs {@code true} to resolve references, {@code false} + * to leave them unresolved + * @return {@code true} if the data was loaded into {@code outValue}, + * {@code false} otherwise + */ + final boolean getThemeValue(long theme, @AnyRes int resId, @NonNull TypedValue outValue, + boolean resolveRefs) { + final int block = loadThemeAttributeValue(theme, resId, outValue, resolveRefs); + if (block < 0) { + return false; + } + if (outValue.type == TypedValue.TYPE_STRING) { + final StringBlock[] blocks = ensureStringBlocks(); outValue.string = blocks[block].get(outValue.data); - return true; } - return false; + return true; } - /*package*/ final void ensureStringBlocks() { - if (mStringBlocks == null) { - synchronized (this) { - if (mStringBlocks == null) { - makeStringBlocks(sSystem.mStringBlocks); - } + /** + * Ensures the string blocks are loaded. + * + * @return the string blocks + */ + @NonNull + final StringBlock[] ensureStringBlocks() { + synchronized (this) { + if (mStringBlocks == null) { + makeStringBlocks(sSystem.mStringBlocks); } + return mStringBlocks; } } diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index b01633e641f3..7b56eebf34ac 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -151,8 +151,9 @@ public class Resources { private boolean mPreloading; + // Cyclical cache used for recently-accessed XML files. private int mLastCachedXmlBlockIndex = -1; - private final int[] mCachedXmlBlockIds = { 0, 0, 0, 0 }; + private final String[] mCachedXmlBlockFiles = new String[4]; private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[4]; final AssetManager mAssets; @@ -866,6 +867,11 @@ public class Resources { try { getValueForDensity(id, density, value, true); + // If the drawable's XML lives in our current density qualifier, + // it's okay to use a scaled version from the cache. Otherwise, we + // need to actually load the drawable from XML. + final boolean useCache = value.density == mMetrics.densityDpi; + /* * Pretend the requested density is actually the display density. If * the drawable returned is not the requested density, then force it @@ -881,7 +887,7 @@ public class Resources { } } - return loadDrawable(value, id, theme); + return loadDrawable(value, id, theme, useCache); } finally { releaseTempTypedValue(value); } @@ -2365,16 +2371,17 @@ public class Resources { * tools. */ public final void flushLayoutCache() { - synchronized (mCachedXmlBlockIds) { - // First see if this block is in our cache. - final int num = mCachedXmlBlockIds.length; - for (int i=0; i<num; i++) { - mCachedXmlBlockIds[i] = -0; - XmlBlock oldBlock = mCachedXmlBlocks[i]; + final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles; + final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; + synchronized (cachedXmlBlockFiles) { + final int num = cachedXmlBlockFiles.length; + for (int i = 0; i < num; i++) { + final XmlBlock oldBlock = cachedXmlBlocks[i]; if (oldBlock != null) { oldBlock.close(); } - mCachedXmlBlocks[i] = null; + cachedXmlBlockFiles[i] = null; + cachedXmlBlocks[i] = null; } } } @@ -2451,6 +2458,12 @@ public class Resources { @Nullable Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException { + return loadDrawable(value, id, theme, true); + } + + @Nullable + Drawable loadDrawable(TypedValue value, int id, Theme theme, boolean useCache) + throws NotFoundException { try { if (TRACE_FOR_PRELOAD) { // Log only framework resources @@ -2477,16 +2490,17 @@ public class Resources { } // First, check whether we have a cached version of this drawable - // that was inflated against the specified theme. - if (!mPreloading) { + // that was inflated against the specified theme. Skip the cache if + // we're currently preloading or we're not using the cache. + if (!mPreloading && useCache) { final Drawable cachedDrawable = caches.getInstance(key, theme); if (cachedDrawable != null) { return cachedDrawable; } } - // Next, check preloaded drawables. These may contain unresolved theme - // attributes. + // Next, check preloaded drawables. Preloaded drawables may contain + // unresolved theme attributes. final ConstantState cs; if (isColorDrawable) { cs = sPreloadedColorDrawables.get(key); @@ -2514,8 +2528,9 @@ public class Resources { } // If we were able to obtain a drawable, store it in the appropriate - // cache: preload, not themed, null theme, or theme-specific. - if (dr != null) { + // cache: preload, not themed, null theme, or theme-specific. Don't + // pollute the cache with drawables loaded from a foreign density. + if (dr != null && useCache) { dr.setChangingConfigurations(value.changingConfigurations); cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr); } @@ -2744,7 +2759,16 @@ public class Resources { return csl; } - /*package*/ XmlResourceParser loadXmlResourceParser(int id, String type) + /** + * Loads an XML parser for the specified file. + * + * @param id the resource identifier for the file + * @param type the type of resource (used for logging) + * @return a parser for the specified XML file + * @throws NotFoundException if the file could not be loaded + */ + @NonNull + XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type) throws NotFoundException { final TypedValue value = obtainTempTypedValue(id); try { @@ -2758,53 +2782,58 @@ public class Resources { releaseTempTypedValue(value); } } - - /*package*/ XmlResourceParser loadXmlResourceParser(String file, int id, - int assetCookie, String type) throws NotFoundException { + + /** + * Loads an XML parser for the specified file. + * + * @param file the path for the XML file to parse + * @param id the resource identifier for the file + * @param assetCookie the asset cookie for the file + * @param type the type of resource (used for logging) + * @return a parser for the specified XML file + * @throws NotFoundException if the file could not be loaded + */ + @NonNull + XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id, + int assetCookie, @NonNull String type) throws NotFoundException { if (id != 0) { try { - // These may be compiled... - synchronized (mCachedXmlBlockIds) { + final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles; + final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks; + synchronized (cachedXmlBlockFiles) { // First see if this block is in our cache. - final int num = mCachedXmlBlockIds.length; - for (int i=0; i<num; i++) { - if (mCachedXmlBlockIds[i] == id) { - //System.out.println("**** REUSING XML BLOCK! id=" - // + id + ", index=" + i); - return mCachedXmlBlocks[i].newParser(); + final int num = cachedXmlBlockFiles.length; + for (int i = 0; i < num; i++) { + if (cachedXmlBlockFiles[i] != null + && cachedXmlBlockFiles[i].equals(file)) { + return cachedXmlBlocks[i].newParser(); } } // Not in the cache, create a new block and put it at // the next slot in the cache. - XmlBlock block = mAssets.openXmlBlockAsset( - assetCookie, file); + final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file); if (block != null) { - int pos = mLastCachedXmlBlockIndex+1; - if (pos >= num) pos = 0; + final int pos = (mLastCachedXmlBlockIndex + 1) % num; mLastCachedXmlBlockIndex = pos; - XmlBlock oldBlock = mCachedXmlBlocks[pos]; + final XmlBlock oldBlock = cachedXmlBlocks[pos]; if (oldBlock != null) { oldBlock.close(); } - mCachedXmlBlockIds[pos] = id; - mCachedXmlBlocks[pos] = block; - //System.out.println("**** CACHING NEW XML BLOCK! id=" - // + id + ", index=" + pos); + cachedXmlBlockFiles[pos] = file; + cachedXmlBlocks[pos] = block; return block.newParser(); } } } catch (Exception e) { - NotFoundException rnf = new NotFoundException( - "File " + file + " from xml type " + type + " resource ID #0x" - + Integer.toHexString(id)); + final NotFoundException rnf = new NotFoundException("File " + file + + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id)); rnf.initCause(e); throw rnf; } } - throw new NotFoundException( - "File " + file + " from xml type " + type + " resource ID #0x" + throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id)); } diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java index 8f45f72de6e2..852a4d9fd015 100644 --- a/core/java/android/hardware/camera2/CameraDevice.java +++ b/core/java/android/hardware/camera2/CameraDevice.java @@ -168,7 +168,7 @@ public abstract class CameraDevice implements AutoCloseable { * <p>The active capture session determines the set of potential output Surfaces for * the camera device for each capture request. A given request may use all * or only some of the outputs. Once the CameraCaptureSession is created, requests can be - * can be submitted with {@link CameraCaptureSession#capture capture}, + * submitted with {@link CameraCaptureSession#capture capture}, * {@link CameraCaptureSession#captureBurst captureBurst}, * {@link CameraCaptureSession#setRepeatingRequest setRepeatingRequest}, or * {@link CameraCaptureSession#setRepeatingBurst setRepeatingBurst}.</p> diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl index b8f464d76b0d..5d969b196492 100644 --- a/core/java/android/hardware/input/IInputManager.aidl +++ b/core/java/android/hardware/input/IInputManager.aidl @@ -49,11 +49,12 @@ interface IInputManager { // Keyboard layouts configuration. KeyboardLayout[] getKeyboardLayouts(); + KeyboardLayout[] getKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier); KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor); String getCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier); void setCurrentKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, String keyboardLayoutDescriptor); - String[] getKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier); + String[] getEnabledKeyboardLayoutsForInputDevice(in InputDeviceIdentifier identifier); void addKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, String keyboardLayoutDescriptor); void removeKeyboardLayoutForInputDevice(in InputDeviceIdentifier identifier, diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java index 16b872233f06..9972f49aab1b 100644 --- a/core/java/android/hardware/input/InputManager.java +++ b/core/java/android/hardware/input/InputManager.java @@ -474,6 +474,29 @@ public final class InputManager { } /** + * Gets information about all supported keyboard layouts appropriate + * for a specific input device. + * <p> + * The input manager consults the built-in keyboard layouts as well + * as all keyboard layouts advertised by applications using a + * {@link #ACTION_QUERY_KEYBOARD_LAYOUTS} broadcast receiver. + * </p> + * + * @return A list of all supported keyboard layouts for a specific + * input device. + * + * @hide + */ + public KeyboardLayout[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { + try { + return mIm.getKeyboardLayoutsForInputDevice(identifier); + } catch (RemoteException ex) { + Log.w(TAG, "Could not get list of keyboard layouts for input device.", ex); + return new KeyboardLayout[0]; + } + } + + /** * Gets the keyboard layout with the specified descriptor. * * @param keyboardLayoutDescriptor The keyboard layout descriptor, as returned by @@ -551,13 +574,13 @@ public final class InputManager { * @return The keyboard layout descriptors. * @hide */ - public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { + public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { if (identifier == null) { throw new IllegalArgumentException("inputDeviceDescriptor must not be null"); } try { - return mIm.getKeyboardLayoutsForInputDevice(identifier); + return mIm.getEnabledKeyboardLayoutsForInputDevice(identifier); } catch (RemoteException ex) { Log.w(TAG, "Could not get keyboard layouts for input device.", ex); return ArrayUtils.emptyArray(String.class); diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java index ed51402bdac8..584008c1db33 100644 --- a/core/java/android/hardware/input/KeyboardLayout.java +++ b/core/java/android/hardware/input/KeyboardLayout.java @@ -19,6 +19,8 @@ package android.hardware.input; import android.os.Parcel; import android.os.Parcelable; +import java.util.Locale; + /** * Describes a keyboard layout. * @@ -30,6 +32,9 @@ public final class KeyboardLayout implements Parcelable, private final String mLabel; private final String mCollection; private final int mPriority; + private final Locale[] mLocales; + private final int mVendorId; + private final int mProductId; public static final Parcelable.Creator<KeyboardLayout> CREATOR = new Parcelable.Creator<KeyboardLayout>() { @@ -41,11 +46,19 @@ public final class KeyboardLayout implements Parcelable, } }; - public KeyboardLayout(String descriptor, String label, String collection, int priority) { + public KeyboardLayout(String descriptor, String label, String collection, int priority, + Locale[] locales, int vid, int pid) { mDescriptor = descriptor; mLabel = label; mCollection = collection; mPriority = priority; + if (locales != null) { + mLocales = locales; + } else { + mLocales = new Locale[0]; + } + mVendorId = vid; + mProductId = pid; } private KeyboardLayout(Parcel source) { @@ -53,6 +66,13 @@ public final class KeyboardLayout implements Parcelable, mLabel = source.readString(); mCollection = source.readString(); mPriority = source.readInt(); + int N = source.readInt(); + mLocales = new Locale[N]; + for (int i = 0; i < N; i++) { + mLocales[i] = Locale.forLanguageTag(source.readString()); + } + mVendorId = source.readInt(); + mProductId = source.readInt(); } /** @@ -83,6 +103,33 @@ public final class KeyboardLayout implements Parcelable, return mCollection; } + /** + * Gets the locales that this keyboard layout is intended for. + * This may be empty if a locale has not been assigned to this keyboard layout. + * @return The keyboard layout's intended locale. + */ + public Locale[] getLocales() { + return mLocales; + } + + /** + * Gets the vendor ID of the hardware device this keyboard layout is intended for. + * Returns -1 if this is not specific to any piece of hardware. + * @return The hardware vendor ID of the keyboard layout's intended device. + */ + public int getVendorId() { + return mVendorId; + } + + /** + * Gets the product ID of the hardware device this keyboard layout is intended for. + * Returns -1 if this is not specific to any piece of hardware. + * @return The hardware product ID of the keyboard layout's intended device. + */ + public int getProductId() { + return mProductId; + } + @Override public int describeContents() { return 0; @@ -94,6 +141,16 @@ public final class KeyboardLayout implements Parcelable, dest.writeString(mLabel); dest.writeString(mCollection); dest.writeInt(mPriority); + if (mLocales != null) { + dest.writeInt(mLocales.length); + for (Locale l : mLocales) { + dest.writeString(l.toLanguageTag()); + } + } else { + dest.writeInt(0); + } + dest.writeInt(mVendorId); + dest.writeInt(mProductId); } @Override diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 8ab8991c7a42..f642f08df76e 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -19,16 +19,22 @@ package android.inputmethodservice; import static android.view.ViewGroup.LayoutParams.MATCH_PARENT; import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT; +import android.annotation.CallSuper; import android.annotation.DrawableRes; +import android.annotation.IntDef; +import android.annotation.MainThread; import android.app.ActivityManager; import android.app.Dialog; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; +import android.database.ContentObserver; import android.graphics.Rect; import android.graphics.Region; +import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.os.IBinder; import android.os.ResultReceiver; import android.os.SystemClock; @@ -68,6 +74,8 @@ import android.widget.LinearLayout; import java.io.FileDescriptor; import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * InputMethodService provides a standard implementation of an InputMethod, @@ -634,6 +642,97 @@ public class InputMethodService extends AbstractInputMethodService { } /** + * A {@link ContentObserver} to monitor {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD}. + * + * <p>Note that {@link Settings.Secure#SHOW_IME_WITH_HARD_KEYBOARD} is not a public API. + * Basically this functionality still needs to be considered as implementation details.</p> + */ + @MainThread + private static final class SettingsObserver extends ContentObserver { + @Retention(RetentionPolicy.SOURCE) + @IntDef({ + ShowImeWithHardKeyboardType.UNKNOWN, + ShowImeWithHardKeyboardType.FALSE, + ShowImeWithHardKeyboardType.TRUE, + }) + private @interface ShowImeWithHardKeyboardType { + int UNKNOWN = 0; + int FALSE = 1; + int TRUE = 2; + } + @ShowImeWithHardKeyboardType + private int mShowImeWithHardKeyboard = ShowImeWithHardKeyboardType.UNKNOWN; + + private final InputMethodService mService; + + private SettingsObserver(InputMethodService service) { + super(new Handler(service.getMainLooper())); + mService = service; + } + + /** + * A factory method that internally enforces two-phase initialization to make sure that the + * object reference will not be escaped until the object is properly constructed. + * + * <p>NOTE: Currently {@link SettingsObserver} is accessed only from main thread. Hence + * this enforcement of two-phase initialization may be unnecessary at the moment.</p> + * + * @param service {@link InputMethodService} that needs to receive the callback. + * @return {@link SettingsObserver} that is already registered to + * {@link android.content.ContentResolver}. The caller must call + * {@link SettingsObserver#unregister()}. + */ + public static SettingsObserver createAndRegister(InputMethodService service) { + final SettingsObserver observer = new SettingsObserver(service); + // The observer is properly constructed. Let's start accepting the event. + service.getContentResolver().registerContentObserver( + Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), + false, observer); + return observer; + } + + void unregister() { + mService.getContentResolver().unregisterContentObserver(this); + } + + private boolean shouldShowImeWithHardKeyboard() { + // Lazily initialize as needed. + if (mShowImeWithHardKeyboard == ShowImeWithHardKeyboardType.UNKNOWN) { + mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(), + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ? + ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE; + } + switch (mShowImeWithHardKeyboard) { + case ShowImeWithHardKeyboardType.TRUE: + return true; + case ShowImeWithHardKeyboardType.FALSE: + return false; + default: + Log.e(TAG, "Unexpected mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard); + return false; + } + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + final Uri showImeWithHardKeyboardUri = + Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); + if (showImeWithHardKeyboardUri.equals(uri)) { + mShowImeWithHardKeyboard = Settings.Secure.getInt(mService.getContentResolver(), + Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0 ? + ShowImeWithHardKeyboardType.TRUE : ShowImeWithHardKeyboardType.FALSE; + mService.updateInputViewShown(); + } + } + + @Override + public String toString() { + return "SettingsObserver{mShowImeWithHardKeyboard=" + mShowImeWithHardKeyboard + "}"; + } + } + private SettingsObserver mSettingsObserver; + + /** * You can call this to customize the theme used by your IME's window. * This theme should typically be one that derives from * {@link android.R.style#Theme_InputMethod}, which is the default theme @@ -682,6 +781,7 @@ public class InputMethodService extends AbstractInputMethodService { super.setTheme(mTheme); super.onCreate(); mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE); + mSettingsObserver = SettingsObserver.createAndRegister(this); // If the previous IME has occupied non-empty inset in the screen, we need to decide whether // we continue to use the same size of the inset or update it mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0); @@ -764,6 +864,10 @@ public class InputMethodService extends AbstractInputMethodService { mWindow.getWindow().setWindowAnimations(0); mWindow.dismiss(); } + if (mSettingsObserver != null) { + mSettingsObserver.unregister(); + mSettingsObserver = null; + } } /** @@ -1140,21 +1244,28 @@ public class InputMethodService extends AbstractInputMethodService { public boolean isInputViewShown() { return mIsInputViewShown && mWindowVisible; } - + /** - * Override this to control when the soft input area should be shown to - * the user. The default implementation only shows the input view when - * there is no hard keyboard or the keyboard is hidden. If you change what - * this returns, you will need to call {@link #updateInputViewShown()} - * yourself whenever the returned value may have changed to have it - * re-evaluated and applied. + * Override this to control when the soft input area should be shown to the user. The default + * implementation returns {@code false} when there is no hard keyboard or the keyboard is hidden + * unless the user shows an intention to use software keyboard. If you change what this + * returns, you will need to call {@link #updateInputViewShown()} yourself whenever the returned + * value may have changed to have it re-evaluated and applied. + * + * <p>When you override this method, it is recommended to call + * {@code super.onEvaluateInputViewShown()} and return {@code true} when {@code true} is + * returned.</p> */ + @CallSuper public boolean onEvaluateInputViewShown() { + if (mSettingsObserver.shouldShowImeWithHardKeyboard()) { + return true; + } Configuration config = getResources().getConfiguration(); return config.keyboard == Configuration.KEYBOARD_NOKEYS || config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES; } - + /** * Controls the visibility of the candidates display area. By default * it is hidden. @@ -2483,5 +2594,6 @@ public class InputMethodService extends AbstractInputMethodService { + " touchableInsets=" + mTmpInsets.touchableInsets + " touchableRegion=" + mTmpInsets.touchableRegion); p.println(" mShouldClearInsetOfPreviousIme=" + mShouldClearInsetOfPreviousIme); + p.println(" mSettingsObserver=" + mSettingsObserver); } } diff --git a/core/java/android/net/NetworkScorerAppManager.java b/core/java/android/net/NetworkScorerAppManager.java index ec76b8a6633e..e555fa412a5b 100644 --- a/core/java/android/net/NetworkScorerAppManager.java +++ b/core/java/android/net/NetworkScorerAppManager.java @@ -33,6 +33,7 @@ import android.util.Log; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -90,13 +91,18 @@ public final class NetworkScorerAppManager { * @return the list of scorers, or the empty list if there are no valid scorers. */ public static Collection<NetworkScorerAppData> getAllValidScorers(Context context) { - List<NetworkScorerAppData> scorers = new ArrayList<>(); + // Network scorer apps can only run as the primary user so exit early if we're not the + // primary user. + if (UserHandle.getCallingUserId() != UserHandle.USER_SYSTEM) { + return Collections.emptyList(); + } + List<NetworkScorerAppData> scorers = new ArrayList<>(); PackageManager pm = context.getPackageManager(); // Only apps installed under the primary user of the device can be scorers. // TODO: http://b/23422763 List<ResolveInfo> receivers = - pm.queryBroadcastReceivers(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM); + pm.queryBroadcastReceiversAsUser(SCORE_INTENT, 0 /* flags */, UserHandle.USER_SYSTEM); for (ResolveInfo receiver : receivers) { // This field is a misnomer, see android.content.pm.ResolveInfo#activityInfo final ActivityInfo receiverInfo = receiver.activityInfo; @@ -105,8 +111,9 @@ public final class NetworkScorerAppManager { continue; } if (!permission.BROADCAST_NETWORK_PRIVILEGED.equals(receiverInfo.permission)) { - // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which means - // anyone could trigger network scoring and flood the framework with score requests. + // Receiver doesn't require the BROADCAST_NETWORK_PRIVILEGED permission, which + // means anyone could trigger network scoring and flood the framework with score + // requests. continue; } if (pm.checkPermission(permission.SCORE_NETWORKS, receiverInfo.packageName) != @@ -128,8 +135,8 @@ public final class NetworkScorerAppManager { } } - // NOTE: loadLabel will attempt to load the receiver's label and fall back to the app - // label if none is present. + // NOTE: loadLabel will attempt to load the receiver's label and fall back to the + // app label if none is present. scorers.add(new NetworkScorerAppData(receiverInfo.packageName, receiverInfo.applicationInfo.uid, receiverInfo.loadLabel(pm), configurationActivityClassName)); diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java index 126824f2c46a..4159d89d1be1 100644 --- a/core/java/android/os/PowerManager.java +++ b/core/java/android/os/PowerManager.java @@ -980,6 +980,14 @@ public final class PowerManager { = "android.os.action.POWER_SAVE_MODE_CHANGED"; /** + * Intent that is broadcast when the state of {@link #isPowerSaveMode()} changes. + * @hide + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL + = "android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL"; + + /** * Intent that is broadcast when the state of {@link #isDeviceIdleMode()} changes. * This broadcast is only sent to registered receivers. */ diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java index 13b8b66306e1..2ba4aa433713 100644 --- a/core/java/android/os/ServiceManager.java +++ b/core/java/android/os/ServiceManager.java @@ -112,8 +112,10 @@ public final class ServiceManager { /** * Return a list of all currently running services. + * @return an array of all currently running services, or <code>null</code> in + * case of an exception */ - public static String[] listServices() throws RemoteException { + public static String[] listServices() { try { return getIServiceManager().listServices(); } catch (RemoteException e) { diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java index f946ca7ed415..867d0b963cda 100644 --- a/core/java/android/os/UserHandle.java +++ b/core/java/android/os/UserHandle.java @@ -16,7 +16,10 @@ package android.os; +import android.annotation.AppIdInt; import android.annotation.SystemApi; +import android.annotation.TestApi; +import android.annotation.UserIdInt; import java.io.PrintWriter; @@ -127,7 +130,7 @@ public final class UserHandle implements Parcelable { * Returns the user id for a given uid. * @hide */ - public static int getUserId(int uid) { + public static @UserIdInt int getUserId(int uid) { if (MU_ENABLED) { return uid / PER_USER_RANGE; } else { @@ -136,12 +139,12 @@ public final class UserHandle implements Parcelable { } /** @hide */ - public static int getCallingUserId() { + public static @UserIdInt int getCallingUserId() { return getUserId(Binder.getCallingUid()); } /** @hide */ - public static UserHandle of(int userId) { + public static UserHandle of(@UserIdInt int userId) { return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId); } @@ -149,7 +152,7 @@ public final class UserHandle implements Parcelable { * Returns the uid that is composed from the userId and the appId. * @hide */ - public static int getUid(int userId, int appId) { + public static int getUid(@UserIdInt int userId, @AppIdInt int appId) { if (MU_ENABLED) { return userId * PER_USER_RANGE + (appId % PER_USER_RANGE); } else { @@ -161,7 +164,8 @@ public final class UserHandle implements Parcelable { * Returns the app id (or base uid) for a given uid, stripping out the user id from it. * @hide */ - public static int getAppId(int uid) { + @TestApi + public static @AppIdInt int getAppId(int uid) { return uid % PER_USER_RANGE; } @@ -169,7 +173,7 @@ public final class UserHandle implements Parcelable { * Returns the gid shared between all apps with this userId. * @hide */ - public static int getUserGid(int userId) { + public static int getUserGid(@UserIdInt int userId) { return getUid(userId, Process.SHARED_USER_GID); } @@ -186,7 +190,7 @@ public final class UserHandle implements Parcelable { * Returns the app id for a given shared app gid. Returns -1 if the ID is invalid. * @hide */ - public static int getAppIdFromSharedAppGid(int gid) { + public static @AppIdInt int getAppIdFromSharedAppGid(int gid) { final int appId = getAppId(gid) + Process.FIRST_APPLICATION_UID - Process.FIRST_SHARED_APPLICATION_GID; if (appId < 0 || appId >= Process.FIRST_SHARED_APPLICATION_GID) { @@ -257,7 +261,7 @@ public final class UserHandle implements Parcelable { } /** @hide */ - public static int parseUserArg(String arg) { + public static @UserIdInt int parseUserArg(String arg) { int userId; if ("all".equals(arg)) { userId = UserHandle.USER_ALL; @@ -279,7 +283,7 @@ public final class UserHandle implements Parcelable { * @hide */ @SystemApi - public static int myUserId() { + public static @UserIdInt int myUserId() { return getUserId(Process.myUid()); } @@ -315,7 +319,7 @@ public final class UserHandle implements Parcelable { * @hide */ @SystemApi - public int getIdentifier() { + public @UserIdInt int getIdentifier() { return mHandle; } diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 037916a94e5f..d1b3f590b024 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -20,6 +20,7 @@ import android.accounts.AccountManager; import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; +import android.annotation.UserIdInt; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; @@ -517,6 +518,16 @@ public class UserManager { public static final String DISALLOW_CAMERA = "no_camera"; /** + * Specifies if a user is not allowed to use cellular data when roaming. This can only be set by + * device owners. The default value is <code>false</code>. + * + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) + * @see #getUserRestrictions() + */ + public static final String DISALLOW_DATA_ROAMING = "no_data_roaming"; + + /** * Allows apps in the parent profile to handle web links from the managed profile. * * This user restriction has an effect only in a managed profile. @@ -601,7 +612,7 @@ public class UserManager { * @return the user handle of this process. * @hide */ - public int getUserHandle() { + public @UserIdInt int getUserHandle() { return UserHandle.myUserId(); } @@ -671,7 +682,7 @@ public class UserManager { * Returns whether the provided user is an admin user. There can be more than one admin * user. */ - public boolean isUserAdmin(int userId) { + public boolean isUserAdmin(@UserIdInt int userId) { UserInfo user = getUserInfo(userId); return user != null && user.isAdmin(); } @@ -695,7 +706,7 @@ public class UserManager { * Checks if specified user can have restricted profile. * @hide */ - public boolean canHaveRestrictedProfile(int userId) { + public boolean canHaveRestrictedProfile(@UserIdInt int userId) { try { return mService.canHaveRestrictedProfile(userId); } catch (RemoteException re) { @@ -741,7 +752,7 @@ public class UserManager { * Returns whether the specified user is ephemeral. * @hide */ - public boolean isUserEphemeral(int userId) { + public boolean isUserEphemeral(@UserIdInt int userId) { final UserInfo user = getUserInfo(userId); return user != null && user.isEphemeral(); } @@ -861,7 +872,7 @@ public class UserManager { } /** {@hide} */ - public boolean isUserUnlocked(int userId) { + public boolean isUserUnlocked(@UserIdInt int userId) { // TODO: eventually pivot this back to look at ActivityManager state, // but there is race where we can start a non-encryption-aware launcher // before that lifecycle has entered the running unlocked state. @@ -875,7 +886,7 @@ public class UserManager { * @return the UserInfo object for a specific user. * @hide */ - public UserInfo getUserInfo(int userHandle) { + public UserInfo getUserInfo(@UserIdInt int userHandle) { try { return mService.getUserInfo(userHandle); } catch (RemoteException re) { @@ -1093,7 +1104,7 @@ public class UserManager { * @return the UserInfo object for the created user, or null if the user could not be created. * @hide */ - public UserInfo createProfileForUser(String name, int flags, int userHandle) { + public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle) { try { return mService.createProfileForUser(name, flags, userHandle); } catch (RemoteException re) { @@ -1133,7 +1144,7 @@ public class UserManager { * @param userHandle * @return */ - public boolean markGuestForDeletion(int userHandle) { + public boolean markGuestForDeletion(@UserIdInt int userHandle) { try { return mService.markGuestForDeletion(userHandle); } catch (RemoteException re) { @@ -1150,7 +1161,7 @@ public class UserManager { * @param userHandle the id of the profile to enable * @hide */ - public void setUserEnabled(int userHandle) { + public void setUserEnabled(@UserIdInt int userHandle) { try { mService.setUserEnabled(userHandle); } catch (RemoteException e) { @@ -1189,7 +1200,7 @@ public class UserManager { Manifest.permission.INTERACT_ACROSS_USERS_FULL, Manifest.permission.MANAGE_USERS }) - public @Nullable String getUserAccount(int userHandle) { + public @Nullable String getUserAccount(@UserIdInt int userHandle) { try { return mService.getUserAccount(userHandle); } catch (RemoteException re) { @@ -1206,7 +1217,7 @@ public class UserManager { Manifest.permission.INTERACT_ACROSS_USERS_FULL, Manifest.permission.MANAGE_USERS }) - public void setUserAccount(int userHandle, @Nullable String accountName) { + public void setUserAccount(@UserIdInt int userHandle, @Nullable String accountName) { try { mService.setUserAccount(userHandle, accountName); } catch (RemoteException re) { @@ -1259,7 +1270,7 @@ public class UserManager { * @return true if more managed profiles can be added, false if limit has been reached. * @hide */ - public boolean canAddMoreManagedProfiles(int userId, boolean allowedToRemoveOne) { + public boolean canAddMoreManagedProfiles(@UserIdInt int userId, boolean allowedToRemoveOne) { try { return mService.canAddMoreManagedProfiles(userId, allowedToRemoveOne); } catch (RemoteException re) { @@ -1279,7 +1290,7 @@ public class UserManager { * @return the list of profiles. * @hide */ - public List<UserInfo> getProfiles(int userHandle) { + public List<UserInfo> getProfiles(@UserIdInt int userHandle) { try { return mService.getProfiles(userHandle, false /* enabledOnly */); } catch (RemoteException re) { @@ -1295,7 +1306,7 @@ public class UserManager { * @return true if the two user ids are in the same profile group. * @hide */ - public boolean isSameProfileGroup(int userId, int otherUserId) { + public boolean isSameProfileGroup(@UserIdInt int userId, int otherUserId) { try { return mService.isSameProfileGroup(userId, otherUserId); } catch (RemoteException re) { @@ -1314,7 +1325,7 @@ public class UserManager { * @return the list of profiles. * @hide */ - public List<UserInfo> getEnabledProfiles(int userHandle) { + public List<UserInfo> getEnabledProfiles(@UserIdInt int userHandle) { try { return mService.getProfiles(userHandle, true /* enabledOnly */); } catch (RemoteException re) { @@ -1352,7 +1363,7 @@ public class UserManager { * * @hide */ - public int getCredentialOwnerProfile(int userHandle) { + public int getCredentialOwnerProfile(@UserIdInt int userHandle) { try { return mService.getCredentialOwnerProfile(userHandle); } catch (RemoteException re) { @@ -1367,7 +1378,7 @@ public class UserManager { * * @hide */ - public UserInfo getProfileParent(int userHandle) { + public UserInfo getProfileParent(@UserIdInt int userHandle) { try { return mService.getProfileParent(userHandle); } catch (RemoteException re) { @@ -1383,7 +1394,7 @@ public class UserManager { * @param enableQuietMode Whether quiet mode should be enabled or disabled. * @hide */ - public void setQuietModeEnabled(int userHandle, boolean enableQuietMode) { + public void setQuietModeEnabled(@UserIdInt int userHandle, boolean enableQuietMode) { try { mService.setQuietModeEnabled(userHandle, enableQuietMode); } catch (RemoteException e) { @@ -1499,7 +1510,7 @@ public class UserManager { * @param userHandle the integer handle of the user, where 0 is the primary user. * @hide */ - public boolean removeUser(int userHandle) { + public boolean removeUser(@UserIdInt int userHandle) { try { return mService.removeUser(userHandle); } catch (RemoteException re) { @@ -1516,7 +1527,7 @@ public class UserManager { * @param name the new name for the user * @hide */ - public void setUserName(int userHandle, String name) { + public void setUserName(@UserIdInt int userHandle, String name) { try { mService.setUserName(userHandle, name); } catch (RemoteException re) { @@ -1530,7 +1541,7 @@ public class UserManager { * @param icon the bitmap to set as the photo. * @hide */ - public void setUserIcon(int userHandle, Bitmap icon) { + public void setUserIcon(@UserIdInt int userHandle, Bitmap icon) { try { mService.setUserIcon(userHandle, icon); } catch (RemoteException re) { @@ -1545,7 +1556,7 @@ public class UserManager { * @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default. * @hide */ - public Bitmap getUserIcon(int userHandle) { + public Bitmap getUserIcon(@UserIdInt int userHandle) { try { ParcelFileDescriptor fd = mService.getUserIcon(userHandle); if (fd != null) { @@ -1611,7 +1622,7 @@ public class UserManager { * @return a serial number associated with that user, or -1 if the userHandle is not valid. * @hide */ - public int getUserSerialNumber(int userHandle) { + public int getUserSerialNumber(@UserIdInt int userHandle) { try { return mService.getUserSerialNumber(userHandle); } catch (RemoteException re) { @@ -1629,7 +1640,7 @@ public class UserManager { * is not valid. * @hide */ - public int getUserHandle(int userSerialNumber) { + public @UserIdInt int getUserHandle(int userSerialNumber) { try { return mService.getUserHandle(userSerialNumber); } catch (RemoteException re) { diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java index beda16996e0e..49d41cfaf997 100644 --- a/core/java/android/os/storage/StorageManager.java +++ b/core/java/android/os/storage/StorageManager.java @@ -882,7 +882,8 @@ public class StorageManager { } packageName = packageNames[0]; } - final int uid = ActivityThread.getPackageManager().getPackageUid(packageName, userId); + final int uid = ActivityThread.getPackageManager().getPackageUidEtc(packageName, + PackageManager.MATCH_DEBUG_TRIAGED_MISSING, userId); if (uid <= 0) { return new StorageVolume[0]; } diff --git a/core/java/android/print/IPrintSpooler.aidl b/core/java/android/print/IPrintSpooler.aidl index c3625b8fb029..469a4ea812b5 100644 --- a/core/java/android/print/IPrintSpooler.aidl +++ b/core/java/android/print/IPrintSpooler.aidl @@ -98,5 +98,11 @@ oneway interface IPrintSpooler { void writePrintJobData(in ParcelFileDescriptor fd, in PrintJobId printJobId); void setClient(IPrintSpoolerClient client); void setPrintJobCancelling(in PrintJobId printJobId, boolean cancelling); - void removeApprovedPrintService(in ComponentName serviceToRemove); + + /** + * Remove all approved print services that are not in the given set. + * + * @param servicesToKeep The names of the services to keep + */ + void pruneApprovedPrintServices(in List<ComponentName> servicesToKeep); } diff --git a/core/java/android/print/PrinterInfo.java b/core/java/android/print/PrinterInfo.java index 20d91b20e814..afef9c0dac27 100644 --- a/core/java/android/print/PrinterInfo.java +++ b/core/java/android/print/PrinterInfo.java @@ -410,7 +410,7 @@ public final class PrinterInfo implements Parcelable { * @see PrinterInfo#STATUS_BUSY * @see PrinterInfo#STATUS_UNAVAILABLE */ - public @Nullable Builder setStatus(@Status int status) { + public @NonNull Builder setStatus(@Status int status) { mPrototype.mStatus = status; return this; } diff --git a/core/java/android/printservice/PrintServiceInfo.java b/core/java/android/printservice/PrintServiceInfo.java index b33ef8304556..91e01f2dfd8b 100644 --- a/core/java/android/printservice/PrintServiceInfo.java +++ b/core/java/android/printservice/PrintServiceInfo.java @@ -16,6 +16,7 @@ package android.printservice; +import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -94,6 +95,16 @@ public final class PrintServiceInfo implements Parcelable { } /** + * Return the component name for this print service. + * + * @return The component name for this print service. + */ + public @NonNull ComponentName getComponentName() { + return new ComponentName(mResolveInfo.serviceInfo.packageName, + mResolveInfo.serviceInfo.name); + } + + /** * Creates a new instance. * * @param resolveInfo The service resolve info. diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 084ff7728ca4..a401ac2ff864 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -230,7 +230,6 @@ public final class DocumentsContract { * @see #FLAG_SUPPORTS_WRITE * @see #FLAG_SUPPORTS_DELETE * @see #FLAG_SUPPORTS_THUMBNAIL - * @see #FLAG_SUPPORTS_TYPED_DOCUMENT * @see #FLAG_DIR_PREFERS_GRID * @see #FLAG_DIR_PREFERS_LAST_MODIFIED * @see #FLAG_VIRTUAL_DOCUMENT @@ -349,15 +348,6 @@ public final class DocumentsContract { public static final int FLAG_SUPPORTS_MOVE = 1 << 8; /** - * Flag indicating that a document can be converted to alternative types. - * - * @see #COLUMN_FLAGS - * @see DocumentsProvider#openTypedDocument(String, String, Bundle, - * android.os.CancellationSignal) - */ - public static final int FLAG_SUPPORTS_TYPED_DOCUMENT = 1 << 9; - - /** * Flag indicating that a document is virtual, and doesn't have byte * representation in the MIME type specified as {@link #COLUMN_MIME_TYPE}. * @@ -366,7 +356,7 @@ public final class DocumentsContract { * @see DocumentsProvider#openTypedDocument(String, String, Bundle, * android.os.CancellationSignal) */ - public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 10; + public static final int FLAG_VIRTUAL_DOCUMENT = 1 << 9; /** * Flag indicating that a document is an archive, and it's contents can be @@ -378,7 +368,7 @@ public final class DocumentsContract { * @see #COLUMN_FLAGS * @see DocumentsProvider#queryChildDocuments(String, String[], String) */ - public static final int FLAG_ARCHIVE = 1 << 11; + public static final int FLAG_ARCHIVE = 1 << 10; /** * Flag indicating that document titles should be hidden when viewing diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java index e25ba35c8bb6..94b41575d0a3 100644 --- a/core/java/android/provider/DocumentsProvider.java +++ b/core/java/android/provider/DocumentsProvider.java @@ -517,13 +517,12 @@ public abstract class DocumentsProvider extends ContentProvider { * provider. * @param signal used by the caller to signal if the request should be * cancelled. May be null. - * @see Document#FLAG_SUPPORTS_TYPED_DOCUMENT */ @SuppressWarnings("unused") public AssetFileDescriptor openTypedDocument( String documentId, String mimeTypeFilter, Bundle opts, CancellationSignal signal) throws FileNotFoundException { - throw new UnsupportedOperationException("Typed documents not supported"); + throw new FileNotFoundException("The requested MIME type is not supported."); } /** diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java index 48b3c1a1b064..89ac27c9a816 100644 --- a/core/java/android/provider/MediaStore.java +++ b/core/java/android/provider/MediaStore.java @@ -384,8 +384,14 @@ public final class MediaStore { public interface MediaColumns extends BaseColumns { /** - * The data stream for the file - * <P>Type: DATA STREAM</P> + * Path to the file on disk. + * <p> + * Note that apps may not have filesystem permissions to directly access + * this path. Instead of trying to open this path directly, apps should + * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain + * access. + * <p> + * Type: TEXT */ public static final String DATA = "_data"; @@ -1149,8 +1155,15 @@ public final class MediaStore { public static final String DEFAULT_SORT_ORDER = "image_id ASC"; /** - * The data stream for the thumbnail - * <P>Type: DATA STREAM</P> + * Path to the thumbnail file on disk. + * <p> + * Note that apps may not have filesystem permissions to directly + * access this path. Instead of trying to open this path directly, + * apps should use + * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain + * access. + * <p> + * Type: TEXT */ public static final String DATA = "_data"; @@ -1596,8 +1609,15 @@ public final class MediaStore { public static final String NAME = "name"; /** - * The data stream for the playlist file - * <P>Type: DATA STREAM</P> + * Path to the playlist file on disk. + * <p> + * Note that apps may not have filesystem permissions to directly + * access this path. Instead of trying to open this path directly, + * apps should use + * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain + * access. + * <p> + * Type: TEXT */ public static final String DATA = "_data"; @@ -2192,8 +2212,15 @@ public final class MediaStore { public static final String DEFAULT_SORT_ORDER = "video_id ASC"; /** - * The data stream for the thumbnail - * <P>Type: DATA STREAM</P> + * Path to the thumbnail file on disk. + * <p> + * Note that apps may not have filesystem permissions to directly + * access this path. Instead of trying to open this path directly, + * apps should use + * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain + * access. + * <p> + * Type: TEXT */ public static final String DATA = "_data"; diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 4eaee0b44fc5..a0066741e11d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -19,6 +19,7 @@ package android.provider; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; +import android.annotation.TestApi; import android.app.ActivityThread; import android.app.AppOpsManager; import android.app.Application; @@ -1138,6 +1139,19 @@ public final class Settings { /** @hide */ public static final String EXTRA_APP_UID = "app_uid"; /** @hide */ public static final String EXTRA_APP_PACKAGE = "app_package"; + /** + * Activity Action: Show a dialog with disabled by policy message. + * <p> If an user action is disabled by policy, this dialog can be triggered to let + * the user know about this. + * <p> + * Input: Nothing. + * <p> + * Output: Nothing. + */ + @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) + public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS + = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS"; + // End of Intent actions for Settings /** @@ -2592,6 +2606,15 @@ public final class Settings { private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator; /** + * Master mono (int 1 = mono, 0 = normal). + * + * @hide + */ + public static final String MASTER_MONO = "master_mono"; + + private static final Validator MASTER_MONO_VALIDATOR = sBooleanValidator; + + /** * Whether the notifications should use the ring volume (value of 1) or * a separate notification volume (value of 0). In most cases, users * will have this enabled so the notification and ringer volumes will be @@ -3286,7 +3309,8 @@ public final class Settings { VIBRATE_WHEN_RINGING, RINGTONE, LOCK_TO_APP_ENABLED, - NOTIFICATION_SOUND + NOTIFICATION_SOUND, + ACCELEROMETER_ROTATION }; /** @@ -3357,6 +3381,7 @@ public final class Settings { PRIVATE_SETTINGS.add(VOLUME_MASTER); PRIVATE_SETTINGS.add(VOLUME_MASTER_MUTE); PRIVATE_SETTINGS.add(MICROPHONE_MUTE); + PRIVATE_SETTINGS.add(MASTER_MONO); PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME); PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT); PRIVATE_SETTINGS.add(MEDIA_BUTTON_RECEIVER); @@ -3435,6 +3460,7 @@ public final class Settings { VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR); VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR); VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR); + VALIDATORS.put(MASTER_MONO, MASTER_MONO_VALIDATOR); VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR); VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR); VALIDATORS.put(MEDIA_BUTTON_RECEIVER, MEDIA_BUTTON_RECEIVER_VALIDATOR); @@ -4349,6 +4375,7 @@ public final class Settings { * The currently selected voice interaction service flattened ComponentName. * @hide */ + @TestApi public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service"; /** @@ -4972,19 +4999,22 @@ public final class Settings { /** * List of the enabled print services. + * + * N and beyond uses {@link #DISABLED_PRINT_SERVICES}. But this might be used in an upgrade + * from pre-N. + * * @hide */ public static final String ENABLED_PRINT_SERVICES = "enabled_print_services"; /** - * List of the system print services we enabled on first boot. On - * first boot we enable all system, i.e. bundled print services, - * once, so they work out-of-the-box. + * List of the disabled print services. + * * @hide */ - public static final String ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES = - "enabled_on_first_boot_system_print_services"; + public static final String DISABLED_PRINT_SERVICES = + "disabled_print_services"; /** * Setting to always use the default text-to-speech settings regardless @@ -5795,10 +5825,15 @@ public final class Settings { PARENTAL_CONTROL_ENABLED, PARENTAL_CONTROL_REDIRECT_URL, USB_MASS_STORAGE_ENABLED, // moved to global + ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, + ACCESSIBILITY_DISPLAY_DALTONIZER, + ACCESSIBILITY_DISPLAY_COLOR_MATRIX, + ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED, ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED, ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, ACCESSIBILITY_DISPLAY_MAGNIFICATION_AUTO_UPDATE, ACCESSIBILITY_SCRIPT_INJECTION, + ACCESSIBILITY_WEB_CONTENT_KEY_BINDINGS, BACKUP_AUTO_RESTORE, ENABLED_ACCESSIBILITY_SERVICES, ENABLED_NOTIFICATION_LISTENERS, @@ -5808,6 +5843,7 @@ public final class Settings { ACCESSIBILITY_ENABLED, ACCESSIBILITY_SPEAK_PASSWORD, ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED, + ACCESSIBILITY_CAPTIONING_PRESET, ACCESSIBILITY_CAPTIONING_ENABLED, ACCESSIBILITY_CAPTIONING_LOCALE, ACCESSIBILITY_CAPTIONING_BACKGROUND_COLOR, @@ -5816,6 +5852,7 @@ public final class Settings { ACCESSIBILITY_CAPTIONING_EDGE_COLOR, ACCESSIBILITY_CAPTIONING_TYPEFACE, ACCESSIBILITY_CAPTIONING_FONT_SCALE, + ACCESSIBILITY_CAPTIONING_WINDOW_COLOR, TTS_USE_DEFAULTS, TTS_DEFAULT_RATE, TTS_DEFAULT_PITCH, @@ -5824,6 +5861,7 @@ public final class Settings { TTS_DEFAULT_COUNTRY, TTS_ENABLED_PLUGINS, TTS_DEFAULT_LOCALE, + SHOW_IME_WITH_HARD_KEYBOARD, WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, // moved to global WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, // moved to global WIFI_NUM_OPEN_NETWORKS_KEPT, // moved to global @@ -5837,9 +5875,16 @@ public final class Settings { UI_NIGHT_MODE, SLEEP_TIMEOUT, DOUBLE_TAP_TO_WAKE, + WAKE_GESTURE_ENABLED, + LONG_PRESS_TIMEOUT, CAMERA_GESTURE_DISABLED, ACCESSIBILITY_AUTOCLICK_ENABLED, - ACCESSIBILITY_AUTOCLICK_DELAY + ACCESSIBILITY_AUTOCLICK_DELAY, + ACCESSIBILITY_LARGE_POINTER_ICON, + PREFERRED_TTY_MODE, + ENHANCED_VOICE_PRIVACY_ENABLED, + TTY_MODE_ENABLED, + INCALL_POWER_BUTTON_BEHAVIOR }; /** diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java index 3a8956ec15d9..aba82fad0bfa 100644 --- a/core/java/android/service/notification/NotificationAssistantService.java +++ b/core/java/android/service/notification/NotificationAssistantService.java @@ -17,13 +17,18 @@ package android.service.notification; import android.annotation.SdkConstant; +import android.annotation.SystemApi; +import android.app.INotificationManager; import android.app.Notification; +import android.content.ComponentName; +import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.IBinder; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; +import android.os.ServiceManager; import android.util.Log; /** diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java index b42d9eaf9cb5..ed90e795af00 100644 --- a/core/java/android/service/notification/NotificationListenerService.java +++ b/core/java/android/service/notification/NotificationListenerService.java @@ -692,6 +692,36 @@ public abstract class NotificationListenerService extends Service { } } + /** + * Request that the listener be rebound, after a previous call to (@link requestUnbind). + * + * <P>This method will fail for assistants that have + * not been granted the permission by the user. + * + * <P>The service should wait for the {@link #onListenerConnected()} event + * before performing any operations. + */ + public static final void requestRebind(ComponentName componentName) + throws RemoteException { + INotificationManager noMan = INotificationManager.Stub.asInterface( + ServiceManager.getService(Context.NOTIFICATION_SERVICE)); + noMan.requestBindListener(componentName); + } + + /** + * Request that the service be unbound. + * + * <P>This will no longer receive updates until + * {@link #requestRebind(ComponentName)} is called. + * The service will likely be kiled by the system after this call. + */ + public final void requestUnbind() throws RemoteException { + if (mWrapper != null) { + INotificationManager noMan = getNotificationInterface(); + noMan.requestUnbindListener(mWrapper); + } + } + /** Convert new-style Icons to legacy representations for pre-M clients. */ private void createLegacyIconExtras(Notification n) { Icon smallIcon = n.getSmallIcon(); @@ -1002,13 +1032,12 @@ public abstract class NotificationListenerService extends Service { return mImportanceExplanation; } - private void populate(String key, int rank, boolean isAmbient, - boolean matchesInterruptionFilter, int visibilityOverride, - int suppressedVisualEffects, int importance, + private void populate(String key, int rank, boolean matchesInterruptionFilter, + int visibilityOverride, int suppressedVisualEffects, int importance, CharSequence explanation) { mKey = key; mRank = rank; - mIsAmbient = isAmbient; + mIsAmbient = importance < IMPORTANCE_DEFAULT; mMatchesInterruptionFilter = matchesInterruptionFilter; mVisibilityOverride = visibilityOverride; mSuppressedVisualEffects = suppressedVisualEffects; @@ -1079,7 +1108,7 @@ public abstract class NotificationListenerService extends Service { */ public boolean getRanking(String key, Ranking outRanking) { int rank = getRank(key); - outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key), + outRanking.populate(key, rank, !isIntercepted(key), getVisibilityOverride(key), getSuppressedVisualEffects(key), getImportance(key), getImportanceExplanation(key)); return rank >= 0; @@ -1095,15 +1124,6 @@ public abstract class NotificationListenerService extends Service { return rank != null ? rank : -1; } - private boolean isAmbient(String key) { - int firstAmbientIndex = mRankingUpdate.getFirstAmbientIndex(); - if (firstAmbientIndex < 0) { - return false; - } - int rank = getRank(key); - return rank >= 0 && rank >= firstAmbientIndex; - } - private boolean isIntercepted(String key) { synchronized (this) { if (mIntercepted == null) { diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java index 0d42ffb4c30f..79f6fc4da1b9 100644 --- a/core/java/android/service/notification/NotificationRankingUpdate.java +++ b/core/java/android/service/notification/NotificationRankingUpdate.java @@ -26,17 +26,15 @@ public class NotificationRankingUpdate implements Parcelable { // TODO: Support incremental updates. private final String[] mKeys; private final String[] mInterceptedKeys; - private final int mFirstAmbientIndex; private final Bundle mVisibilityOverrides; private final Bundle mSuppressedVisualEffects; private final int[] mImportance; private final Bundle mImportanceExplanation; public NotificationRankingUpdate(String[] keys, String[] interceptedKeys, - Bundle visibilityOverrides, int firstAmbientIndex, Bundle suppressedVisualEffects, + Bundle visibilityOverrides, Bundle suppressedVisualEffects, int[] importance, Bundle explanation) { mKeys = keys; - mFirstAmbientIndex = firstAmbientIndex; mInterceptedKeys = interceptedKeys; mVisibilityOverrides = visibilityOverrides; mSuppressedVisualEffects = suppressedVisualEffects; @@ -46,7 +44,6 @@ public class NotificationRankingUpdate implements Parcelable { public NotificationRankingUpdate(Parcel in) { mKeys = in.readStringArray(); - mFirstAmbientIndex = in.readInt(); mInterceptedKeys = in.readStringArray(); mVisibilityOverrides = in.readBundle(); mSuppressedVisualEffects = in.readBundle(); @@ -63,7 +60,6 @@ public class NotificationRankingUpdate implements Parcelable { @Override public void writeToParcel(Parcel out, int flags) { out.writeStringArray(mKeys); - out.writeInt(mFirstAmbientIndex); out.writeStringArray(mInterceptedKeys); out.writeBundle(mVisibilityOverrides); out.writeBundle(mSuppressedVisualEffects); @@ -86,10 +82,6 @@ public class NotificationRankingUpdate implements Parcelable { return mKeys; } - public int getFirstAmbientIndex() { - return mFirstAmbientIndex; - } - public String[] getInterceptedKeys() { return mInterceptedKeys; } diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl index 75da82fc43c0..9991d416bb5a 100644 --- a/core/java/android/service/quicksettings/IQSService.aidl +++ b/core/java/android/service/quicksettings/IQSService.aidl @@ -16,6 +16,7 @@ package android.service.quicksettings; import android.content.ComponentName; +import android.graphics.drawable.Icon; import android.service.quicksettings.Tile; /** @@ -23,6 +24,8 @@ import android.service.quicksettings.Tile; */ interface IQSService { void updateQsTile(in Tile tile); + void updateStatusIcon(in Tile tile, in Icon icon, + String contentDescription); void onShowDialog(in Tile tile); void setTileMode(in ComponentName component, int mode); } diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java index 1e134c7efaba..6b1219335cb8 100644 --- a/core/java/android/service/quicksettings/TileService.java +++ b/core/java/android/service/quicksettings/TileService.java @@ -16,11 +16,13 @@ package android.service.quicksettings; import android.Manifest; +import android.annotation.SystemApi; import android.app.Dialog; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.graphics.drawable.Icon; import android.os.Handler; import android.os.IBinder; import android.os.Looper; @@ -172,6 +174,26 @@ public class TileService extends Service { } /** + * Sets an icon to be shown in the status bar. + * <p> + * The icon will be displayed before all other icons. Can only be called between + * {@link #onStartListening} and {@link #onStopListening}. Can only be called by system apps. + * + * @param icon The icon to be displayed, null to hide + * @param contentDescription Content description of the icon to be displayed + * @hide + */ + @SystemApi + public final void setStatusIcon(Icon icon, String contentDescription) { + if (mService != null) { + try { + mService.updateStatusIcon(mTile, icon, contentDescription); + } catch (RemoteException e) { + } + } + } + + /** * Used to show a dialog. * * This will collapse the Quick Settings panel and show the dialog. @@ -279,6 +301,10 @@ public class TileService extends Service { } break; case MSG_TILE_REMOVED: + if (mListening) { + mListening = false; + TileService.this.onStopListening(); + } TileService.this.onTileRemoved(); break; case MSG_STOP_LISTENING: diff --git a/core/java/android/text/Editable.java b/core/java/android/text/Editable.java index a284a0005918..b3f2c2a5c447 100644 --- a/core/java/android/text/Editable.java +++ b/core/java/android/text/Editable.java @@ -40,10 +40,14 @@ extends CharSequence, GetChars, Spannable, Appendable * is Spanned, the spans from it are preserved into the Editable. * Existing spans within the Editable that entirely cover the replaced * range are retained, but any that were strictly within the range - * that was replaced are removed. As a special case, the cursor - * position is preserved even when the entire range where it is - * located is replaced. + * that was replaced are removed. If the <code>source</code> contains a span + * with {@link Spanned#SPAN_PARAGRAPH} flag, and it does not satisfy the + * paragraph boundary constraint, it is not retained. As a special case, the + * cursor position is preserved even when the entire range where it is located + * is replaced. * @return a reference to this object. + * + * @see Spanned#SPAN_PARAGRAPH */ public Editable replace(int st, int en, CharSequence source, int start, int end); diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java index 40315add603d..42672384f316 100644 --- a/core/java/android/text/SpannableStringBuilder.java +++ b/core/java/android/text/SpannableStringBuilder.java @@ -421,8 +421,17 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable // Add span only if this object is not yet used as a span in this string if (getSpanStart(spans[i]) < 0) { - setSpan(false, spans[i], st - csStart + start, en - csStart + start, - sp.getSpanFlags(spans[i]) | SPAN_ADDED); + int copySpanStart = st - csStart + start; + int copySpanEnd = en - csStart + start; + int copySpanFlags = sp.getSpanFlags(spans[i]) | SPAN_ADDED; + + int flagsStart = (copySpanFlags & START_MASK) >> START_SHIFT; + int flagsEnd = copySpanFlags & END_MASK; + + if(!isInvalidParagraphStart(copySpanStart, flagsStart) && + !isInvalidParagraphEnd(copySpanEnd, flagsEnd)) { + setSpan(false, spans[i], copySpanStart, copySpanEnd, copySpanFlags); + } } } restoreInvariants(); @@ -666,23 +675,13 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable checkRange("setSpan", start, end); int flagsStart = (flags & START_MASK) >> START_SHIFT; - if (flagsStart == PARAGRAPH) { - if (start != 0 && start != length()) { - char c = charAt(start - 1); - - if (c != '\n') - throw new RuntimeException("PARAGRAPH span must start at paragraph boundary"); - } + if(isInvalidParagraphStart(start, flagsStart)) { + throw new RuntimeException("PARAGRAPH span must start at paragraph boundary"); } int flagsEnd = flags & END_MASK; - if (flagsEnd == PARAGRAPH) { - if (end != 0 && end != length()) { - char c = charAt(end - 1); - - if (c != '\n') - throw new RuntimeException("PARAGRAPH span must end at paragraph boundary"); - } + if(isInvalidParagraphEnd(end, flagsEnd)) { + throw new RuntimeException("PARAGRAPH span must end at paragraph boundary"); } // 0-length Spanned.SPAN_EXCLUSIVE_EXCLUSIVE @@ -761,6 +760,28 @@ public class SpannableStringBuilder implements CharSequence, GetChars, Spannable } } + private final boolean isInvalidParagraphStart(int start, int flagsStart) { + if (flagsStart == PARAGRAPH) { + if (start != 0 && start != length()) { + char c = charAt(start - 1); + + if (c != '\n') return true; + } + } + return false; + } + + private final boolean isInvalidParagraphEnd(int end, int flagsEnd) { + if (flagsEnd == PARAGRAPH) { + if (end != 0 && end != length()) { + char c = charAt(end - 1); + + if (c != '\n') return true; + } + } + return false; + } + /** * Remove the specified markup object from the buffer. */ diff --git a/core/java/android/text/Spanned.java b/core/java/android/text/Spanned.java index a785d1b7d2c7..a0d54c26c6d9 100644 --- a/core/java/android/text/Spanned.java +++ b/core/java/android/text/Spanned.java @@ -81,7 +81,9 @@ extends CharSequence * immediately after a \n character, and if the \n * that anchors it is deleted, the endpoint is pulled to the * next \n that follows in the buffer (or to the end of - * the buffer). + * the buffer). If a span with SPAN_PARAGRAPH flag is pasted + * into another text and the paragraph boundary constraint + * is not satisfied, the span is discarded. */ public static final int SPAN_PARAGRAPH = 0x33; diff --git a/core/java/android/text/method/Touch.java b/core/java/android/text/method/Touch.java index d9068dc74a2c..44811cb3ef8b 100644 --- a/core/java/android/text/method/Touch.java +++ b/core/java/android/text/method/Touch.java @@ -150,6 +150,7 @@ public class Touch { ds[0].mX = event.getX(); ds[0].mY = event.getY(); + int nx = widget.getScrollX() + (int) dx; int ny = widget.getScrollY() + (int) dy; int padding = widget.getTotalPaddingTop() + widget.getTotalPaddingBottom(); @@ -161,6 +162,8 @@ public class Touch { int oldX = widget.getScrollX(); int oldY = widget.getScrollY(); + scrollTo(widget, layout, nx, ny); + // If we actually scrolled, then cancel the up action. if (oldX != widget.getScrollX() || oldY != widget.getScrollY()) { widget.cancelLongPress(); diff --git a/core/java/android/text/util/Linkify.java b/core/java/android/text/util/Linkify.java index c1192776ed4f..fbd992466f5f 100644 --- a/core/java/android/text/util/Linkify.java +++ b/core/java/android/text/util/Linkify.java @@ -218,7 +218,7 @@ public class Linkify { ArrayList<LinkSpec> links = new ArrayList<LinkSpec>(); if ((mask & WEB_URLS) != 0) { - gatherLinks(links, text, Patterns.WEB_URL, + gatherLinks(links, text, Patterns.AUTOLINK_WEB_URL, new String[] { "http://", "https://", "rtsp://" }, sUrlMatchFilter, null); } diff --git a/core/java/android/util/Patterns.java b/core/java/android/util/Patterns.java index 2cc91b9dfe97..9f2bcfd3a136 100644 --- a/core/java/android/util/Patterns.java +++ b/core/java/android/util/Patterns.java @@ -109,11 +109,137 @@ public class Patterns { + "|z[amw]))"; /** - * Good characters for Internationalized Resource Identifiers (IRI). - * This comprises most common used Unicode characters allowed in IRI - * as detailed in RFC 3987. - * Specifically, those two byte Unicode characters are not included. + * Regular expression to match all IANA top-level domains. + * + * List accurate as of 2015/11/24. List taken from: + * http://data.iana.org/TLD/tlds-alpha-by-domain.txt + * This pattern is auto-generated by frameworks/ex/common/tools/make-iana-tld-pattern.py + * + * @hide */ + static final String IANA_TOP_LEVEL_DOMAINS = + "(?:" + + "(?:aaa|aarp|abb|abbott|abogado|academy|accenture|accountant|accountants|aco|active" + + "|actor|ads|adult|aeg|aero|afl|agency|aig|airforce|airtel|allfinanz|alsace|amica|amsterdam" + + "|android|apartments|app|apple|aquarelle|aramco|archi|army|arpa|arte|asia|associates" + + "|attorney|auction|audio|auto|autos|axa|azure|a[cdefgilmoqrstuwxz])" + + "|(?:band|bank|bar|barcelona|barclaycard|barclays|bargains|bauhaus|bayern|bbc|bbva" + + "|bcn|beats|beer|bentley|berlin|best|bet|bharti|bible|bid|bike|bing|bingo|bio|biz|black" + + "|blackfriday|bloomberg|blue|bms|bmw|bnl|bnpparibas|boats|bom|bond|boo|boots|boutique" + + "|bradesco|bridgestone|broadway|broker|brother|brussels|budapest|build|builders|business" + + "|buzz|bzh|b[abdefghijmnorstvwyz])" + + "|(?:cab|cafe|cal|camera|camp|cancerresearch|canon|capetown|capital|car|caravan|cards" + + "|care|career|careers|cars|cartier|casa|cash|casino|cat|catering|cba|cbn|ceb|center|ceo" + + "|cern|cfa|cfd|chanel|channel|chat|cheap|chloe|christmas|chrome|church|cipriani|cisco" + + "|citic|city|cityeats|claims|cleaning|click|clinic|clothing|cloud|club|clubmed|coach" + + "|codes|coffee|college|cologne|com|commbank|community|company|computer|comsec|condos" + + "|construction|consulting|contractors|cooking|cool|coop|corsica|country|coupons|courses" + + "|credit|creditcard|creditunion|cricket|crown|crs|cruises|csc|cuisinella|cymru|cyou|c[acdfghiklmnoruvwxyz])" + + "|(?:dabur|dad|dance|date|dating|datsun|day|dclk|deals|degree|delivery|dell|delta" + + "|democrat|dental|dentist|desi|design|dev|diamonds|diet|digital|direct|directory|discount" + + "|dnp|docs|dog|doha|domains|doosan|download|drive|durban|dvag|d[ejkmoz])" + + "|(?:earth|eat|edu|education|email|emerck|energy|engineer|engineering|enterprises" + + "|epson|equipment|erni|esq|estate|eurovision|eus|events|everbank|exchange|expert|exposed" + + "|express|e[cegrstu])" + + "|(?:fage|fail|fairwinds|faith|family|fan|fans|farm|fashion|feedback|ferrero|film" + + "|final|finance|financial|firmdale|fish|fishing|fit|fitness|flights|florist|flowers|flsmidth" + + "|fly|foo|football|forex|forsale|forum|foundation|frl|frogans|fund|furniture|futbol|fyi" + + "|f[ijkmor])" + + "|(?:gal|gallery|game|garden|gbiz|gdn|gea|gent|genting|ggee|gift|gifts|gives|giving" + + "|glass|gle|global|globo|gmail|gmo|gmx|gold|goldpoint|golf|goo|goog|google|gop|gov|grainger" + + "|graphics|gratis|green|gripe|group|gucci|guge|guide|guitars|guru|g[abdefghilmnpqrstuwy])" + + "|(?:hamburg|hangout|haus|healthcare|help|here|hermes|hiphop|hitachi|hiv|hockey|holdings" + + "|holiday|homedepot|homes|honda|horse|host|hosting|hoteles|hotmail|house|how|hsbc|hyundai" + + "|h[kmnrtu])" + + "|(?:ibm|icbc|ice|icu|ifm|iinet|immo|immobilien|industries|infiniti|info|ing|ink|institute" + + "|insure|int|international|investments|ipiranga|irish|ist|istanbul|itau|iwc|i[delmnoqrst])" + + "|(?:jaguar|java|jcb|jetzt|jewelry|jlc|jll|jobs|joburg|jprs|juegos|j[emop])" + + "|(?:kaufen|kddi|kia|kim|kinder|kitchen|kiwi|koeln|komatsu|krd|kred|kyoto|k[eghimnprwyz])" + + "|(?:lacaixa|lancaster|land|landrover|lasalle|lat|latrobe|law|lawyer|lds|lease|leclerc" + + "|legal|lexus|lgbt|liaison|lidl|life|lifestyle|lighting|limited|limo|linde|link|live" + + "|lixil|loan|loans|lol|london|lotte|lotto|love|ltd|ltda|lupin|luxe|luxury|l[abcikrstuvy])" + + "|(?:madrid|maif|maison|man|management|mango|market|marketing|markets|marriott|mba" + + "|media|meet|melbourne|meme|memorial|men|menu|meo|miami|microsoft|mil|mini|mma|mobi|moda" + + "|moe|moi|mom|monash|money|montblanc|mormon|mortgage|moscow|motorcycles|mov|movie|movistar" + + "|mtn|mtpc|mtr|museum|mutuelle|m[acdeghklmnopqrstuvwxyz])" + + "|(?:nadex|nagoya|name|navy|nec|net|netbank|network|neustar|new|news|nexus|ngo|nhk" + + "|nico|ninja|nissan|nokia|nra|nrw|ntt|nyc|n[acefgilopruz])" + + "|(?:obi|office|okinawa|omega|one|ong|onl|online|ooo|oracle|orange|org|organic|osaka" + + "|otsuka|ovh|om)" + + "|(?:page|panerai|paris|partners|parts|party|pet|pharmacy|philips|photo|photography" + + "|photos|physio|piaget|pics|pictet|pictures|ping|pink|pizza|place|play|playstation|plumbing" + + "|plus|pohl|poker|porn|post|praxi|press|pro|prod|productions|prof|properties|property" + + "|protection|pub|p[aefghklmnrstwy])" + + "|(?:qpon|quebec|qa)" + + "|(?:racing|realtor|realty|recipes|red|redstone|rehab|reise|reisen|reit|ren|rent|rentals" + + "|repair|report|republican|rest|restaurant|review|reviews|rich|ricoh|rio|rip|rocher|rocks" + + "|rodeo|rsvp|ruhr|run|rwe|ryukyu|r[eosuw])" + + "|(?:saarland|sakura|sale|samsung|sandvik|sandvikcoromant|sanofi|sap|sapo|sarl|saxo" + + "|sbs|sca|scb|schmidt|scholarships|school|schule|schwarz|science|scor|scot|seat|security" + + "|seek|sener|services|seven|sew|sex|sexy|shiksha|shoes|show|shriram|singles|site|ski" + + "|sky|skype|sncf|soccer|social|software|sohu|solar|solutions|sony|soy|space|spiegel|spreadbetting" + + "|srl|stada|starhub|statoil|stc|stcgroup|stockholm|studio|study|style|sucks|supplies" + + "|supply|support|surf|surgery|suzuki|swatch|swiss|sydney|systems|s[abcdeghijklmnortuvxyz])" + + "|(?:tab|taipei|tatamotors|tatar|tattoo|tax|taxi|team|tech|technology|tel|telefonica" + + "|temasek|tennis|thd|theater|theatre|tickets|tienda|tips|tires|tirol|today|tokyo|tools" + + "|top|toray|toshiba|tours|town|toyota|toys|trade|trading|training|travel|trust|tui|t[cdfghjklmnortvwz])" + + "|(?:ubs|university|uno|uol|u[agksyz])" + + "|(?:vacations|vana|vegas|ventures|versicherung|vet|viajes|video|villas|vin|virgin" + + "|vision|vista|vistaprint|viva|vlaanderen|vodka|vote|voting|voto|voyage|v[aceginu])" + + "|(?:wales|walter|wang|watch|webcam|website|wed|wedding|weir|whoswho|wien|wiki|williamhill" + + "|win|windows|wine|wme|work|works|world|wtc|wtf|w[fs])" + + "|(?:\u03b5\u03bb|\u0431\u0435\u043b|\u0434\u0435\u0442\u0438|\u043a\u043e\u043c|\u043c\u043a\u0434" + + "|\u043c\u043e\u043d|\u043c\u043e\u0441\u043a\u0432\u0430|\u043e\u043d\u043b\u0430\u0439\u043d" + + "|\u043e\u0440\u0433|\u0440\u0443\u0441|\u0440\u0444|\u0441\u0430\u0439\u0442|\u0441\u0440\u0431" + + "|\u0443\u043a\u0440|\u049b\u0430\u0437|\u0570\u0561\u0575|\u05e7\u05d5\u05dd|\u0627\u0631\u0627\u0645\u0643\u0648" + + "|\u0627\u0644\u0627\u0631\u062f\u0646|\u0627\u0644\u062c\u0632\u0627\u0626\u0631|\u0627\u0644\u0633\u0639\u0648\u062f\u064a\u0629" + + "|\u0627\u0644\u0645\u063a\u0631\u0628|\u0627\u0645\u0627\u0631\u0627\u062a|\u0627\u06cc\u0631\u0627\u0646" + + "|\u0628\u0627\u0632\u0627\u0631|\u0628\u06be\u0627\u0631\u062a|\u062a\u0648\u0646\u0633" + + "|\u0633\u0648\u062f\u0627\u0646|\u0633\u0648\u0631\u064a\u0629|\u0634\u0628\u0643\u0629" + + "|\u0639\u0631\u0627\u0642|\u0639\u0645\u0627\u0646|\u0641\u0644\u0633\u0637\u064a\u0646" + + "|\u0642\u0637\u0631|\u0643\u0648\u0645|\u0645\u0635\u0631|\u0645\u0644\u064a\u0633\u064a\u0627" + + "|\u0645\u0648\u0642\u0639|\u0915\u0949\u092e|\u0928\u0947\u091f|\u092d\u093e\u0930\u0924" + + "|\u0938\u0902\u0917\u0920\u0928|\u09ad\u09be\u09b0\u09a4|\u0a2d\u0a3e\u0a30\u0a24|\u0aad\u0abe\u0ab0\u0aa4" + + "|\u0b87\u0ba8\u0bcd\u0ba4\u0bbf\u0baf\u0bbe|\u0b87\u0bb2\u0b99\u0bcd\u0b95\u0bc8|\u0b9a\u0bbf\u0b99\u0bcd\u0b95\u0baa\u0bcd\u0baa\u0bc2\u0bb0\u0bcd" + + "|\u0c2d\u0c3e\u0c30\u0c24\u0c4d|\u0dbd\u0d82\u0d9a\u0dcf|\u0e04\u0e2d\u0e21|\u0e44\u0e17\u0e22" + + "|\u10d2\u10d4|\u307f\u3093\u306a|\u30b0\u30fc\u30b0\u30eb|\u30b3\u30e0|\u4e16\u754c" + + "|\u4e2d\u4fe1|\u4e2d\u56fd|\u4e2d\u570b|\u4e2d\u6587\u7f51|\u4f01\u4e1a|\u4f5b\u5c71" + + "|\u4fe1\u606f|\u5065\u5eb7|\u516b\u5366|\u516c\u53f8|\u516c\u76ca|\u53f0\u6e7e|\u53f0\u7063" + + "|\u5546\u57ce|\u5546\u5e97|\u5546\u6807|\u5728\u7ebf|\u5927\u62ff|\u5a31\u4e50|\u5de5\u884c" + + "|\u5e7f\u4e1c|\u6148\u5584|\u6211\u7231\u4f60|\u624b\u673a|\u653f\u52a1|\u653f\u5e9c" + + "|\u65b0\u52a0\u5761|\u65b0\u95fb|\u65f6\u5c1a|\u673a\u6784|\u6de1\u9a6c\u9521|\u6e38\u620f" + + "|\u70b9\u770b|\u79fb\u52a8|\u7ec4\u7ec7\u673a\u6784|\u7f51\u5740|\u7f51\u5e97|\u7f51\u7edc" + + "|\u8c37\u6b4c|\u96c6\u56e2|\u98de\u5229\u6d66|\u9910\u5385|\u9999\u6e2f|\ub2f7\ub137" + + "|\ub2f7\ucef4|\uc0bc\uc131|\ud55c\uad6d|xbox" + + "|xerox|xin|xn\\-\\-11b4c3d|xn\\-\\-1qqw23a|xn\\-\\-30rr7y|xn\\-\\-3bst00m|xn\\-\\-3ds443g" + + "|xn\\-\\-3e0b707e|xn\\-\\-3pxu8k|xn\\-\\-42c2d9a|xn\\-\\-45brj9c|xn\\-\\-45q11c|xn\\-\\-4gbrim" + + "|xn\\-\\-55qw42g|xn\\-\\-55qx5d|xn\\-\\-6frz82g|xn\\-\\-6qq986b3xl|xn\\-\\-80adxhks" + + "|xn\\-\\-80ao21a|xn\\-\\-80asehdb|xn\\-\\-80aswg|xn\\-\\-90a3ac|xn\\-\\-90ais|xn\\-\\-9dbq2a" + + "|xn\\-\\-9et52u|xn\\-\\-b4w605ferd|xn\\-\\-c1avg|xn\\-\\-c2br7g|xn\\-\\-cg4bki|xn\\-\\-clchc0ea0b2g2a9gcd" + + "|xn\\-\\-czr694b|xn\\-\\-czrs0t|xn\\-\\-czru2d|xn\\-\\-d1acj3b|xn\\-\\-d1alf|xn\\-\\-efvy88h" + + "|xn\\-\\-estv75g|xn\\-\\-fhbei|xn\\-\\-fiq228c5hs|xn\\-\\-fiq64b|xn\\-\\-fiqs8s|xn\\-\\-fiqz9s" + + "|xn\\-\\-fjq720a|xn\\-\\-flw351e|xn\\-\\-fpcrj9c3d|xn\\-\\-fzc2c9e2c|xn\\-\\-gecrj9c" + + "|xn\\-\\-h2brj9c|xn\\-\\-hxt814e|xn\\-\\-i1b6b1a6a2e|xn\\-\\-imr513n|xn\\-\\-io0a7i" + + "|xn\\-\\-j1aef|xn\\-\\-j1amh|xn\\-\\-j6w193g|xn\\-\\-kcrx77d1x4a|xn\\-\\-kprw13d|xn\\-\\-kpry57d" + + "|xn\\-\\-kput3i|xn\\-\\-l1acc|xn\\-\\-lgbbat1ad8j|xn\\-\\-mgb9awbf|xn\\-\\-mgba3a3ejt" + + "|xn\\-\\-mgba3a4f16a|xn\\-\\-mgbaam7a8h|xn\\-\\-mgbab2bd|xn\\-\\-mgbayh7gpa|xn\\-\\-mgbbh1a71e" + + "|xn\\-\\-mgbc0a9azcg|xn\\-\\-mgberp4a5d4ar|xn\\-\\-mgbpl2fh|xn\\-\\-mgbtx2b|xn\\-\\-mgbx4cd0ab" + + "|xn\\-\\-mk1bu44c|xn\\-\\-mxtq1m|xn\\-\\-ngbc5azd|xn\\-\\-node|xn\\-\\-nqv7f|xn\\-\\-nqv7fs00ema" + + "|xn\\-\\-nyqy26a|xn\\-\\-o3cw4h|xn\\-\\-ogbpf8fl|xn\\-\\-p1acf|xn\\-\\-p1ai|xn\\-\\-pgbs0dh" + + "|xn\\-\\-pssy2u|xn\\-\\-q9jyb4c|xn\\-\\-qcka1pmc|xn\\-\\-qxam|xn\\-\\-rhqv96g|xn\\-\\-s9brj9c" + + "|xn\\-\\-ses554g|xn\\-\\-t60b56a|xn\\-\\-tckwe|xn\\-\\-unup4y|xn\\-\\-vermgensberater\\-ctb" + + "|xn\\-\\-vermgensberatung\\-pwb|xn\\-\\-vhquv|xn\\-\\-vuq861b|xn\\-\\-wgbh1c|xn\\-\\-wgbl6a" + + "|xn\\-\\-xhq521b|xn\\-\\-xkc2al3hye2a|xn\\-\\-xkc2dl3a5ee0h|xn\\-\\-y9a3aq|xn\\-\\-yfro4i67o" + + "|xn\\-\\-ygbi2ammx|xn\\-\\-zfr164b|xperia|xxx|xyz)" + + "|(?:yachts|yamaxun|yandex|yodobashi|yoga|yokohama|youtube|y[et])" + + "|(?:zara|zip|zone|zuerich|z[amw]))"; + + /** + * Kept for backward compatibility reasons. + * + * @deprecated Deprecated since it does not include all IRI characters defined in RFC 3987 + */ + @Deprecated public static final String GOOD_IRI_CHAR = "a-zA-Z0-9\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; @@ -125,35 +251,148 @@ public class Patterns { + "|[1-9][0-9]|[0-9]))"); /** + * Valid UCS characters defined in RFC 3987. + */ + private static final String UCS_CHAR = + "\u00A0-\uD7FF" + + "\uF900-\uFDCF" + + "\uFDF0-\uFFEF" + + "\uD800\uDC00-\uD83F\uDFFD" + + "\uD840\uDC00-\uD87F\uDFFD" + + "\uD880\uDC00-\uD8BF\uDFFD" + + "\uD8C0\uDC00-\uD8FF\uDFFD" + + "\uD900\uDC00-\uD93F\uDFFD" + + "\uD940\uDC00-\uD97F\uDFFD" + + "\uD980\uDC00-\uD9BF\uDFFD" + + "\uD9C0\uDC00-\uD9FF\uDFFD" + + "\uDA00\uDC00-\uDA3F\uDFFD" + + "\uDA40\uDC00-\uDA7F\uDFFD" + + "\uDA80\uDC00-\uDABF\uDFFD" + + "\uDAC0\uDC00-\uDAFF\uDFFD" + + "\uDB00\uDC00-\uDB3F\uDFFD" + + "\uDB44\uDC00-\uDB7F\uDFFD"; + + /** + * Valid characters for IRI label defined in RFC 3987. + */ + private static final String LABEL_CHAR = "a-zA-Z0-9" + UCS_CHAR; + + /** + * Valid characters for IRI TLD defined in RFC 3987. + */ + private static final String TLD_CHAR = "a-zA-Z" + UCS_CHAR; + + /** * RFC 1035 Section 2.3.4 limits the labels to a maximum 63 octets. */ - private static final String IRI - = "[" + GOOD_IRI_CHAR + "]([" + GOOD_IRI_CHAR + "\\-]{0,61}[" + GOOD_IRI_CHAR + "]){0,1}"; + private static final String IRI_LABEL = + "[" + LABEL_CHAR + "](?:[" + LABEL_CHAR + "\\-]{0,61}[" + LABEL_CHAR + "]){0,1}"; - private static final String GOOD_GTLD_CHAR = - "a-zA-Z\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF"; - private static final String GTLD = "[" + GOOD_GTLD_CHAR + "]{2,63}"; - private static final String HOST_NAME = "(" + IRI + "\\.)+" + GTLD; + /** + * RFC 3492 references RFC 1034 and limits Punycode algorithm output to 63 characters. + */ + private static final String PUNYCODE_TLD = "xn\\-\\-[\\w\\-]{0,58}\\w"; + + private static final String TLD = "(" + PUNYCODE_TLD + "|" + "[" + TLD_CHAR + "]{2,63}" +")"; + + private static final String HOST_NAME = "(" + IRI_LABEL + "\\.)+" + TLD; public static final Pattern DOMAIN_NAME = Pattern.compile("(" + HOST_NAME + "|" + IP_ADDRESS + ")"); + private static final String PROTOCOL = "(?i:http|https|rtsp):\\/\\/"; + + /* A word boundary or end of input. This is to stop foo.sure from matching as foo.su */ + private static final String WORD_BOUNDARY = "(?:\\b|$|^)"; + + private static final String USER_INFO = "(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" + + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" + + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@"; + + private static final String PORT_NUMBER = "\\:\\d{1,5}"; + + private static final String PATH_AND_QUERY = "\\/(?:(?:[" + LABEL_CHAR + + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus optional query params + + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*"; + /** * Regular expression pattern to match most part of RFC 3987 - * Internationalized URLs, aka IRIs. Commonly used Unicode characters are - * added. - */ - public static final Pattern WEB_URL = Pattern.compile( - "((?:(http|https|Http|Https|rtsp|Rtsp):\\/\\/(?:(?:[a-zA-Z0-9\\$\\-\\_\\.\\+\\!\\*\\'\\(\\)" - + "\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,64}(?:\\:(?:[a-zA-Z0-9\\$\\-\\_" - + "\\.\\+\\!\\*\\'\\(\\)\\,\\;\\?\\&\\=]|(?:\\%[a-fA-F0-9]{2})){1,25})?\\@)?)?" - + "(?:" + DOMAIN_NAME + ")" - + "(?:\\:\\d{1,5})?)" // plus option port number - + "(\\/(?:(?:[" + GOOD_IRI_CHAR + "\\;\\/\\?\\:\\@\\&\\=\\#\\~" // plus option query params - + "\\-\\.\\+\\!\\*\\'\\(\\)\\,\\_])|(?:\\%[a-fA-F0-9]{2}))*)?" - + "(?:\\b|$)"); // and finally, a word boundary or end of - // input. This is to stop foo.sure from - // matching as foo.su + * Internationalized URLs, aka IRIs. + */ + public static final Pattern WEB_URL = Pattern.compile("(" + + "(" + + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")?" + + "(?:" + DOMAIN_NAME + ")" + + "(?:" + PORT_NUMBER + ")?" + + ")" + + "(" + PATH_AND_QUERY + ")?" + + WORD_BOUNDARY + + ")"); + + /** + * Regular expression that matches known TLDs and punycode TLDs + */ + private static final String STRICT_TLD = "(?:" + + IANA_TOP_LEVEL_DOMAINS + "|" + PUNYCODE_TLD + ")"; + + /** + * Regular expression that matches host names using {@link #STRICT_TLD} + */ + private static final String STRICT_HOST_NAME = "(?:(?:" + IRI_LABEL + "\\.)+" + + STRICT_TLD + ")"; + + /** + * Regular expression that matches domain names using either {@link #STRICT_HOST_NAME} or + * {@link #IP_ADDRESS} + */ + private static final Pattern STRICT_DOMAIN_NAME + = Pattern.compile("(?:" + STRICT_HOST_NAME + "|" + IP_ADDRESS + ")"); + + /** + * Regular expression that matches domain names without a TLD + */ + private static final String RELAXED_DOMAIN_NAME = + "(?:" + "(?:" + IRI_LABEL + "(?:\\.(?=\\S))" +"?)+" + "|" + IP_ADDRESS + ")"; + + /** + * Regular expression to match strings that do not start with a supported protocol. The TLDs + * are expected to be one of the known TLDs. + */ + private static final String WEB_URL_WITHOUT_PROTOCOL = "(" + + WORD_BOUNDARY + + "(?<!:\\/\\/)" + + "(" + + "(?:" + STRICT_DOMAIN_NAME + ")" + + "(?:" + PORT_NUMBER + ")?" + + ")" + + "(?:" + PATH_AND_QUERY + ")?" + + WORD_BOUNDARY + + ")"; + + /** + * Regular expression to match strings that start with a supported protocol. Rules for domain + * names and TLDs are more relaxed. TLDs are optional. + */ + private static final String WEB_URL_WITH_PROTOCOL = "(" + + WORD_BOUNDARY + + "(?:" + + "(?:" + PROTOCOL + "(?:" + USER_INFO + ")?" + ")" + + "(?:" + RELAXED_DOMAIN_NAME + ")?" + + "(?:" + PORT_NUMBER + ")?" + + ")" + + "(?:" + PATH_AND_QUERY + ")?" + + WORD_BOUNDARY + + ")"; + + /** + * Regular expression pattern to match IRIs. If a string starts with http(s):// the expression + * tries to match the URL structure with a relaxed rule for TLDs. If the string does not start + * with http(s):// the TLDs are expected to be one of the known TLDs. + * + * @hide + */ + public static final Pattern AUTOLINK_WEB_URL = Pattern.compile( + "(" + WEB_URL_WITH_PROTOCOL + "|" + WEB_URL_WITHOUT_PROTOCOL + ")"); public static final Pattern EMAIL_ADDRESS = Pattern.compile( diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java index 7a544b8f0bb3..a0f51425ab1e 100644 --- a/core/java/android/view/MotionEvent.java +++ b/core/java/android/view/MotionEvent.java @@ -973,6 +973,7 @@ public final class MotionEvent extends InputEvent implements Parcelable { * </p> * * @see #getAxisValue(int, int) + * {@hide} */ public static final int AXIS_SCROLL = 26; diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java index 6b60be9c91b5..1be4810779da 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -297,7 +297,7 @@ public class TextureView extends View { @Override public void setForeground(Drawable foreground) { - if (foreground != null) { + if (foreground != null && !sTextureViewIgnoresDrawableSetters) { throw new UnsupportedOperationException( "TextureView doesn't support displaying a foreground drawable"); } @@ -305,7 +305,7 @@ public class TextureView extends View { @Override public void setBackgroundDrawable(Drawable background) { - if (background != null) { + if (background != null && !sTextureViewIgnoresDrawableSetters) { throw new UnsupportedOperationException( "TextureView doesn't support displaying a background drawable"); } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 537f887305ee..68f1ac3c1108 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -812,6 +812,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private static boolean sLayoutParamsAlwaysChanged = false; /** + * Allow setForeground/setBackground to be called (and ignored) on a textureview, + * without throwing + */ + static boolean sTextureViewIgnoresDrawableSetters = false; + + /** * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when * calling setFlags. */ @@ -3586,6 +3592,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback, private int[] mDrawableState = null; + /** Whether draw() is currently being called. */ + private boolean mInDraw = false; + ViewOutlineProvider mOutlineProvider = ViewOutlineProvider.BACKGROUND; /** @@ -3984,6 +3993,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // work. Partial layout breaks this assumption. sLayoutParamsAlwaysChanged = targetSdkVersion <= M; + // Prior to N, TextureView would silently ignore calls to setBackground/setForeground. + // On N+, we throw, but that breaks compatibility with apps that use these methods. + sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M; + sCompatibilityDone = true; } } @@ -16460,6 +16473,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @CallSuper public void draw(Canvas canvas) { + mInDraw = true; + final int privateFlags = mPrivateFlags; final boolean dirtyOpaque = (privateFlags & PFLAG_DIRTY_MASK) == PFLAG_DIRTY_OPAQUE && (mAttachInfo == null || !mAttachInfo.mIgnoreDirtyState); @@ -16504,6 +16519,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, onDrawForeground(canvas); // we're done... + mInDraw = false; return; } @@ -16651,6 +16667,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // Step 6, draw decorations (foreground, scrollbars) onDrawForeground(canvas); + + mInDraw = false; } /** @@ -17095,7 +17113,8 @@ public class View implements Drawable.Callback, KeyEvent.Callback, */ @Override public void invalidateDrawable(@NonNull Drawable drawable) { - if (verifyDrawable(drawable)) { + // Don't invalidate if a drawable changes during drawing. + if (verifyDrawable(drawable) && !mInDraw) { final Rect dirty = drawable.getDirtyBounds(); final int scrollX = mScrollX; final int scrollY = mScrollY; diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 1c9f3b403ef8..0fb39516d4d2 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -384,6 +384,8 @@ public final class ViewRootImpl implements ViewParent, int localChanges; } + private String mTag = TAG; + public ViewRootImpl(Context context, Display display) { mContext = context; mWindowSession = WindowManagerGlobal.getWindowSession(); @@ -510,6 +512,7 @@ public final class ViewRootImpl implements ViewParent, mWindowAttributes.packageName = mBasePackageName; } attrs = mWindowAttributes; + setTag(); // Keep track of the actual window flags supplied by the client. mClientWindowLayoutFlags = attrs.flags; @@ -546,7 +549,7 @@ public final class ViewRootImpl implements ViewParent, attrs.backup(); mTranslator.translateWindowLayout(attrs); } - if (DEBUG_LAYOUT) Log.d(TAG, "WindowLayout in setView:" + attrs); + if (DEBUG_LAYOUT) Log.d(mTag, "WindowLayout in setView:" + attrs); if (!compatibilityInfo.supportsScreen()) { attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW; @@ -607,7 +610,7 @@ public final class ViewRootImpl implements ViewParent, mPendingContentInsets.set(mAttachInfo.mContentInsets); mPendingStableInsets.set(mAttachInfo.mStableInsets); mPendingVisibleInsets.set(0, 0, 0, 0); - if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow); + if (DEBUG_LAYOUT) Log.v(mTag, "Added window " + mWindow); if (res < WindowManagerGlobal.ADD_OKAY) { mAttachInfo.mRootView = null; mAdded = false; @@ -701,6 +704,13 @@ public final class ViewRootImpl implements ViewParent, } } + private void setTag() { + final String[] split = mWindowAttributes.getTitle().toString().split("\\."); + if (split.length > 0) { + mTag = TAG + "[" + split[split.length - 1] + "]"; + } + } + /** Whether the window is in local focus mode or not */ private boolean isInLocalFocusMode() { return (mWindowAttributes.flags & WindowManager.LayoutParams.FLAG_LOCAL_FOCUS_MODE) != 0; @@ -990,7 +1000,7 @@ public final class ViewRootImpl implements ViewParent, @Override public ViewParent invalidateChildInParent(int[] location, Rect dirty) { checkThread(); - if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty); + if (DEBUG_DRAW) Log.v(mTag, "Invalidate child: " + dirty); if (dirty == null) { invalidate(); @@ -1174,7 +1184,7 @@ public final class ViewRootImpl implements ViewParent, private boolean collectViewAttributes() { if (mAttachInfo.mRecomputeGlobalAttributes) { - //Log.i(TAG, "Computing view hierarchy attributes!"); + //Log.i(mTag, "Computing view hierarchy attributes!"); mAttachInfo.mRecomputeGlobalAttributes = false; boolean oldScreenOn = mAttachInfo.mKeepScreenOn; mAttachInfo.mKeepScreenOn = false; @@ -1215,7 +1225,7 @@ public final class ViewRootImpl implements ViewParent, int childHeightMeasureSpec; boolean windowSizeMayChange = false; - if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(TAG, + if (DEBUG_ORIENTATION || DEBUG_LAYOUT) Log.v(mTag, "Measuring " + host + " in display " + desiredWindowWidth + "x" + desiredWindowHeight + "..."); @@ -1231,26 +1241,26 @@ public final class ViewRootImpl implements ViewParent, if (mTmpValue.type == TypedValue.TYPE_DIMENSION) { baseSize = (int)mTmpValue.getDimension(packageMetrics); } - if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": baseSize=" + baseSize); + if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": baseSize=" + baseSize); if (baseSize != 0 && desiredWindowWidth > baseSize) { childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); childHeightMeasureSpec = getRootMeasureSpec(desiredWindowHeight, lp.height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); - if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured (" + if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { goodMeasure = true; } else { // Didn't fit in that size... try expanding a bit. baseSize = (baseSize+desiredWindowWidth)/2; - if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": next baseSize=" + if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": next baseSize=" + baseSize); childWidthMeasureSpec = getRootMeasureSpec(baseSize, lp.width); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); - if (DEBUG_DIALOG) Log.v(TAG, "Window " + mView + ": measured (" + if (DEBUG_DIALOG) Log.v(mTag, "Window " + mView + ": measured (" + host.getMeasuredWidth() + "," + host.getMeasuredHeight() + ")"); if ((host.getMeasuredWidthAndState()&View.MEASURED_STATE_TOO_SMALL) == 0) { - if (DEBUG_DIALOG) Log.v(TAG, "Good!"); + if (DEBUG_DIALOG) Log.v(mTag, "Good!"); goodMeasure = true; } } @@ -1350,8 +1360,8 @@ public final class ViewRootImpl implements ViewParent, int desiredWindowHeight; final int viewVisibility = getHostVisibility(); - boolean viewVisibilityChanged = mViewVisibility != viewVisibility - || mNewSurfaceNeeded; + final boolean viewVisibilityChanged = !mFirst + && (mViewVisibility != viewVisibility || mNewSurfaceNeeded); WindowManager.LayoutParams params = null; if (mWindowAttributesChanged) { @@ -1401,7 +1411,6 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mHasWindowFocus = false; mAttachInfo.mWindowVisibility = viewVisibility; mAttachInfo.mRecomputeGlobalAttributes = false; - viewVisibilityChanged = false; mLastConfiguration.setTo(host.getResources().getConfiguration()); mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility; // Set the layout direction if it has not been set before (inherit is the default) @@ -1411,14 +1420,13 @@ public final class ViewRootImpl implements ViewParent, host.dispatchAttachedToWindow(mAttachInfo, 0); mAttachInfo.mTreeObserver.dispatchOnWindowAttachedChange(true); dispatchApplyInsets(host); - //Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn); + //Log.i(mTag, "Screen on initialized: " + attachInfo.mKeepScreenOn); } else { desiredWindowWidth = frame.width(); desiredWindowHeight = frame.height(); if (desiredWindowWidth != mWidth || desiredWindowHeight != mHeight) { - if (DEBUG_ORIENTATION) Log.v(TAG, - "View " + host + " resized to: " + frame); + if (DEBUG_ORIENTATION) Log.v(mTag, "View " + host + " resized to: " + frame); mFullRedrawNeeded = true; mLayoutRequested = true; windowSizeMayChange = true; @@ -1471,28 +1479,22 @@ public final class ViewRootImpl implements ViewParent, } if (!mPendingVisibleInsets.equals(mAttachInfo.mVisibleInsets)) { mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); - if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: " + if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: " + mAttachInfo.mVisibleInsets); } if (!mPendingOutsets.equals(mAttachInfo.mOutsets)) { insetsChanged = true; } - if (lp.width == ViewGroup.LayoutParams.WRAP_CONTENT - || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) { + if ((lp.width == ViewGroup.LayoutParams.WRAP_CONTENT + || lp.height == ViewGroup.LayoutParams.WRAP_CONTENT) + && (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL + || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD)) { windowSizeMayChange = true; - - if (lp.type == WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL - || lp.type == WindowManager.LayoutParams.TYPE_INPUT_METHOD) { - // NOTE -- system code, won't try to do compat mode. - Point size = new Point(); - mDisplay.getRealSize(size); - desiredWindowWidth = size.x; - desiredWindowHeight = size.y; - } else { - DisplayMetrics packageMetrics = res.getDisplayMetrics(); - desiredWindowWidth = packageMetrics.widthPixels; - desiredWindowHeight = packageMetrics.heightPixels; - } + // NOTE -- system code, won't try to do compat mode. + Point size = new Point(); + mDisplay.getRealSize(size); + desiredWindowWidth = size.x; + desiredWindowHeight = size.y; } } @@ -1616,7 +1618,7 @@ public final class ViewRootImpl implements ViewParent, try { if (DEBUG_LAYOUT) { - Log.i(TAG, "host=w:" + host.getMeasuredWidth() + ", h:" + + Log.i(mTag, "host=w:" + host.getMeasuredWidth() + ", h:" + host.getMeasuredHeight() + ", params=" + params); } @@ -1634,7 +1636,7 @@ public final class ViewRootImpl implements ViewParent, final int surfaceGenerationId = mSurface.getGenerationId(); relayoutResult = relayoutWindow(params, viewVisibility, insetsPending); - if (DEBUG_LAYOUT) Log.v(TAG, "relayout: frame=" + frame.toShortString() + if (DEBUG_LAYOUT) Log.v(mTag, "relayout: frame=" + frame.toShortString() + " overscan=" + mPendingOverscanInsets.toShortString() + " content=" + mPendingContentInsets.toShortString() + " visible=" + mPendingVisibleInsets.toShortString() @@ -1643,7 +1645,7 @@ public final class ViewRootImpl implements ViewParent, + " surface=" + mSurface); if (mPendingConfiguration.seq != 0) { - if (DEBUG_CONFIGURATION) Log.v(TAG, "Visible with new config: " + if (DEBUG_CONFIGURATION) Log.v(mTag, "Visible with new config: " + mPendingConfiguration); updateConfiguration(new Configuration(mPendingConfiguration), !mFirst); mPendingConfiguration.seq = 0; @@ -1662,19 +1664,19 @@ public final class ViewRootImpl implements ViewParent, & WindowManagerGlobal.RELAYOUT_RES_SURFACE_RESIZED) != 0; if (contentInsetsChanged) { mAttachInfo.mContentInsets.set(mPendingContentInsets); - if (DEBUG_LAYOUT) Log.v(TAG, "Content insets changing to: " + if (DEBUG_LAYOUT) Log.v(mTag, "Content insets changing to: " + mAttachInfo.mContentInsets); } if (overscanInsetsChanged) { mAttachInfo.mOverscanInsets.set(mPendingOverscanInsets); - if (DEBUG_LAYOUT) Log.v(TAG, "Overscan insets changing to: " + if (DEBUG_LAYOUT) Log.v(mTag, "Overscan insets changing to: " + mAttachInfo.mOverscanInsets); // Need to relayout with content insets. contentInsetsChanged = true; } if (stableInsetsChanged) { mAttachInfo.mStableInsets.set(mPendingStableInsets); - if (DEBUG_LAYOUT) Log.v(TAG, "Decor insets changing to: " + if (DEBUG_LAYOUT) Log.v(mTag, "Decor insets changing to: " + mAttachInfo.mStableInsets); // Need to relayout with content insets. contentInsetsChanged = true; @@ -1691,7 +1693,7 @@ public final class ViewRootImpl implements ViewParent, } if (visibleInsetsChanged) { mAttachInfo.mVisibleInsets.set(mPendingVisibleInsets); - if (DEBUG_LAYOUT) Log.v(TAG, "Visible insets changing to: " + if (DEBUG_LAYOUT) Log.v(mTag, "Visible insets changing to: " + mAttachInfo.mVisibleInsets); } @@ -1872,7 +1874,7 @@ public final class ViewRootImpl implements ViewParent, int childWidthMeasureSpec = getRootMeasureSpec(mWidth, lp.width); int childHeightMeasureSpec = getRootMeasureSpec(mHeight, lp.height); - if (DEBUG_LAYOUT) Log.v(TAG, "Ooops, something changed! mWidth=" + if (DEBUG_LAYOUT) Log.v(mTag, "Ooops, something changed! mWidth=" + mWidth + " measuredWidth=" + host.getMeasuredWidth() + " mHeight=" + mHeight + " measuredHeight=" + host.getMeasuredHeight() @@ -1902,7 +1904,7 @@ public final class ViewRootImpl implements ViewParent, } if (measureAgain) { - if (DEBUG_LAYOUT) Log.v(TAG, + if (DEBUG_LAYOUT) Log.v(mTag, "And hey let's measure once more: width=" + width + " height=" + height); performMeasure(childWidthMeasureSpec, childHeightMeasureSpec); @@ -2024,15 +2026,15 @@ public final class ViewRootImpl implements ViewParent, if (mFirst) { // handle first focus request - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: mView.hasFocus()=" + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: mView.hasFocus()=" + mView.hasFocus()); if (mView != null) { if (!mView.hasFocus()) { mView.requestFocus(View.FOCUS_FORWARD); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: requested focused view=" + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: requested focused view=" + mView.findFocus()); } else { - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "First: existing focused view=" + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "First: existing focused view=" + mView.findFocus()); } } @@ -2104,11 +2106,11 @@ public final class ViewRootImpl implements ViewParent, } private void handleOutOfResourcesException(Surface.OutOfResourcesException e) { - Log.e(TAG, "OutOfResourcesException initializing HW surface", e); + Log.e(mTag, "OutOfResourcesException initializing HW surface", e); try { if (!mWindowSession.outOfMemory(mWindow) && Process.myUid() != Process.SYSTEM_UID) { - Slog.w(TAG, "No processes killed for memory; killing self"); + Slog.w(mTag, "No processes killed for memory; killing self"); Process.killProcess(Process.myPid()); } } catch (RemoteException ex) { @@ -2184,7 +2186,7 @@ public final class ViewRootImpl implements ViewParent, final View host = mView; if (DEBUG_ORIENTATION || DEBUG_LAYOUT) { - Log.v(TAG, "Laying out " + host + " to (" + + Log.v(mTag, "Laying out " + host + " to (" + host.getMeasuredWidth() + ", " + host.getMeasuredHeight() + ")"); } @@ -2427,11 +2429,11 @@ public final class ViewRootImpl implements ViewParent, String thisHash = Integer.toHexString(System.identityHashCode(this)); long frameTime = nowTime - mFpsPrevTime; long totalTime = nowTime - mFpsStartTime; - Log.v(TAG, "0x" + thisHash + "\tFrame time:\t" + frameTime); + Log.v(mTag, "0x" + thisHash + "\tFrame time:\t" + frameTime); mFpsPrevTime = nowTime; if (totalTime > 1000) { float fps = (float) mFpsNumFrames * 1000 / totalTime; - Log.v(TAG, "0x" + thisHash + "\tFPS:\t" + fps); + Log.v(mTag, "0x" + thisHash + "\tFPS:\t" + fps); mFpsStartTime = nowTime; mFpsNumFrames = 0; } @@ -2473,7 +2475,7 @@ public final class ViewRootImpl implements ViewParent, try { mWindowDrawCountDown.await(); } catch (InterruptedException e) { - Log.e(TAG, "Window redraw count down interruped!"); + Log.e(mTag, "Window redraw count down interruped!"); } mWindowDrawCountDown = null; } @@ -2483,7 +2485,7 @@ public final class ViewRootImpl implements ViewParent, } if (LOCAL_LOGV) { - Log.v(TAG, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); + Log.v(mTag, "FINISHED DRAWING: " + mWindowAttributes.getTitle()); } if (mSurfaceHolder != null && mSurface.isValid()) { mSurfaceHolderCallback.surfaceRedrawNeeded(mSurfaceHolder); @@ -2566,7 +2568,7 @@ public final class ViewRootImpl implements ViewParent, } if (DEBUG_ORIENTATION || DEBUG_DRAW) { - Log.v(TAG, "Draw " + mView + "/" + Log.v(mTag, "Draw " + mView + "/" + mWindowAttributes.getTitle() + ": dirty={" + dirty.left + "," + dirty.top + "," + dirty.right + "," + dirty.bottom + "} surface=" @@ -2700,7 +2702,7 @@ public final class ViewRootImpl implements ViewParent, handleOutOfResourcesException(e); return false; } catch (IllegalArgumentException e) { - Log.e(TAG, "Could not lock surface", e); + Log.e(mTag, "Could not lock surface", e); // Don't assume this is due to out of memory, it could be // something else, and if it is something else then we could // kill stuff (or ourself) for no reason. @@ -2710,7 +2712,7 @@ public final class ViewRootImpl implements ViewParent, try { if (DEBUG_ORIENTATION || DEBUG_DRAW) { - Log.v(TAG, "Surface " + surface + " drawing to bitmap w=" + Log.v(mTag, "Surface " + surface + " drawing to bitmap w=" + canvas.getWidth() + ", h=" + canvas.getHeight()); //canvas.drawARGB(255, 255, 0, 0); } @@ -2733,7 +2735,7 @@ public final class ViewRootImpl implements ViewParent, if (DEBUG_DRAW) { Context cxt = mView.getContext(); - Log.i(TAG, "Drawing: package:" + cxt.getPackageName() + + Log.i(mTag, "Drawing: package:" + cxt.getPackageName() + ", metrics=" + cxt.getResources().getDisplayMetrics() + ", compatibilityInfo=" + cxt.getResources().getCompatibilityInfo()); } @@ -2758,14 +2760,14 @@ public final class ViewRootImpl implements ViewParent, try { surface.unlockCanvasAndPost(canvas); } catch (IllegalArgumentException e) { - Log.e(TAG, "Could not unlock surface", e); + Log.e(mTag, "Could not unlock surface", e); mLayoutRequested = true; // ask wm for a new surface next time. //noinspection ReturnInsideFinallyBlock return false; } if (LOCAL_LOGV) { - Log.v(TAG, "Surface " + surface + " unlockCanvasAndPost"); + Log.v(mTag, "Surface " + surface + " unlockCanvasAndPost"); } } return true; @@ -2870,14 +2872,14 @@ public final class ViewRootImpl implements ViewParent, // view is visible. rectangle = null; } - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Eval scroll: focus=" + focus + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Eval scroll: focus=" + focus + " rectangle=" + rectangle + " ci=" + ci + " vi=" + vi); if (focus == lastScrolledFocus && !mScrollMayChange && rectangle == null) { // Optimization: if the focus hasn't changed since last // time, and no layout has happened, then just leave things // as they are. - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Keeping scroll y=" + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Keeping scroll y=" + mScrollY + " vi=" + vi.toShortString()); } else { // We need to determine if the currently focused view is @@ -2885,51 +2887,51 @@ public final class ViewRootImpl implements ViewParent, // a pan so it can be seen. mLastScrolledFocus = new WeakReference<View>(focus); mScrollMayChange = false; - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Need to scroll?"); + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Need to scroll?"); // Try to find the rectangle from the focus view. if (focus.getGlobalVisibleRect(mVisRect, null)) { - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Root w=" + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Root w=" + mView.getWidth() + " h=" + mView.getHeight() + " ci=" + ci.toShortString() + " vi=" + vi.toShortString()); if (rectangle == null) { focus.getFocusedRect(mTempRect); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Focus " + focus + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus " + focus + ": focusRect=" + mTempRect.toShortString()); if (mView instanceof ViewGroup) { ((ViewGroup) mView).offsetDescendantRectToMyCoords( focus, mTempRect); } - if (DEBUG_INPUT_RESIZE) Log.v(TAG, + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus in window: focusRect=" + mTempRect.toShortString() + " visRect=" + mVisRect.toShortString()); } else { mTempRect.set(rectangle); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Request scroll to rect: " + mTempRect.toShortString() + " visRect=" + mVisRect.toShortString()); } if (mTempRect.intersect(mVisRect)) { - if (DEBUG_INPUT_RESIZE) Log.v(TAG, + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Focus window visible rect: " + mTempRect.toShortString()); if (mTempRect.height() > (mView.getHeight()-vi.top-vi.bottom)) { // If the focus simply is not going to fit, then // best is probably just to leave things as-is. - if (DEBUG_INPUT_RESIZE) Log.v(TAG, + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Too tall; leaving scrollY=" + scrollY); } else if ((mTempRect.top-scrollY) < vi.top) { scrollY -= vi.top - (mTempRect.top-scrollY); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Top covered; scrollY=" + scrollY); } else if ((mTempRect.bottom-scrollY) > (mView.getHeight()-vi.bottom)) { scrollY += (mTempRect.bottom-scrollY) - (mView.getHeight()-vi.bottom); - if (DEBUG_INPUT_RESIZE) Log.v(TAG, + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Bottom covered; scrollY=" + scrollY); } handled = true; @@ -2939,7 +2941,7 @@ public final class ViewRootImpl implements ViewParent, } if (scrollY != mScrollY) { - if (DEBUG_INPUT_RESIZE) Log.v(TAG, "Pan scroll changed: old=" + if (DEBUG_INPUT_RESIZE) Log.v(mTag, "Pan scroll changed: old=" + mScrollY + " , new=" + scrollY); if (!immediate) { if (mScroller == null) { @@ -3018,7 +3020,7 @@ public final class ViewRootImpl implements ViewParent, void setPointerCapture(View view) { if (!mAttachInfo.mHasWindowFocus) { - Log.w(TAG, "Can't set capture if it's not focused."); + Log.w(mTag, "Can't set capture if it's not focused."); return; } if (mCapturingView == view) { @@ -3044,7 +3046,7 @@ public final class ViewRootImpl implements ViewParent, @Override public void requestChildFocus(View child, View focused) { if (DEBUG_INPUT_RESIZE) { - Log.v(TAG, "Request child focus: focus now " + focused); + Log.v(mTag, "Request child focus: focus now " + focused); } checkThread(); scheduleTraversals(); @@ -3053,7 +3055,7 @@ public final class ViewRootImpl implements ViewParent, @Override public void clearChildFocus(View child) { if (DEBUG_INPUT_RESIZE) { - Log.v(TAG, "Clearing child focus"); + Log.v(mTag, "Clearing child focus"); } checkThread(); scheduleTraversals(); @@ -3152,7 +3154,7 @@ public final class ViewRootImpl implements ViewParent, } void updateConfiguration(Configuration config, boolean force) { - if (DEBUG_CONFIGURATION) Log.v(TAG, + if (DEBUG_CONFIGURATION) Log.v(mTag, "Applying new config to window " + mWindowAttributes.getTitle() + ": " + config); @@ -3388,10 +3390,10 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mHardwareRenderer.initializeIfNeeded( mWidth, mHeight, mAttachInfo, mSurface, surfaceInsets); } catch (OutOfResourcesException e) { - Log.e(TAG, "OutOfResourcesException locking surface", e); + Log.e(mTag, "OutOfResourcesException locking surface", e); try { if (!mWindowSession.outOfMemory(mWindow)) { - Slog.w(TAG, "No processes killed for memory; killing self"); + Slog.w(mTag, "No processes killed for memory; killing self"); Process.killProcess(Process.myPid()); } } catch (RemoteException ex) { @@ -3714,7 +3716,7 @@ public final class ViewRootImpl implements ViewParent, */ protected void onDeliverToNext(QueuedInputEvent q) { if (DEBUG_INPUT_STAGES) { - Log.v(TAG, "Done with " + getClass().getSimpleName() + ". " + q); + Log.v(mTag, "Done with " + getClass().getSimpleName() + ". " + q); } if (mNext != null) { mNext.deliver(q); @@ -3725,7 +3727,7 @@ public final class ViewRootImpl implements ViewParent, protected boolean shouldDropInputEvent(QueuedInputEvent q) { if (mView == null || !mAdded) { - Slog.w(TAG, "Dropping event due to root view being removed: " + q.mEvent); + Slog.w(mTag, "Dropping event due to root view being removed: " + q.mEvent); return true; } else if ((!mAttachInfo.mHasWindowFocus && !q.mEvent.isFromSource(InputDevice.SOURCE_CLASS_POINTER)) || mStopped @@ -3736,12 +3738,12 @@ public final class ViewRootImpl implements ViewParent, if (isTerminalInputEvent(q.mEvent)) { // Don't drop terminal input events, however mark them as canceled. q.mEvent.cancel(); - Slog.w(TAG, "Cancelling event due to no window focus: " + q.mEvent); + Slog.w(mTag, "Cancelling event due to no window focus: " + q.mEvent); return false; } // Drop non-terminal input events. - Slog.w(TAG, "Dropping event due to no window focus: " + q.mEvent); + Slog.w(mTag, "Dropping event due to no window focus: " + q.mEvent); return true; } return false; @@ -3981,7 +3983,7 @@ public final class ViewRootImpl implements ViewParent, InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null) { final InputEvent event = q.mEvent; - if (DEBUG_IMF) Log.v(TAG, "Sending input event to IME: " + event); + if (DEBUG_IMF) Log.v(mTag, "Sending input event to IME: " + event); int result = imm.dispatchInputEvent(event, q, this, mHandler); if (result == InputMethodManager.DISPATCH_HANDLED) { return FINISH_HANDLED; @@ -4413,7 +4415,7 @@ public final class ViewRootImpl implements ViewParent, break; } - if (DEBUG_TRACKBALL) Log.v(TAG, "TB X=" + mX.position + " step=" + if (DEBUG_TRACKBALL) Log.v(mTag, "TB X=" + mX.position + " step=" + mX.step + " dir=" + mX.dir + " acc=" + mX.acceleration + " move=" + event.getX() + " / Y=" + mY.position + " step=" @@ -4452,11 +4454,11 @@ public final class ViewRootImpl implements ViewParent, if (keycode != 0) { if (movement < 0) movement = -movement; int accelMovement = (int)(movement * accel); - if (DEBUG_TRACKBALL) Log.v(TAG, "Move: movement=" + movement + if (DEBUG_TRACKBALL) Log.v(mTag, "Move: movement=" + movement + " accelMovement=" + accelMovement + " accel=" + accel); if (accelMovement > movement) { - if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: " + if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: " + keycode); movement--; int repeatCount = accelMovement - movement; @@ -4466,7 +4468,7 @@ public final class ViewRootImpl implements ViewParent, InputDevice.SOURCE_KEYBOARD)); } while (movement > 0) { - if (DEBUG_TRACKBALL) Log.v(TAG, "Delivering fake DPAD: " + if (DEBUG_TRACKBALL) Log.v(mTag, "Delivering fake DPAD: " + keycode); movement--; curTime = SystemClock.uptimeMillis(); @@ -4708,7 +4710,7 @@ public final class ViewRootImpl implements ViewParent, update(event, true); break; default: - Log.w(TAG, "Unexpected action: " + event.getActionMasked()); + Log.w(mTag, "Unexpected action: " + event.getActionMasked()); } } @@ -5347,7 +5349,7 @@ public final class ViewRootImpl implements ViewParent, mWindowSession.dragRecipientEntered(mWindow); } } catch (RemoteException e) { - Slog.e(TAG, "Unable to note drag target change"); + Slog.e(mTag, "Unable to note drag target change"); } } @@ -5355,10 +5357,10 @@ public final class ViewRootImpl implements ViewParent, if (what == DragEvent.ACTION_DROP) { mDragDescription = null; try { - Log.i(TAG, "Reporting drop result: " + result); + Log.i(mTag, "Reporting drop result: " + result); mWindowSession.reportDropResult(mWindow, result); } catch (RemoteException e) { - Log.e(TAG, "Unable to report drop result"); + Log.e(mTag, "Unable to report drop result"); } } @@ -5444,14 +5446,14 @@ public final class ViewRootImpl implements ViewParent, mTranslator.translateWindowLayout(params); } if (params != null) { - if (DBG) Log.d(TAG, "WindowLayout in layoutWindow:" + params); + if (DBG) Log.d(mTag, "WindowLayout in layoutWindow:" + params); } mPendingConfiguration.seq = 0; - //Log.d(TAG, ">>>>>> CALLING relayout"); + //Log.d(mTag, ">>>>>> CALLING relayout"); if (params != null && mOrigWindowType != params.type) { // For compatibility with old apps, don't crash here. if (mTargetSdkVersion < Build.VERSION_CODES.ICE_CREAM_SANDWICH) { - Slog.w(TAG, "Window type can not be changed after " + Slog.w(mTag, "Window type can not be changed after " + "the window is added; ignoring change of " + mView); params.type = mOrigWindowType; } @@ -5463,7 +5465,7 @@ public final class ViewRootImpl implements ViewParent, viewVisibility, insetsPending ? WindowManagerGlobal.RELAYOUT_INSETS_PENDING : 0, mWinFrame, mPendingOverscanInsets, mPendingContentInsets, mPendingVisibleInsets, mPendingStableInsets, mPendingOutsets, mPendingConfiguration, mSurface); - //Log.d(TAG, "<<<<<< BACK FROM relayout"); + //Log.d(mTag, "<<<<<< BACK FROM relayout"); if (restore) { params.restore(); } @@ -5510,7 +5512,7 @@ public final class ViewRootImpl implements ViewParent, } } catch (IllegalStateException e) { // Exception thrown by getAudioManager() when mView is null - Log.e(TAG, "FATAL EXCEPTION when attempting to play sound effect: " + e); + Log.e(mTag, "FATAL EXCEPTION when attempting to play sound effect: " + e); e.printStackTrace(); } } @@ -5633,7 +5635,7 @@ public final class ViewRootImpl implements ViewParent, if (!mIsDrawing) { destroyHardwareRenderer(); } else { - Log.e(TAG, "Attempting to destroy the window while drawing!\n" + + Log.e(mTag, "Attempting to destroy the window while drawing!\n" + " window=" + this + ", title=" + mWindowAttributes.getTitle()); } mHandler.sendEmptyMessage(MSG_DIE); @@ -5642,7 +5644,7 @@ public final class ViewRootImpl implements ViewParent, void doDie() { checkThread(); - if (LOCAL_LOGV) Log.v(TAG, "DIE in " + this + " of " + mSurface); + if (LOCAL_LOGV) Log.v(mTag, "DIE in " + this + " of " + mSurface); synchronized (this) { if (mRemoved) { return; @@ -5735,7 +5737,7 @@ public final class ViewRootImpl implements ViewParent, public void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets, Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw, Configuration newConfig, Rect backDropFrame) { - if (DEBUG_LAYOUT) Log.v(TAG, "Resizing " + this + ": frame=" + frame.toShortString() + if (DEBUG_LAYOUT) Log.v(mTag, "Resizing " + this + ": frame=" + frame.toShortString() + " contentInsets=" + contentInsets.toShortString() + " visibleInsets=" + visibleInsets.toShortString() + " reportDraw=" + reportDraw @@ -5773,7 +5775,7 @@ public final class ViewRootImpl implements ViewParent, } public void dispatchMoved(int newX, int newY) { - if (DEBUG_LAYOUT) Log.v(TAG, "Window moved " + this + ": newX=" + newX + " newY=" + newY); + if (DEBUG_LAYOUT) Log.v(mTag, "Window moved " + this + ": newX=" + newX + " newY=" + newY); if (mTranslator != null) { PointF point = new PointF(newX, newY); mTranslator.translatePointInScreenToAppWindow(point); @@ -6690,7 +6692,7 @@ public final class ViewRootImpl implements ViewParent, } void changeCanvasOpacity(boolean opaque) { - Log.d(TAG, "changeCanvasOpacity: opaque=" + opaque); + Log.d(mTag, "changeCanvasOpacity: opaque=" + opaque); if (mAttachInfo.mHardwareRenderer != null) { mAttachInfo.mHardwareRenderer.setOpaque(opaque); } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index d7a98abdb271..0b06d1591731 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -571,14 +571,11 @@ public abstract class Window { /** @hide */ public interface WindowControllerCallback { /** - * Called to move the window and its activity/task to a different stack container. - * For example, a window can move between - * {@link android.app.ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} stack and - * {@link android.app.ActivityManager.StackId#FREEFORM_WORKSPACE_STACK_ID} stack. - * - * @param stackId stack Id to change to. + * Moves the activity from + * {@link android.app.ActivityManager.StackId#FREEFORM_WORKSPACE_STACK_ID} to + * {@link android.app.ActivityManager.StackId#FULLSCREEN_WORKSPACE_STACK_ID} stack. */ - void changeWindowStack(int stackId) throws RemoteException; + void exitFreeformMode() throws RemoteException; /** Returns the current stack Id for the window. */ int getWindowStackId() throws RemoteException; diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 01bfbb5cea9f..ecec25852cbb 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -623,14 +623,16 @@ public interface WindowManagerPolicy { * decorations that can never be removed. That is, system bar or * button bar. */ - public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation); + public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, + int uiMode); /** * Return the display height available after excluding any screen * decorations that can never be removed. That is, system bar or * button bar. */ - public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation); + public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, + int uiMode); /** * Return the available screen width that we should report for the @@ -638,7 +640,8 @@ public interface WindowManagerPolicy { * {@link #getNonDecorDisplayWidth(int, int, int)}; it may be smaller than * that to account for more transient decoration like a status bar. */ - public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation); + public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, + int uiMode); /** * Return the available screen height that we should report for the @@ -646,7 +649,8 @@ public interface WindowManagerPolicy { * {@link #getNonDecorDisplayHeight(int, int, int)}; it may be smaller than * that to account for more transient decoration like a status bar. */ - public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation); + public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, + int uiMode); /** * Return whether the given window is forcibly hiding all windows except windows with @@ -861,11 +865,11 @@ public interface WindowManagerPolicy { * @param isDefaultDisplay true if window is on {@link Display#DEFAULT_DISPLAY}. * @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 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, - int displayRotation); + int displayRotation, int uiMode); /** * Returns the bottom-most layer of the system decor, above which no policy decor should diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 9442226a9be5..9595db2ccd21 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -987,9 +987,6 @@ public abstract class WebSettings { * @deprecated Database paths are managed by the implementation and calling this method * will have no effect. */ - // This will update WebCore when the Sync runs in the C++ side. - // Note that the WebCore Database Tracker only allows the path to be set - // once. @Deprecated public abstract void setDatabasePath(String databasePath); @@ -1000,8 +997,10 @@ public abstract class WebSettings { * * @param databasePath a path to the directory where databases should be * saved. + * @deprecated Geolocation database are managed by the implementation and calling this method + * will have no effect. */ - // This will update WebCore when the Sync runs in the C++ side. + @Deprecated public abstract void setGeolocationDatabasePath(String databasePath); /** @@ -1102,8 +1101,6 @@ public abstract class WebSettings { * via the JavaScript Geolocation API. * </ul> * <p> - * As an option, it is possible to store previous locations and web origin - * permissions in a database. See {@link #setGeolocationDatabasePath}. * * @param flag whether Geolocation should be enabled */ diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 7443bce5e4d0..0f58ba3c002c 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -280,6 +280,23 @@ import java.util.Map; * instead. * </p> * + * <h3>Metrics</h3> + * + * <p> + * 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: + * </p> + * <pre> + * <meta-data android:name="android.webkit.WebView.MetricsOptOut" + * android:value="true" /> + * </pre> + * <p> + * Data will only be uploaded for a given app if the user has consented AND the app has not opted + * out. + * </p> + * */ // Implementation notes. // The WebView is a thin API class that delegates its public API to a backend WebViewProvider diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 6aa5e2f573bd..9f08b214a849 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -271,18 +271,25 @@ public final class WebViewFactory { private static Class<WebViewFactoryProvider> getProviderClass() { try { - // First fetch the package info so we can log the webview package version. - int res = waitForProviderAndSetPackageInfo(); - if (res != LIBLOAD_SUCCESS) { - throw new MissingWebViewPackageException( - "Failed to load WebView provider, error: " - + getWebViewPreparationErrorReason(res)); + Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, + "WebViewFactory.waitForProviderAndSetPackageInfo()"); + try { + // First fetch the package info so we can log the webview package version. + int res = waitForProviderAndSetPackageInfo(); + if (res != LIBLOAD_SUCCESS) { + throw new MissingWebViewPackageException( + "Failed to load WebView provider, error: " + + getWebViewPreparationErrorReason(res)); + } + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " + sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")"); Application initialApplication = AppGlobals.getInitialApplication(); Context webViewContext = null; + Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "initialApplication.createPackageContext()"); try { // Construct a package context to load the Java code into the current app. // This is done as early as possible since by constructing a package context we @@ -293,6 +300,8 @@ public final class WebViewFactory { Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); } catch (PackageManager.NameNotFoundException e) { throw new MissingWebViewPackageException(e); + } finally { + Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); } Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()"); diff --git a/core/java/android/webkit/WebViewProviderInfo.java b/core/java/android/webkit/WebViewProviderInfo.java index 7bad6521b734..ac5b67089d20 100644 --- a/core/java/android/webkit/WebViewProviderInfo.java +++ b/core/java/android/webkit/WebViewProviderInfo.java @@ -139,9 +139,8 @@ public class WebViewProviderInfo implements Parcelable { private String[] signatures; private PackageInfo packageInfo; + // flags declaring we want extra info from the package manager - private final static int PACKAGE_FLAGS = - PackageManager.GET_META_DATA - | PackageManager.GET_SIGNATURES; + private final static int PACKAGE_FLAGS = PackageManager.GET_META_DATA + | PackageManager.GET_SIGNATURES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING; } - diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index cf4587d30373..831481ddba45 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -44,6 +44,12 @@ public abstract class AbsSeekBar extends ProgressBar { private boolean mHasThumbTint = false; private boolean mHasThumbTintMode = false; + private Drawable mTickMark; + private ColorStateList mTickMarkTintList = null; + private PorterDuff.Mode mTickMarkTintMode = null; + private boolean mHasTickMarkTint = false; + private boolean mHasTickMarkTintMode = false; + private int mThumbOffset; private boolean mSplitTrack; @@ -103,10 +109,25 @@ public abstract class AbsSeekBar extends ProgressBar { mHasThumbTint = true; } + final Drawable tickMark = a.getDrawable(R.styleable.SeekBar_tickMark); + setTickMark(tickMark); + + if (a.hasValue(R.styleable.SeekBar_tickMarkTintMode)) { + mTickMarkTintMode = Drawable.parseTintMode(a.getInt( + R.styleable.SeekBar_tickMarkTintMode, -1), mTickMarkTintMode); + mHasTickMarkTintMode = true; + } + + if (a.hasValue(R.styleable.SeekBar_tickMarkTint)) { + mTickMarkTintList = a.getColorStateList(R.styleable.SeekBar_tickMarkTint); + mHasTickMarkTint = true; + } + mSplitTrack = a.getBoolean(R.styleable.SeekBar_splitTrack, false); // Guess thumb offset if thumb != null, but allow layout to override. - final int thumbOffset = a.getDimensionPixelOffset(R.styleable.SeekBar_thumbOffset, getThumbOffset()); + final int thumbOffset = a.getDimensionPixelOffset( + R.styleable.SeekBar_thumbOffset, getThumbOffset()); setThumbOffset(thumbOffset); final boolean useDisabledAlpha = a.getBoolean(R.styleable.SeekBar_useDisabledAlpha, true); @@ -313,6 +334,123 @@ public abstract class AbsSeekBar extends ProgressBar { } /** + * Sets the drawable displayed at each progress position, e.g. at each + * possible thumb position. + * + * @param tickMark the drawable to display at each progress position + */ + public void setTickMark(Drawable tickMark) { + if (mTickMark != null) { + mTickMark.setCallback(null); + } + + mTickMark = tickMark; + + if (tickMark != null) { + tickMark.setCallback(this); + tickMark.setLayoutDirection(getLayoutDirection()); + if (tickMark.isStateful()) { + tickMark.setState(getDrawableState()); + } + applyTickMarkTint(); + } + + invalidate(); + } + + /** + * @return the drawable displayed at each progress position + */ + public Drawable getTickMark() { + return mTickMark; + } + + /** + * Applies a tint to the tick mark drawable. Does not modify the current tint + * mode, which is {@link PorterDuff.Mode#SRC_IN} by default. + * <p> + * Subsequent calls to {@link #setTickMark(Drawable)} will automatically + * mutate the drawable and apply the specified tint and tint mode using + * {@link Drawable#setTintList(ColorStateList)}. + * + * @param tint the tint to apply, may be {@code null} to clear tint + * + * @attr ref android.R.styleable#SeekBar_tickMarkTint + * @see #getTickMarkTintList() + * @see Drawable#setTintList(ColorStateList) + */ + public void setTickMarkTintList(@Nullable ColorStateList tint) { + mTickMarkTintList = tint; + mHasTickMarkTint = true; + + applyTickMarkTint(); + } + + /** + * Returns the tint applied to the tick mark drawable, if specified. + * + * @return the tint applied to the tick mark drawable + * @attr ref android.R.styleable#SeekBar_tickMarkTint + * @see #setTickMarkTintList(ColorStateList) + */ + @Nullable + public ColorStateList getTickMarkTintList() { + return mTickMarkTintList; + } + + /** + * Specifies the blending mode used to apply the tint specified by + * {@link #setTickMarkTintList(ColorStateList)}} to the tick mark drawable. The + * default mode is {@link PorterDuff.Mode#SRC_IN}. + * + * @param tintMode the blending mode used to apply the tint, may be + * {@code null} to clear tint + * + * @attr ref android.R.styleable#SeekBar_tickMarkTintMode + * @see #getTickMarkTintMode() + * @see Drawable#setTintMode(PorterDuff.Mode) + */ + public void setTickMarkTintMode(@Nullable PorterDuff.Mode tintMode) { + mTickMarkTintMode = tintMode; + mHasTickMarkTintMode = true; + + applyTickMarkTint(); + } + + /** + * Returns the blending mode used to apply the tint to the tick mark drawable, + * if specified. + * + * @return the blending mode used to apply the tint to the tick mark drawable + * @attr ref android.R.styleable#SeekBar_tickMarkTintMode + * @see #setTickMarkTintMode(PorterDuff.Mode) + */ + @Nullable + public PorterDuff.Mode getTickMarkTintMode() { + return mTickMarkTintMode; + } + + private void applyTickMarkTint() { + if (mTickMark != null && (mHasTickMarkTint || mHasTickMarkTintMode)) { + mTickMark = mTickMark.mutate(); + + if (mHasTickMarkTint) { + mTickMark.setTintList(mTickMarkTintList); + } + + if (mHasTickMarkTintMode) { + mTickMark.setTintMode(mTickMarkTintMode); + } + + // The drawable (or one of its children) may not have been + // stateful before applying the tint, so let's try again. + if (mTickMark.isStateful()) { + mTickMark.setState(getDrawableState()); + } + } + } + + /** * Sets the amount of progress changed via the arrow keys. * * @param increment The amount to increment or decrement when the user @@ -347,7 +485,7 @@ public abstract class AbsSeekBar extends ProgressBar { @Override protected boolean verifyDrawable(Drawable who) { - return who == mThumb || super.verifyDrawable(who); + return who == mThumb || who == mTickMark || super.verifyDrawable(who); } @Override @@ -357,6 +495,10 @@ public abstract class AbsSeekBar extends ProgressBar { if (mThumb != null) { mThumb.jumpToCurrentState(); } + + if (mTickMark != null) { + mTickMark.jumpToCurrentState(); + } } @Override @@ -373,6 +515,12 @@ public abstract class AbsSeekBar extends ProgressBar { && thumb.setState(getDrawableState())) { invalidateDrawable(thumb); } + + final Drawable tickMark = mTickMark; + if (tickMark != null && tickMark.isStateful() + && tickMark.setState(getDrawableState())) { + invalidateDrawable(tickMark); + } } @Override @@ -524,9 +672,36 @@ public abstract class AbsSeekBar extends ProgressBar { final int saveCount = canvas.save(); canvas.clipRect(tempRect, Op.DIFFERENCE); super.drawTrack(canvas); + drawTickMarks(canvas); canvas.restoreToCount(saveCount); } else { super.drawTrack(canvas); + drawTickMarks(canvas); + } + } + + /** + * Draw the tick marks. + */ + void drawTickMarks(Canvas canvas) { + if (mTickMark != null) { + final int count = getMax(); + if (count > 1) { + final int w = mTickMark.getIntrinsicWidth(); + final int h = mTickMark.getIntrinsicHeight(); + final int halfW = w >= 0 ? w / 2 : 1; + final int halfH = h >= 0 ? h / 2 : 1; + mTickMark.setBounds(-halfW, -halfH, halfW, halfH); + + final int spacing = (getWidth() - mPaddingLeft - mPaddingRight) / count; + final int saveCount = canvas.save(); + canvas.translate(mPaddingLeft, getHeight() / 2); + for (int i = 0; i <= count; i++) { + mTickMark.draw(canvas); + canvas.translate(spacing, 0); + } + canvas.restoreToCount(saveCount); + } } } @@ -535,12 +710,12 @@ public abstract class AbsSeekBar extends ProgressBar { */ void drawThumb(Canvas canvas) { if (mThumb != null) { - canvas.save(); + final int saveCount = canvas.save(); // Translate the padding. For the x, we need to allow the thumb to // draw in its extra space canvas.translate(mPaddingLeft - mThumbOffset, mPaddingTop); mThumb.draw(canvas); - canvas.restore(); + canvas.restoreToCount(saveCount); } } diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java index 0032f177633e..48d1d2b1b32f 100644 --- a/core/java/android/widget/ActionMenuPresenter.java +++ b/core/java/android/widget/ActionMenuPresenter.java @@ -20,6 +20,8 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -134,7 +136,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter } @Override - public void initForMenu(Context context, MenuBuilder menu) { + public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { super.initForMenu(context, menu); final Resources res = context.getResources(); @@ -629,8 +631,16 @@ public class ActionMenuPresenter extends BaseMenuPresenter } public boolean flagActionItems() { - final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems(); - final int itemsSize = visibleItems.size(); + final ArrayList<MenuItemImpl> visibleItems; + final int itemsSize; + if (mMenu != null) { + visibleItems = mMenu.getVisibleItems(); + itemsSize = visibleItems.size(); + } else { + visibleItems = null; + itemsSize = 0; + } + int maxActions = mMaxItems; int widthLimit = mActionItemWidthLimit; final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); @@ -786,7 +796,7 @@ public class ActionMenuPresenter extends BaseMenuPresenter if (isVisible) { // Not a submenu, but treat it like one. super.onSubMenuSelected(null); - } else { + } else if (mMenu != null) { mMenu.close(false /* closeAllMenus */); } } @@ -938,7 +948,9 @@ public class ActionMenuPresenter extends BaseMenuPresenter @Override protected void onDismiss() { - mMenu.close(); + if (mMenu != null) { + mMenu.close(); + } mOverflowPopup = null; super.onDismiss(); @@ -999,7 +1011,9 @@ public class ActionMenuPresenter extends BaseMenuPresenter } public void run() { - mMenu.changeMenuMode(); + if (mMenu != null) { + mMenu.changeMenuMode(); + } final View menuView = (View) mMenuView; if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) { mOverflowPopup = mPopup; diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java index 1f02c3b33e03..4d0a1c86fd92 100644 --- a/core/java/android/widget/ActionMenuView.java +++ b/core/java/android/widget/ActionMenuView.java @@ -622,7 +622,7 @@ public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvo } /** @hide */ - public void initialize(MenuBuilder menu) { + public void initialize(@Nullable MenuBuilder menu) { mMenu = menu; } diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java index 5f5943fe7472..87bee44611d8 100644 --- a/core/java/android/widget/DatePicker.java +++ b/core/java/android/widget/DatePicker.java @@ -999,8 +999,8 @@ public class DatePicker extends FrameLayout { private boolean isNewDate(int year, int month, int dayOfMonth) { return (mCurrentDate.get(Calendar.YEAR) != year - || mCurrentDate.get(Calendar.MONTH) != dayOfMonth - || mCurrentDate.get(Calendar.DAY_OF_MONTH) != month); + || mCurrentDate.get(Calendar.MONTH) != month + || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth); } private void setDate(int year, int month, int dayOfMonth) { diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 258424a2e574..ef6628a20063 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -1752,7 +1752,8 @@ public class GridLayout extends ViewGroup { boolean validSolution = true; // do a binary search to find the max delta that won't conflict with constraints while(deltaMin < deltaMax) { - final int delta = (deltaMin + deltaMax) / 2; + // cast to long to prevent overflow. + final int delta = (int) (((long) deltaMin + deltaMax) / 2); invalidateValues(); shareOutDelta(delta, totalWeight); validSolution = solve(getArcs(), a, false); diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index acbf5eb8d699..8e711b07b213 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -2070,7 +2070,7 @@ public class Toolbar extends ViewGroup { MenuItemImpl mCurrentExpandedItem; @Override - public void initForMenu(Context context, MenuBuilder menu) { + public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { // Clear the expanded action view when menus change. if (mMenu != null && mCurrentExpandedItem != null) { mMenu.collapseItemActionView(mCurrentExpandedItem); diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index ba0912a5536a..aa38de737484 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -718,9 +718,9 @@ public class ResolverActivity extends Activity { if (ri.handleAllWebDataURI) { // Set default Browser if needed - final String packageName = pm.getDefaultBrowserPackageName(userId); + final String packageName = pm.getDefaultBrowserPackageNameAsUser(userId); if (TextUtils.isEmpty(packageName)) { - pm.setDefaultBrowserPackageName(ri.activityInfo.packageName, userId); + pm.setDefaultBrowserPackageNameAsUser(ri.activityInfo.packageName, userId); } } else { // Update Domain Verification status @@ -737,7 +737,7 @@ public class ResolverActivity extends Activity { categories.contains(Intent.CATEGORY_BROWSABLE); if (isHttpOrHttps && isViewAction && hasCategoryBrowsable) { - pm.updateIntentVerificationStatus(packageName, + pm.updateIntentVerificationStatusAsUser(packageName, PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS, userId); } diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 4b821abec6fb..40eb375c027b 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -43,19 +43,25 @@ public class MetricsLogger implements MetricsConstants { * Logged when the user docks a window from recents by longpressing a task and dragging it to * the dock area. */ - public static final int ACTION_WINDOW_DOCK_DRAG_DROP = 265; + public static final int ACTION_WINDOW_DOCK_DRAG_DROP = 268; /** * Logged when the user docks a fullscreen window by long pressing recents which also opens * recents on the lower/right side. */ - public static final int ACTION_WINDOW_DOCK_LONGPRESS = 266; + public static final int ACTION_WINDOW_DOCK_LONGPRESS = 269; /** * Logged when the user docks a window by dragging from the navbar which also opens recents on * the lower/right side. */ - public static final int ACTION_WINDOW_DOCK_SWIPE = 267; + public static final int ACTION_WINDOW_DOCK_SWIPE = 270; + + /** + * Logged when the user launches a profile-specific app and we intercept it with the confirm + * credentials UI. + */ + public static final int PROFILE_CHALLENGE = 271; public static void visible(Context context, int category) throws IllegalArgumentException { if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) { diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java index 40eaaf7bae80..cc2f7142f893 100644 --- a/core/java/com/android/internal/policy/DecorView.java +++ b/core/java/com/android/internal/policy/DecorView.java @@ -23,7 +23,6 @@ import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.StandaloneActionMode; import com.android.internal.view.menu.ContextMenuBuilder; import com.android.internal.view.menu.MenuHelper; -import com.android.internal.view.menu.MenuPresenter; import com.android.internal.widget.ActionBarContextView; import com.android.internal.widget.BackgroundFallback; import com.android.internal.widget.DecorCaptionView; @@ -72,6 +71,7 @@ import android.widget.PopupWindow; import static android.app.ActivityManager.StackId; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; +import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.view.View.MeasureSpec.AT_MOST; import static android.view.View.MeasureSpec.EXACTLY; import static android.view.View.MeasureSpec.getMode; @@ -194,7 +194,12 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind private Drawable mCaptionBackgroundDrawable; private Drawable mUserCaptionBackgroundDrawable; - DecorView(Context context, int featureId, PhoneWindow window) { + private float mAvailableWidth; + + String mLogTag = TAG; + + DecorView(Context context, int featureId, PhoneWindow window, + WindowManager.LayoutParams params) { super(context); mFeatureId = featureId; @@ -210,7 +215,11 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind mSemiTransparentStatusBarColor = context.getResources().getColor( R.color.system_bar_background_semi_transparent, null /* theme */); + updateAvailableWidth(); + setWindow(window); + + updateLogTag(params); } void setBackgroundFallback(int resId) { @@ -408,7 +417,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind if (mFeatureId >= 0) { if (action == MotionEvent.ACTION_DOWN) { - Log.i(TAG, "Watchiing!"); + Log.i(mLogTag, "Watchiing!"); mWatchingForMenu = true; mDownY = (int) event.getY(); return false; @@ -421,7 +430,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind int y = (int)event.getY(); if (action == MotionEvent.ACTION_MOVE) { if (y > (mDownY+30)) { - Log.i(TAG, "Closing!"); + Log.i(mLogTag, "Closing!"); mWindow.closePanel(mFeatureId); mWatchingForMenu = false; return true; @@ -433,13 +442,13 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind return false; } - //Log.i(TAG, "Intercept: action=" + action + " y=" + event.getY() + //Log.i(mLogTag, "Intercept: action=" + action + " y=" + event.getY() // + " (in " + getHeight() + ")"); if (action == MotionEvent.ACTION_DOWN) { int y = (int)event.getY(); if (y >= (getHeight()-5) && !mWindow.hasChildren()) { - Log.i(TAG, "Watching!"); + Log.i(mLogTag, "Watching!"); mWatchingForMenu = true; } return false; @@ -452,7 +461,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind int y = (int)event.getY(); if (action == MotionEvent.ACTION_MOVE) { if (y < (getHeight()-30)) { - Log.i(TAG, "Opening!"); + Log.i(mLogTag, "Opening!"); mWindow.openPanel(Window.FEATURE_OPTIONS_PANEL, new KeyEvent( KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU)); mWatchingForMenu = false; @@ -543,15 +552,15 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics(); - final boolean isPortrait = metrics.widthPixels < metrics.heightPixels; + final boolean isPortrait = + getResources().getConfiguration().orientation == ORIENTATION_PORTRAIT; final int widthMode = getMode(widthMeasureSpec); final int heightMode = getMode(heightMeasureSpec); boolean fixedWidth = false; if (widthMode == AT_MOST) { - final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor - : mWindow.mFixedWidthMajor; + final TypedValue tvw = isPortrait ? mWindow.mFixedWidthMinor : mWindow.mFixedWidthMajor; if (tvw != null && tvw.type != TypedValue.TYPE_NULL) { final int w; if (tvw.type == TypedValue.TYPE_DIMENSION) { @@ -623,7 +632,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind if (tv.type == TypedValue.TYPE_DIMENSION) { min = (int)tv.getDimension(metrics); } else if (tv.type == TypedValue.TYPE_FRACTION) { - min = (int)tv.getFraction(metrics.widthPixels, metrics.widthPixels); + min = (int)tv.getFraction(mAvailableWidth, mAvailableWidth); } else { min = 0; } @@ -1217,7 +1226,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind int fop = fg.getOpacity(); int bop = bg.getOpacity(); if (false) - Log.v(TAG, "Background opacity: " + bop + ", Frame opacity: " + fop); + Log.v(mLogTag, "Background opacity: " + bop + ", Frame opacity: " + fop); if (fop == PixelFormat.OPAQUE || bop == PixelFormat.OPAQUE) { opacity = PixelFormat.OPAQUE; } else if (fop == PixelFormat.UNKNOWN) { @@ -1232,16 +1241,16 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind // frame with padding... there is no way to tell if the // frame and background together will draw all pixels. if (false) - Log.v(TAG, "Padding: " + mFramePadding); + Log.v(mLogTag, "Padding: " + mFramePadding); opacity = PixelFormat.TRANSLUCENT; } } if (false) - Log.v(TAG, "Background: " + bg + ", Frame: " + fg); + Log.v(mLogTag, "Background: " + bg + ", Frame: " + fg); } if (false) - Log.v(TAG, "Selected default opacity: " + opacity); + Log.v(mLogTag, "Selected default opacity: " + opacity); mDefaultOpacity = opacity; if (mFeatureId < 0) { @@ -1600,6 +1609,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind enableCaption(StackId.hasWindowDecor(workspaceId)); } } + updateAvailableWidth(); initializeElevation(); } @@ -1744,7 +1754,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind // We shouldn't really get here as the background fallback should be always available since // it is defaulted by the system. - Log.w(TAG, "Failed to find background drawable for PhoneWindow=" + mWindow); + Log.w(mLogTag, "Failed to find background drawable for PhoneWindow=" + mWindow); return null; } @@ -1761,7 +1771,7 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind try { workspaceId = callback.getWindowStackId(); } catch (RemoteException ex) { - Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow."); + Log.e(mLogTag, "Failed to get the workspace ID of a PhoneWindow."); } } if (workspaceId == INVALID_STACK_ID) { @@ -1927,6 +1937,19 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind } } + void updateLogTag(WindowManager.LayoutParams params) { + final String[] split = params.getTitle().toString().split("\\."); + if (split.length > 0) { + mLogTag = TAG + "[" + split[split.length - 1] + "]"; + } + } + + private void updateAvailableWidth() { + Resources res = getResources(); + mAvailableWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, + res.getConfiguration().screenWidthDp, res.getDisplayMetrics()); + } + private static class ColorViewState { View view = null; int targetVisibility = View.INVISIBLE; @@ -1988,12 +2011,12 @@ public class DecorView extends FrameLayout implements RootViewSurfaceTaker, Wind isPrimary = mode == mPrimaryActionMode; isFloating = mode == mFloatingActionMode; if (!isPrimary && mode.getType() == ActionMode.TYPE_PRIMARY) { - Log.e(TAG, "Destroying unexpected ActionMode instance of TYPE_PRIMARY; " + Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_PRIMARY; " + mode + " was not the current primary action mode! Expected " + mPrimaryActionMode); } if (!isFloating && mode.getType() == ActionMode.TYPE_FLOATING) { - Log.e(TAG, "Destroying unexpected ActionMode instance of TYPE_FLOATING; " + Log.e(mLogTag, "Destroying unexpected ActionMode instance of TYPE_FLOATING; " + mode + " was not the current floating action mode! Expected " + mFloatingActionMode); } diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index fafe3d1a7506..f159a4d71f20 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -113,6 +113,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { private final static String TAG = "PhoneWindow"; + private static final boolean DEBUG = false; + private final static int DEFAULT_BACKGROUND_FADE_DURATION_MS = 300; private static final int CUSTOM_TITLE_COMPATIBLE_FEATURES = DEFAULT_FEATURES | @@ -146,6 +148,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { // This is the view in which the window contents are placed. It is either // mDecor itself, or a child of mDecor where the contents go. ViewGroup mContentParent; + // Whether the client has explicitly set the content view. If false and mContentParent is not + // null, then the content parent was set due to window preservation. + private boolean mContentParentExplicitlySet = false; Callback2 mTakeSurfaceCallback; @@ -315,7 +320,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { @Override public boolean requestFeature(int featureId) { - if (mContentParent != null) { + if (mContentParentExplicitlySet) { throw new AndroidRuntimeException("requestFeature() must be called before adding content"); } final int features = getFeatures(); @@ -399,6 +404,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (cb != null && !isDestroyed()) { cb.onContentChanged(); } + mContentParentExplicitlySet = true; } @Override @@ -429,6 +435,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { if (cb != null && !isDestroyed()) { cb.onContentChanged(); } + mContentParentExplicitlySet = true; } @Override @@ -2281,7 +2288,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { context = getContext(); } - return new DecorView(context, featureId, this); + return new DecorView(context, featureId, this, getAttributes()); } protected ViewGroup generateLayout(DecorView decor) { @@ -2360,6 +2367,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { a.getValue(R.styleable.Window_windowMinWidthMajor, mMinWidthMajor); a.getValue(R.styleable.Window_windowMinWidthMinor, mMinWidthMinor); + if (DEBUG) Log.d(TAG, "Min width minor: " + mMinWidthMinor.coerceToString() + + ", major: " + mMinWidthMajor.coerceToString()); if (a.hasValue(R.styleable.Window_windowFixedWidthMajor)) { if (mFixedWidthMajor == null) mFixedWidthMajor = new TypedValue(); a.getValue(R.styleable.Window_windowFixedWidthMajor, @@ -3776,4 +3785,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { int getDecorCaptionShade() { return mDecorCaptionShade; } + + @Override + public void setAttributes(WindowManager.LayoutParams params) { + super.setAttributes(params); + if (mDecor != null) { + mDecor.updateLogTag(params); + } + } } diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl index 849d3145bb56..632285ccf511 100644 --- a/core/java/com/android/internal/statusbar/IStatusBar.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl @@ -24,8 +24,8 @@ import com.android.internal.statusbar.StatusBarIcon; /** @hide */ oneway interface IStatusBar { - void setIcon(int index, in StatusBarIcon icon); - void removeIcon(int index); + void setIcon(String slot, in StatusBarIcon icon); + void removeIcon(String slot); void disable(int state1, int state2); void animateExpandNotificationsPanel(); void animateExpandSettingsPanel(String subPanel); @@ -46,7 +46,7 @@ oneway interface IStatusBar void cancelPreloadRecentApps(); void showScreenPinningRequest(); - void showKeyboardShortcutsMenu(); + void toggleKeyboardShortcutsMenu(); /** * Notifies the status bar that an app transition is pending to delay applying some flags with diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 0a4ad0661c64..32de45cb70f3 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -44,7 +44,8 @@ interface IStatusBarService // ---- Methods below are for use by the status bar policy services ---- // You need the STATUS_BAR_SERVICE permission - void registerStatusBar(IStatusBar callbacks, out StatusBarIconList iconList, + void registerStatusBar(IStatusBar callbacks, out List<String> iconSlots, + out List<StatusBarIcon> iconList, out int[] switches, out List<IBinder> binders); void onPanelRevealed(boolean clearNotificationEffects, int numItems); void onPanelHidden(); @@ -68,7 +69,7 @@ interface IStatusBarService void preloadRecentApps(); void cancelPreloadRecentApps(); - void showKeyboardShortcutsMenu(); + void toggleKeyboardShortcutsMenu(); /** * Notifies the status bar that an app transition is pending to delay applying some flags with diff --git a/core/java/com/android/internal/statusbar/StatusBarIconList.java b/core/java/com/android/internal/statusbar/StatusBarIconList.java deleted file mode 100644 index 478d245eb8cd..000000000000 --- a/core/java/com/android/internal/statusbar/StatusBarIconList.java +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.internal.statusbar; - -import android.os.Parcel; -import android.os.Parcelable; - -import java.io.PrintWriter; - -public class StatusBarIconList implements Parcelable { - private String[] mSlots; - private StatusBarIcon[] mIcons; - - public StatusBarIconList() { - } - - public StatusBarIconList(Parcel in) { - readFromParcel(in); - } - - public void readFromParcel(Parcel in) { - this.mSlots = in.readStringArray(); - final int N = in.readInt(); - if (N < 0) { - mIcons = null; - } else { - mIcons = new StatusBarIcon[N]; - for (int i=0; i<N; i++) { - if (in.readInt() != 0) { - mIcons[i] = new StatusBarIcon(in); - } - } - } - } - - public void writeToParcel(Parcel out, int flags) { - out.writeStringArray(mSlots); - if (mIcons == null) { - out.writeInt(-1); - } else { - final int N = mIcons.length; - out.writeInt(N); - for (int i=0; i<N; i++) { - StatusBarIcon ic = mIcons[i]; - if (ic == null) { - out.writeInt(0); - } else { - out.writeInt(1); - ic.writeToParcel(out, flags); - } - } - } - } - - public int describeContents() { - return 0; - } - - /** - * Parcelable.Creator that instantiates StatusBarIconList objects - */ - public static final Parcelable.Creator<StatusBarIconList> CREATOR - = new Parcelable.Creator<StatusBarIconList>() - { - public StatusBarIconList createFromParcel(Parcel parcel) - { - return new StatusBarIconList(parcel); - } - - public StatusBarIconList[] newArray(int size) - { - return new StatusBarIconList[size]; - } - }; - - public void defineSlots(String[] slots) { - final int N = slots.length; - String[] s = mSlots = new String[N]; - for (int i=0; i<N; i++) { - s[i] = slots[i]; - } - mIcons = new StatusBarIcon[N]; - } - - public int getSlotIndex(String slot) { - final int N = mSlots.length; - for (int i=0; i<N; i++) { - if (slot.equals(mSlots[i])) { - return i; - } - } - return -1; - } - - public int size() { - return mSlots.length; - } - - public void setIcon(int index, StatusBarIcon icon) { - mIcons[index] = icon.clone(); - } - - public void removeIcon(int index) { - mIcons[index] = null; - } - - public String getSlot(int index) { - return mSlots[index]; - } - - public StatusBarIcon getIcon(int index) { - return mIcons[index]; - } - - public int getViewIndex(int index) { - int count = 0; - for (int i=0; i<index; i++) { - if (mIcons[i] != null) { - count++; - } - } - return count; - } - - public void copyFrom(StatusBarIconList that) { - if (that.mSlots == null) { - this.mSlots = null; - this.mIcons = null; - } else { - final int N = that.mSlots.length; - this.mSlots = new String[N]; - this.mIcons = new StatusBarIcon[N]; - for (int i=0; i<N; i++) { - this.mSlots[i] = that.mSlots[i]; - this.mIcons[i] = that.mIcons[i] != null ? that.mIcons[i].clone() : null; - } - } - } - - public void dump(PrintWriter pw) { - final int N = mSlots.length; - pw.println("Icon list:"); - for (int i=0; i<N; i++) { - pw.printf(" %2d: (%s) %s\n", i, mSlots[i], mIcons[i]); - } - } -} diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java index 406b487f643d..dc668189c771 100644 --- a/core/java/com/android/internal/util/StateMachine.java +++ b/core/java/com/android/internal/util/StateMachine.java @@ -779,7 +779,7 @@ public class StateMachine { @Override public final void handleMessage(Message msg) { if (!mHasQuit) { - if (mSm != null) { + if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) { mSm.onPreHandleMessage(msg); } @@ -807,7 +807,7 @@ public class StateMachine { // We need to check if mSm == null here as we could be quitting. if (mDbg && mSm != null) mSm.log("handleMessage: X"); - if (mSm != null) { + if (mSm != null && msg.what != SM_INIT_CMD && msg.what != SM_QUIT_CMD) { mSm.onPostHandleMessage(msg); } } diff --git a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java index 92e9ea6f3c18..7ac0ac368407 100644 --- a/core/java/com/android/internal/view/menu/BaseMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/BaseMenuPresenter.java @@ -16,6 +16,8 @@ package com.android.internal.view.menu; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.view.LayoutInflater; import android.view.View; @@ -58,7 +60,7 @@ public abstract class BaseMenuPresenter implements MenuPresenter { } @Override - public void initForMenu(Context context, MenuBuilder menu) { + public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { mContext = context; mInflater = LayoutInflater.from(mContext); mMenu = menu; diff --git a/core/java/com/android/internal/view/menu/IconMenuPresenter.java b/core/java/com/android/internal/view/menu/IconMenuPresenter.java index 2439b5df3acc..5223a7b6d8a1 100644 --- a/core/java/com/android/internal/view/menu/IconMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/IconMenuPresenter.java @@ -17,6 +17,8 @@ package com.android.internal.view.menu; import com.android.internal.view.menu.MenuView.ItemView; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.Bundle; import android.os.Parcelable; @@ -49,7 +51,7 @@ public class IconMenuPresenter extends BaseMenuPresenter { } @Override - public void initForMenu(Context context, MenuBuilder menu) { + public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { super.initForMenu(context, menu); mMaxItems = -1; } diff --git a/core/java/com/android/internal/view/menu/ListMenuPresenter.java b/core/java/com/android/internal/view/menu/ListMenuPresenter.java index c476354c9281..2fff3ba54ac8 100644 --- a/core/java/com/android/internal/view/menu/ListMenuPresenter.java +++ b/core/java/com/android/internal/view/menu/ListMenuPresenter.java @@ -16,6 +16,8 @@ package com.android.internal.view.menu; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.Bundle; import android.os.Parcelable; @@ -76,7 +78,7 @@ public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClick } @Override - public void initForMenu(Context context, MenuBuilder menu) { + public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { if (mThemeRes != 0) { mContext = new ContextThemeWrapper(context, mThemeRes); mInflater = LayoutInflater.from(mContext); diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java index 465d775508e6..31b2f9619ed6 100644 --- a/core/java/com/android/internal/view/menu/MenuBuilder.java +++ b/core/java/com/android/internal/view/menu/MenuBuilder.java @@ -17,6 +17,7 @@ package com.android.internal.view.menu; +import android.annotation.NonNull; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -1027,23 +1028,24 @@ public class MenuBuilder implements Menu { mIsActionItemsStale = true; onItemsChanged(true); } - + + @NonNull public ArrayList<MenuItemImpl> getVisibleItems() { if (!mIsVisibleItemsStale) return mVisibleItems; - + // Refresh the visible items mVisibleItems.clear(); - + final int itemsSize = mItems.size(); MenuItemImpl item; for (int i = 0; i < itemsSize; i++) { item = mItems.get(i); if (item.isVisible()) mVisibleItems.add(item); } - + mIsVisibleItemsStale = false; mIsActionItemsStale = true; - + return mVisibleItems; } diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java index 98f5d9061e14..b151f348e58c 100644 --- a/core/java/com/android/internal/view/menu/MenuPopup.java +++ b/core/java/com/android/internal/view/menu/MenuPopup.java @@ -16,6 +16,8 @@ package com.android.internal.view.menu; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.view.MenuItem; import android.view.View; @@ -73,7 +75,7 @@ public abstract class MenuPopup implements ShowableListMenu, MenuPresenter, public abstract void setOnDismissListener(PopupWindow.OnDismissListener listener); @Override - public void initForMenu(Context context, MenuBuilder menu) { + public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { // Don't need to do anything; we added as a presenter in the constructor. } diff --git a/core/java/com/android/internal/view/menu/MenuPresenter.java b/core/java/com/android/internal/view/menu/MenuPresenter.java index c847c15607e1..65bdc096bc07 100644 --- a/core/java/com/android/internal/view/menu/MenuPresenter.java +++ b/core/java/com/android/internal/view/menu/MenuPresenter.java @@ -16,6 +16,8 @@ package com.android.internal.view.menu; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.Parcelable; import android.view.ViewGroup; @@ -49,14 +51,16 @@ public interface MenuPresenter { } /** - * Initialize this presenter for the given context and menu. - * This method is called by MenuBuilder when a presenter is - * added. See {@link MenuBuilder#addMenuPresenter(MenuPresenter)} + * Initializes this presenter for the given context and menu. + * <p> + * This method is called by MenuBuilder when a presenter is added. See + * {@link MenuBuilder#addMenuPresenter(MenuPresenter)}. * - * @param context Context for this presenter; used for view creation and resource management - * @param menu Menu to host + * @param context the context for this presenter; used for view creation + * and resource management, must be non-{@code null} + * @param menu the menu to host, or {@code null} to clear the hosted menu */ - public void initForMenu(Context context, MenuBuilder menu); + public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu); /** * Retrieve a MenuView to display the menu specified in diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 825e336a7ea3..f90b59dbdbb2 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -17,6 +17,8 @@ package com.android.internal.widget; import android.animation.LayoutTransition; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActionBar; import android.content.Context; import android.content.res.Configuration; @@ -1593,7 +1595,7 @@ public class ActionBarView extends AbsActionBarView implements DecorToolbar { MenuItemImpl mCurrentExpandedItem; @Override - public void initForMenu(Context context, MenuBuilder menu) { + public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { // Clear the expanded action view when menus change. if (mMenu != null && mCurrentExpandedItem != null) { mMenu.collapseItemActionView(mCurrentExpandedItem); diff --git a/core/java/com/android/internal/widget/DecorCaptionView.java b/core/java/com/android/internal/widget/DecorCaptionView.java index c3fe9e77e877..409a17f9c4db 100644 --- a/core/java/com/android/internal/widget/DecorCaptionView.java +++ b/core/java/com/android/internal/widget/DecorCaptionView.java @@ -16,8 +16,6 @@ package com.android.internal.widget; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; - import android.content.Context; import android.graphics.Color; import android.graphics.Rect; @@ -351,7 +349,7 @@ public class DecorCaptionView extends ViewGroup implements View.OnTouchListener, Window.WindowControllerCallback callback = mOwner.getWindowControllerCallback(); if (callback != null) { try { - callback.changeWindowStack(FULLSCREEN_WORKSPACE_STACK_ID); + callback.exitFreeformMode(); } catch (RemoteException ex) { Log.e(TAG, "Cannot change task workspace."); } diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index d8ec22a0f697..92f781268732 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -260,6 +260,15 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding return nullObjectReturn("SkAndroidCodec::NewFromStream returned null"); } + // Do not allow ninepatch decodes to 565. In the past, decodes to 565 + // would dither, and we do not want to pre-dither ninepatches, since we + // know that they will be stretched. We no longer dither 565 decodes, + // but we continue to prevent ninepatches from decoding to 565, in order + // to maintain the old behavior. + if (peeker.mPatch && kRGB_565_SkColorType == prefColorType) { + prefColorType = kN32_SkColorType; + } + // Determine the output size and return if the client only wants the size. SkISize size = codec->getSampledDimensions(sampleSize); if (options != NULL) { @@ -369,15 +378,7 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding case SkCodec::kIncompleteInput: break; default: - return nullObjectReturn("codec->getAndoridPixels() failed."); - } - - // Some images may initially report that they have alpha due to the format - // of the encoded data, but then never use any colors which have alpha - // less than 100%. Here we check if the image really had alpha, and - // mark it as opaque if it is actually opaque. - if (kOpaque_SkAlphaType != alphaType && !codec->reallyHasAlpha()) { - decodingBitmap.setAlphaType(kOpaque_SkAlphaType); + return nullObjectReturn("codec->getAndroidPixels() failed."); } int scaledWidth = size.width(); diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index 6d3c7d7363c6..e162810fd802 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -498,6 +498,22 @@ android_media_AudioSystem_getMasterMute(JNIEnv *env, jobject thiz) } static jint +android_media_AudioSystem_setMasterMono(JNIEnv *env, jobject thiz, jboolean mono) +{ + return (jint) check_AudioSystem_Command(AudioSystem::setMasterMono(mono)); +} + +static jboolean +android_media_AudioSystem_getMasterMono(JNIEnv *env, jobject thiz) +{ + bool mono; + if (AudioSystem::getMasterMono(&mono) != NO_ERROR) { + mono = false; + } + return mono; +} + +static jint android_media_AudioSystem_getDevicesForStream(JNIEnv *env, jobject thiz, jint stream) { return (jint) AudioSystem::getDevicesForStream(static_cast <audio_stream_type_t>(stream)); @@ -1637,6 +1653,8 @@ static const JNINativeMethod gMethods[] = { {"getMasterVolume", "()F", (void *)android_media_AudioSystem_getMasterVolume}, {"setMasterMute", "(Z)I", (void *)android_media_AudioSystem_setMasterMute}, {"getMasterMute", "()Z", (void *)android_media_AudioSystem_getMasterMute}, + {"setMasterMono", "(Z)I", (void *)android_media_AudioSystem_setMasterMono}, + {"getMasterMono", "()Z", (void *)android_media_AudioSystem_getMasterMono}, {"getDevicesForStream", "(I)I", (void *)android_media_AudioSystem_getDevicesForStream}, {"getPrimaryOutputSamplingRate", "()I", (void *)android_media_AudioSystem_getPrimaryOutputSamplingRate}, {"getPrimaryOutputFrameCount", "()I", (void *)android_media_AudioSystem_getPrimaryOutputFrameCount}, diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index 7860b74cc804..42f3fb0d4465 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -1049,6 +1049,10 @@ static void android_media_AudioTrack_disableDeviceCallback( pJniStorage->mDeviceCallback.clear(); } +static jint android_media_AudioTrack_get_FCC_8(JNIEnv *env, jobject thiz) { + return FCC_8; +} + // ---------------------------------------------------------------------------- // ---------------------------------------------------------------------------- @@ -1106,6 +1110,7 @@ static const JNINativeMethod gMethods[] = { {"native_getRoutedDeviceId", "()I", (void *)android_media_AudioTrack_getRoutedDeviceId}, {"native_enableDeviceCallback", "()V", (void *)android_media_AudioTrack_enableDeviceCallback}, {"native_disableDeviceCallback", "()V", (void *)android_media_AudioTrack_disableDeviceCallback}, + {"native_get_FCC_8", "()I", (void *)android_media_AudioTrack_get_FCC_8}, }; @@ -1135,6 +1140,9 @@ bool android_media_getIntConstantFromClass(JNIEnv* pEnv, jclass theClass, const // ---------------------------------------------------------------------------- int register_android_media_AudioTrack(JNIEnv *env) { + // must be first + int res = RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); + javaAudioTrackFields.nativeTrackInJavaObj = NULL; javaAudioTrackFields.postNativeEventInJava = NULL; @@ -1173,7 +1181,7 @@ int register_android_media_AudioTrack(JNIEnv *env) // initialize PlaybackParams field info gPlaybackParamsFields.init(env); - return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods)); + return res; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index c154e91bb559..21ba793c2a92 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -103,9 +103,9 @@ <protected-broadcast android:name="android.os.action.SETTING_RESTORED" /> - <protected-broadcast android:name="android.backup.intent.RUN" /> - <protected-broadcast android:name="android.backup.intent.CLEAR" /> - <protected-broadcast android:name="android.backup.intent.INIT" /> + <protected-broadcast android:name="android.app.backup.intent.RUN" /> + <protected-broadcast android:name="android.app.backup.intent.CLEAR" /> + <protected-broadcast android:name="android.app.backup.intent.INIT" /> <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" /> <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" /> @@ -205,6 +205,7 @@ <protected-broadcast android:name="android.media.VOLUME_CHANGED_ACTION" /> <protected-broadcast android:name="android.media.MASTER_VOLUME_CHANGED_ACTION" /> <protected-broadcast android:name="android.media.MASTER_MUTE_CHANGED_ACTION" /> + <protected-broadcast android:name="android.media.MASTER_MONO_CHANGED_ACTION" /> <protected-broadcast android:name="android.media.SCO_AUDIO_STATE_CHANGED" /> <protected-broadcast android:name="android.media.ACTION_SCO_AUDIO_STATE_UPDATED" /> @@ -277,8 +278,10 @@ <protected-broadcast android:name="android.intent.action.AIRPLANE_MODE" /> <protected-broadcast android:name="android.intent.action.ADVANCED_SETTINGS" /> <protected-broadcast android:name="android.intent.action.APPLICATION_RESTRICTIONS_CHANGED" /> - <protected-broadcast android:name="android.intent.action.BUGREPORT_FINISHED" /> <protected-broadcast android:name="android.intent.action.BUGREPORT_STARTED" /> + <protected-broadcast android:name="android.intent.action.BUGREPORT_FINISHED" /> + <protected-broadcast android:name="android.intent.action.REMOTE_BUGREPORT_FINISHED" /> + <protected-broadcast android:name="android.intent.action.REMOTE_BUGREPORT_DISPATCH" /> <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_START" /> <protected-broadcast android:name="android.intent.action.ACTION_IDLE_MAINTENANCE_END" /> @@ -383,6 +386,15 @@ <protected-broadcast android:name="com.android.server.Wifi.action.TOGGLE_PNO" /> <protected-broadcast android:name="intent.action.ACTION_RF_BAND_INFO" /> + <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED" /> + <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" /> + <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_CHANGED" /> + <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED" /> + <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" /> + + <protected-broadcast android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" /> + <protected-broadcast android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS" /> + <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> <!-- ====================================================================== --> @@ -2184,6 +2196,21 @@ <permission android:name="android.permission.CLEAR_APP_USER_DATA" android:protectionLevel="signature|installer" /> + <!-- @hide Allows an application to get the URI permissions + granted to another application. + <p>Not for use by third-party applications + --> + <permission android:name="android.permission.GET_APP_GRANTED_URI_PERMISSIONS" + android:protectionLevel="signature" /> + + <!-- @hide Allows an application to clear the URI permissions + granted to another application. + <p>Not for use by third-party applications + --> + <permission + android:name="android.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS" + android:protectionLevel="signature" /> + <!-- @SystemApi Allows an application to delete cache files. <p>Not for use by third-party applications. --> <permission android:name="android.permission.DELETE_CACHE_FILES" diff --git a/core/res/res/drawable/seekbar_tick_mark_material.xml b/core/res/res/drawable/seekbar_tick_mark_material.xml new file mode 100644 index 000000000000..d2c38a214b35 --- /dev/null +++ b/core/res/res/drawable/seekbar_tick_mark_material.xml @@ -0,0 +1,23 @@ +<?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. +--> + +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="oval" + android:tint="?attr/colorControlNormal"> + <size android:width="@dimen/progress_bar_height_material" + android:height="@dimen/progress_bar_height_material" /> + <solid android:color="@color/white" /> +</shape> diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml index 04466e511bb8..36c167ea8056 100644 --- a/core/res/res/values-af/strings.xml +++ b/core/res/res/values-af/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Laat die program toe om foto\'s en video\'s met die kamera te neem. Hierdie toestemming laat die program toe om die kamera te eniger tyd sonder jou bevestiging te gebruik."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"beheer vibrasie"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Laat die program toe om die vibrator te beheer."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"beheer flitslig"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Laat die program toe om die flitslig te beheer."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"skakel foonnommers direk"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Laat die program toe om telefoonnommers sonder jou tussentrede te bel. Dit kan tot onverwagte heffings of oproepe lei. Let daarop dat dit nie die program toelaat om noodnommers te bel nie. Kwaadwillige programme kan jou geld kos deur oproepe sonder jou bevestiging te maak."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot kitsboodskapoproepdiens"</string> diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index b26232572be7..ec16add34a26 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ነዛሪ ተቆጣጠር"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"ነዛሪውን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"የብርሃንብልጭታ ተቆጣጠር"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"የብልጭታ ብርሃኑን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"በቀጥታ ስልክ ቁጥሮች ደውል"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"መተግበሪያው ያላንተ ጣልቃ ገብነት የስልክ ቁጥሮች ላይ እንዲደውል ይፈቅድለታል። ይህ ያልተጠበቁ ክፍያዎችን ወይም ጥሪዎችን ሊያስከትል ይችላል። ይህ መተግበሪያው የድንገተኛ ስልክ ቁጥሮችን እንዲደውል እንደማይፈቅድለት ልብ በል። ተንኮል አዘል መተግበሪያዎች ያላንተ ማረጋገጫ ጥሪዎችን በማድረግ ገንዘብ ሊያስወጡህ ይችላሉ።"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"የአይኤምኤስ ጥሪ አገልግሎትን ይደርሳል"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 6eb005c0aae4..12ef759d60ad 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -358,8 +358,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"للسماح للتطبيق بالتقاط صور ومقاطع فيديو من خلال الكاميرا. ويتيح هذا الإذن للتطبيق استخدام الكاميرا في أي وقت وبدون موافقة منك."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"التحكم في الاهتزاز"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"للسماح للتطبيق بالتحكم في الهزّاز."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"التحكم في الضوء الوامض"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"للسماح للتطبيق بالتحكم في الضوء الوامض."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"اتصال مباشر بأرقام الهواتف"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"للسماح للتطبيق بطلب أرقام هاتفية بدون تدخل منك. وقد يؤدي ذلك إلى تحمل رسوم غير متوقعة أو إجراء مكالمات غير متوقعة. ومن الجدير بالذكر أن ذلك لا يتيح للتطبيق الاتصال بأرقام الطوارئ. وقد تؤدي التطبيقات الضارة إلى تحملك تكاليف مالية من خلال إجراء مكالمات بدون موافقة منك."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"الوصول إلى خدمة الاتصال عبر الرسائل الفورية"</string> diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml index 30b6e77d59f5..7f0e6d7a3cf7 100644 --- a/core/res/res/values-az-rAZ/strings.xml +++ b/core/res/res/values-az-rAZ/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Tətbiqə kamera ilə şəkil və video çəkməyə imkan yaradır. Bu icazə tətbiqə sizin təsdiqiniz olmadan kameradan istifadə icazəsi verir."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"vibrasiyaya nəzarət edir"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Tətbiqə vibratoru idarə etmə icazəsi verir."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"Flash işığını idarə edir"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Tətbiqə siqnal işığı na nəzarət etməyə imkan verir."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"telefon nömrələrinə birbaşa zəng edir"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Tətbiqə Sizin müdaxiləniz olmadan telefon zəngləri etməyə imkan verir. Zərərli tətbiqlər Sizdən xəbərsiz şəkildə müxtəlif zənglər edərək, Sizə maddi ziyan vura bilər. Qeyd: Bu, tətbiqlərə təcili nömrələrə zəng etməyə icazə vermir."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS zəng xidmətinə giriş"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 0f51f0d9d976..ac5ce6629593 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -355,8 +355,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Dozvoljava aplikaciji da snima slike i video snimke kamerom. Ova dozvola omogućava aplikaciji da u bilo kom trenutku koristi kameru bez vaše potvrde."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kontrola vibracije"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Dozvoljava aplikaciji da kontroliše vibraciju."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kontrola osvetljenja"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Dozvoljava aplikaciji da kontroliše blic."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"direktno pozivanje brojeva telefona"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Dozvoljava aplikaciji da poziva brojeve telefona bez vaše dozvole. Ovo može da dovede do neočekivanih troškova ili poziva. Imajte na umu da ovo ne dozvoljava aplikaciji da poziva brojeve za hitne slučajeve. Zlonamerne aplikacije mogu da pozivaju bez vaše potvrde, što može da dovede do troškova."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristup usluzi poziva pomoću razmene trenutnih poruka"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index d70f95fcd45b..301e1e33b221 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Разрешава на приложението да прави снимки и видеоклипове с камерата. Това разрешение му позволява да я използва по всяко време без потвърждение от ваша страна."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"контролиране на вибрирането"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Разрешава на приложението да контролира устройството за вибрация."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"контролиране на фенерчето"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Разрешава на приложението да контролира фенерчето."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"директно обаждане до телефонни номера"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Разрешава на приложението да се обажда без ваша намеса до телефонни номера, което може да доведе до неочаквано таксуване или обаждания. Обърнете внимание, че това не му позволява да извършва обаждания до спешните служби. Злонамерените приложения могат да ви въвлекат в разходи, като извършват обаждания без потвърждение от ваша страна."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"достъп до услугата за незабавни съобщения за обаждания"</string> diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml index 683e2ecc437a..9c88d44349c5 100644 --- a/core/res/res/values-bn-rBD/strings.xml +++ b/core/res/res/values-bn-rBD/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"ক্যামেরার সাহায্যে ছবি তুলতে ও ভিডিও তৈরি করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে আপনার নিশ্চয়তা ছাড়াই যেকোনো সময় ক্যামেরা ব্যবহার করতে মঞ্জুর করে৷"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"কম্পন নিয়ন্ত্রণ করুন"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ফ্ল্যাশলাইট নিয়ন্ত্রণ করে"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"অ্যাপ্লিকেশানকে টর্চলাইট নিয়ন্ত্রণ করতে দেয়৷"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"সরাসরি ফোন নম্বরগুলিতে কল করে"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"অ্যাপ্লিকেশানটিকে আপনার হস্তক্ষেপ ছাড়াই ফোন নম্বরগুলিতে কল করতে মঞ্জুর করে৷ এটি অপ্রত্যাশিত পরিমাণ খরচা বা কলের কারণ হতে পারে৷ মনে রাখবেন, এটি অ্যাপ্লিকেশানটির দ্বারা জরুরি নম্বরগুলিতে কল করাকে অনুমতি দেয় না৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার সম্মতি ছাড়াই কল করার ফলে আপনাকে অহেতুক অর্থ প্রদান করতে হতে পারে৷"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS পরিষেবাতে অ্যাক্সেস"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index 786fea1b7b0e..8554b84394a5 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibració"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet que l\'aplicació controli el vibrador."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"controla la llanterna"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet que l\'aplicació controli la llanterna."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"trucar directament a números de telèfon"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet que l\'aplicació truqui a números de telèfon sense la teva intervenció. Aquesta acció pot produir càrrecs o trucades inesperades. Tingues en compte que això no permet que l\'aplicació truqui a números d\'emergència. Les aplicacions malicioses poden fer trucades sense la teva confirmació, cosa que et pot fer gastar diners."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accés al servei de trucades IMS"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index a2e12a39e93a..2eca49a6f7bf 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikaci pořizovat fotografie a videa pomocí fotoaparátu. Toto oprávnění umožňuje aplikaci používat fotoaparát kdykoliv i bez vašeho svolení."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ovládání vibrací"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikaci ovládat vibrace."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikaci ovládat svítilnu."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní čísla"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikaci volat na telefonní čísla bez vašeho přičinění. Může mít za následek neočekávané poplatky nebo hovory. Toto oprávnění neumožňuje aplikaci volat na tísňová čísla. Škodlivé aplikace vás mohou připravit o peníze uskutečňováním hovorů bez vašeho svolení."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"přístup ke službě zasílání rychlých zpráv pro účely hovorů"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 67b8ee9195c0..2a719b011c0e 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Tillader, at appen kan tage billeder og videoer med kameraet. Med denne tilladelse kan appen til enhver tid bruge kameraet uden din bekræftelse."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibration"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Tillader, at appen kan kontrollere vibratoren."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillader, at appen kan kontrollere lommelygten."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ringe direkte op til telefonnumre"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Tillader, at appen kan ringe til telefonnumre uden din indgriben. Dette kan resultere i uventede opkrævninger eller opkald. Bemærk, at appen med denne tilladelse ikke kan ringe til nødopkaldsnumre. Skadelige apps kan koste dig penge ved at foretage opkald uden din bekræftelse."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"få adgang til chat-opkaldstjeneste"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 2d64aee2e5e9..d116a24ee817 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Ermöglicht der App, Bilder und Videos mit der Kamera aufzunehmen. Die Berechtigung erlaubt der App, die Kamera jederzeit und ohne Ihre Bestätigung zu nutzen."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"Vibrationsalarm steuern"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Ermöglicht der App, den Vibrationsalarm zu steuern"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Ermöglicht der App, die Lichtanzeige zu steuern"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Ermöglicht der App, ohne Ihr Eingreifen Telefonnummern zu wählen. Dies kann zu unerwarteten Kosten und Anrufen führen. Beachten Sie, dass die App keine Notrufnummern wählen kann. Schädliche Apps verursachen möglicherweise Kosten, indem sie Anrufe ohne Ihre Bestätigung tätigen."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Zugriff auf IMS-Anrufdienst"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index a1a6ced4debb..8116b16ea4fa 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"έλεγχος δόνησης"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακού"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Επιτρέπει στην εφαρμογή την κλήση αριθμών τηλεφώνου χωρίς δική σας παρέμβαση. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις ή κλήσεις. Έχετε υπόψη ότι δεν επιτρέπεται στην εφαρμογή η κλήση αριθμών έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, πραγματοποιώντας κλήσεις χωρίς την έγκρισή σας."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"πρόσβαση στην υπηρεσία κλήσεων της IMS"</string> diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml index cd2dc23c3715..930c310b9267 100644 --- a/core/res/res/values-en-rAU/strings.xml +++ b/core/res/res/values-en-rAU/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string> diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml index cd2dc23c3715..930c310b9267 100644 --- a/core/res/res/values-en-rGB/strings.xml +++ b/core/res/res/values-en-rGB/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string> diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml index cd2dc23c3715..930c310b9267 100644 --- a/core/res/res/values-en-rIN/strings.xml +++ b/core/res/res/values-en-rIN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index a6f76ace6b18..258ef33fe993 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación saque fotos o grabe videos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la vibración."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas a números de teléfono sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio IMS para realizar llamadas"</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 594fa5065603..9848bb624c26 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación haga fotos o grabe vídeos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la función de vibración."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio de llamadas IMS"</string> diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml index 8ee89048d4d2..466bd5dddfe7 100644 --- a/core/res/res/values-et-rEE/strings.xml +++ b/core/res/res/values-et-rEE/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Võimaldab rakendusel teha kaameraga pilte ja videoid. See luba võimaldab rakendusel kasutada kaamerat mis tahes ajal teie kinnituseta."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"juhtige vibreerimist"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Võimaldab rakendusel juhtida vibreerimist."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"juhi taskulampi"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Võimaldab rakendusel juhtida taskulampi."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"helista otse telefoninumbritele"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Võimaldab rakendusel teie sekkumiseta telefoninumbritele helistada. See võib põhjustada ootamatuid tasusid või telefonikõnesid. Pange tähele, et see ei luba rakendusel helistada hädaabinumbritele. Pahatahtlikud rakendused võivad teile kulusid tekitada, tehes telefonikõnesid teie kinnituseta."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"juurdepääs IMS-kõneteenusele"</string> diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml index e257fe991b59..cdb8622e9a01 100644 --- a/core/res/res/values-eu-rES/strings.xml +++ b/core/res/res/values-eu-rES/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Kamerarekin argazkiak ateratzeko eta bideoak grabatzeko baimena ematen die aplikazioei. Baimen horrekin, aplikazioak kamera edonoiz erabil dezake zure baimenik gabe."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"bibrazioa kontrolatzea"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Bibragailua kontrolatzea baimentzen die aplikazioei."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolatu linterna"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Linterna kontrolatzea baimentzen die aplikazioei."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"deitu zuzenean telefono-zenbakietara"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Telefono-zenbakietara zuk esku hartu gabe deitzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak edo deiak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko deiak eginda gastuak eragiteko."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Atzitu IMS dei-zerbitzua"</string> diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml index b6b669ef77cf..b0da5fe89d48 100644 --- a/core/res/res/values-fa/strings.xml +++ b/core/res/res/values-fa/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"به برنامه اجازه میدهد با دوربین به عکسبرداری و فیلمبرداری بپردازد. این مجوز به برنامه اجازه میدهد از دوربین در هر زمانی بدون تأیید شما استفاده کند."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"کنترل لرزش"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"به برنامه اجازه میدهد تا لرزاننده را کنترل کند."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"کنترل چراغ قوه"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"به برنامه اجازه میدهد تا چراغ قوه را کنترل کند."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"تماس مستقیم با شماره تلفنها"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"به برنامه اجازه میدهد بدون دخالت شما با شمارههای تلفن تماس بگیرد. این ممکن است باعث ایجاد هزینه یا تماسهای پیشبینی نشده شود. توجه داشته باشید که این به برنامه اجازه نمیدهد به برقراری تماسهای اضطراری بپردازد. برنامههای مخرب ممکن است با برقراری تماس بدون تأیید شما هزینههایی را برای شما ایجاد کنند."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"دسترسی به سرویس تماس IMS"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index b0efd9638889..f7db67853a4a 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Antaa sovelluksen ottaa kuvia ja kuvata videoita kameralla. Sovellus voi käyttää kameraa milloin tahansa ilman lupaasi."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"hallitse värinää"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Antaa sovelluksen hallita värinää."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"hallitse taskulamppua"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Antaa sovelluksen hallita taskulamppua."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"soittaa puhelinnumeroihin suoraan"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Antaa sovelluksen soittaa puhelinnumeroihin kysymättä sinulta. Tämä voi aiheuttaa odottamattomia kuluja tai puheluita. Huomaa, että tämä ei anna sovellukselle lupaa soittaa hätänumeroihin. Haitalliset sovellukset voivat aiheuttaa sinulle kuluja soittamalla puheluita ilman lupaa."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pikaviestipalvelun puhelukäyttöoikeus"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 52a47587aa2f..50aed95e9594 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"gérer le vibreur"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de gérer le vibreur de l\'appareil."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"gérer la lampe de poche"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de gérer la lampe de poche."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement des numéros de téléphone"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Des applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 2740f3dec6d0..33d20169adfc 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"contrôler le vibreur"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de contrôler le vibreur."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"contrôler la lampe de poche"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de contrôler la lampe de poche."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement les numéros de téléphone"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Les applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string> diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml index 71ce6e9bffb6..7947825f75bf 100644 --- a/core/res/res/values-gl-rES/strings.xml +++ b/core/res/res/values-gl-rES/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permite á aplicación tomar imaxes e vídeos coa cámara. Con este permiso a aplicación pode utilizar a cámara en calquera momento sen a túa confirmación."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controlar a vibración"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite á aplicación controlar o vibrador."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"controlar a lanterna"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite á aplicación controlar a luz do flash."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"chamar directamente aos números de teléfono"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite á aplicación chamar a números de teléfono sen a túa intervención. Esta acción pode implicar chamadas ou custos inesperados. Ten en conta que isto non permite á aplicación chamar a números de emerxencia. É posible que aplicacións maliciosas che custen diñeiro debido á realización de chamadas sen a túa confirmación."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceso ao servizo de chamadas de IMS"</string> diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml index 8258dc2b4e0d..aa9478bd6158 100644 --- a/core/res/res/values-gu-rIN/strings.xml +++ b/core/res/res/values-gu-rIN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"એપ્લિકેશનને કૅમેરા વડે ચિત્રો અને વિડિઓઝ લેવાની મંજૂરી આપે છે. આ પરવાનગી એપ્લિકેશનને તમારી પુષ્ટિ વિના કોઈપણ સમયે કૅમેરાના ઉપયોગની મંજૂરી આપે છે."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"વાઇબ્રેશન નિયંત્રિત કરો"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"એપ્લિકેશનને વાઇબ્રેટરને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ફ્લેશલાઇટ નિયંત્રિત કરો"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"એપ્લિકેશનને ફ્લેશલાઇટને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"સીધા જ ફોન નંબર્સ પર કૉલ કરો"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"એપ્લિકેશનને તમારા હસ્તક્ષેપ વિના ફોન નંબર્સ પર કૉલ કરવાની મંજૂરી આપે છે. આ અનપેક્ષિત શુલ્ક અથવા કૉલ્સમાં પરિણમી શકે છે. નોંધો કે આ એપ્લિકેશનને કટોકટીના નંબર્સ પર કૉલ કરવાની મંજૂરી આપતું નથી. દુર્ભાવનાપૂર્ણ એપ્લિકેશનો તમારી પુષ્ટિ વિના કૉલ્સ કરીને તમારા પૈસા ખર્ચ કરી શકે છે."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS કૉલ સેવા ઍક્સેસ કરો"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index 3f374ac6dc2c..d3d1e2c2aa10 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"ऐप्स को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति ऐप्स को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करें"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"ऐप्स को कंपनकर्ता नियंत्रित करने देता है."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"फ़्लैशलाइट नियंत्रित करें"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ऐप्स को फ़्लैशलाइट नियंत्रित करने देता है."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"फ़ोन नंबर पर सीधे कॉल करें"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"ऐप्स को आपके हस्तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अप्रत्याशित शुल्क या कॉल हो सकते हैं. ध्यान दें कि यह ऐप्स को आपातकालीन नंबर पर कॉल नहीं करने देता. दुर्भावनापूर्ण ऐप्स आपकी पुष्टि के बिना कॉल करके आपका धन व्यय कर सकते हैं."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवा ऐक्सेस करें"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index bf89366b5f24..dc55c57b5001 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -355,8 +355,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogućuje snimanje slika i videozapisa fotoaparatom. Ta dozvola aplikaciji omogućuje upotrebu fotoaparata u bilo kojem trenutku bez vašeg odobrenja."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"upravljanje vibracijom"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogućuje nadzor nad vibratorom."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"upravljanje svjetiljkom"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogućuje upravljanje svjetiljkom."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"izravno pozivanje telefonskog broja"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogućuje pozivanje telefonskih brojeva bez vašeg sudjelovanja. To može dovesti do neočekivanih troškova ili poziva. Uzmite u obzir da se aplikaciji time ne omogućuje pozivanje brojeva u nuždi. Zlonamjerne aplikacije mogu vam uzrokovati dodatne troškove postavljanjem poziva bez vašeg odobrenja."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristupiti usluzi poziva izravnih poruka"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 64e222958266..3176c6579399 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Lehetővé teszi az alkalmazás számára, hogy a fényképezőgéppel fotókat és videókat készítsen. Az engedéllyel rendelkező alkalmazás bármikor, az Ön jóváhagyása nélkül használhatja a fényképezőgépet."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"rezgés szabályozása"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Lehetővé teszi az alkalmazás számára a rezgés vezérlését."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"vaku vezérlése"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Lehetővé teszi az alkalmazás számára a vaku vezérlését."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"telefonszámok közvetlen hívása"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Lehetővé teszi az alkalmazás számára, hogy az Ön jóváhagyása nélkül hívjon fel telefonszámokat. Ennek eredményeként váratlan terhelésekkel vagy telefonhívásokkal találkozhat. Vegye figyelembe, hogy ez nem teszi lehetővé segélyhívó számok hívását az alkalmazás számára. A rosszindulatú alkalmazások az Ön jóváhagyása nélkül kezdeményezhetnek hívásokat, így költségek merülhetnek fel."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"hozzáférés az IMS-hívásszolgáltatáshoz"</string> diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml index 6fdccd30568b..d72ee8dcfb12 100644 --- a/core/res/res/values-hy-rAM/strings.xml +++ b/core/res/res/values-hy-rAM/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Թույլ է տալիս հավելվածին ֆոտոխցիկով լուսանկարել և տեսանկարել: Այս թույլտվությունը հնարավորություն է տալիս հավելվածին օգտագործել ֆոտոխցիկը ցանկացած ժամանակ` առանց ձեր հաստատման:"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"կառավարել թրթռումը"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Թույլ է տալիս հավելվածին կառավարել թրթռոցը:"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"կառավարել լապտերը"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Թույլ է տալիս հավելվածին կառավարել լապտերը:"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ուղղակիորեն զանգել հեռախոսահամարներին"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Թույլ է տալիս հավելվածին զանգել հեռախոսահամարներին առանց ձեր միջամտության: Սա կարող է հանգեցնել անկանխատեսելի գանձումների կամ զանգերի: Նկատի ունեցեք, որ սա թույլ չի տալիս հավելվածին զանգել արտակարգ իրավիճակների համարներին: Վնասարար հավելվածները կարող են ձեր հաշվից զանգեր կատարել` առանց ձեր հաստատման:"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"օգտվել IMS զանգերի ծառայությունից"</string> diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml index 4960267078b0..024eea4c2ca1 100644 --- a/core/res/res/values-in/strings.xml +++ b/core/res/res/values-in/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Memungkinkan aplikasi mengambil gambar dan video dengan kamera. Izin ini memungkinkan aplikasi menggunakan kamera kapan saja tanpa konfirmasi Anda."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kontrol getaran"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Mengizinkan aplikasi untuk mengendalikan vibrator."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"mengontrol lampu senter"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Mengizinkan apl mengontrol lampu kilat."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"panggil nomor telepon secara langsung"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Memungkinkan aplikasi menghubungi nomor telepon tanpa campur tangan Anda. Izin ini dapat mengakibatkan biaya atau panggilan tak terduga. Perhatikan bahwa izin ini tidak memungkinkan aplikasi menghubungi nomor darurat. Aplikasi berbahaya dapat menyebabkan Anda dikenakan biaya dengan melakukan panggilan tanpa konfirmasi Anda."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses layanan panggilan IMS"</string> diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml index 35ae53da0f6e..240c71558b66 100644 --- a/core/res/res/values-is-rIS/strings.xml +++ b/core/res/res/values-is-rIS/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Leyfir forriti að taka myndir og myndskeið með myndavélinni. Þessi heimild leyfir forritinu að nota myndavélina hvenær sem er án þinnar heimildar."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"stjórna titringi"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Leyfir forriti að stjórna titraranum."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"stjórna vasaljósi"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Leyfir forriti að stjórna vasaljósinu."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"hringja beint í símanúmer"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Leyfir forriti að hringja í símanúmer án íhlutunar notanda. Þetta getur haft í för með sér óumbeðin gjöld og símtöl. Athugaðu að þetta leyfir forritinu ekki að hringja í neyðarnúmer. Spilliforrit geta stofnað til kostnaðar fyrir þig með því að hringja símtöl án þinnar heimildar."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"fá aðgang að IMS-símtalsþjónustu"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index ee1b67d623f7..ece503d74a38 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Consente all\'applicazione di scattare foto e riprendere video con la fotocamera. Questa autorizzazione consente all\'applicazione di utilizzare la fotocamera in qualsiasi momento senza la tua conferma."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controllo vibrazione"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Consente all\'applicazione di controllare la vibrazione."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Consente all\'applicazione di controllare il flash."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Consente all\'applicazione di chiamare numeri di telefono senza il tuo intervento. Ciò può comportare chiamate o addebiti imprevisti. Tieni presente che ciò non consente all\'applicazione di chiamare numeri di emergenza. Applicazioni dannose potrebbero generare dei costi effettuando chiamate senza la tua conferma."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Accesso al servizio di chiamata IMS"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index df0471eadbfb..144afc09bb50 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"מאפשר לאפליקציה לצלם תמונות וסרטונים באמצעות המצלמה. אישור זה מאפשר לאפליקציה להשתמש במצלמה בכל עת ללא אישורך."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"שליטה ברטט"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"מאפשר לאפליקציה לשלוט ברטט."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"שליטה בפנס"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"מאפשר לאפליקציה לשלוט בפנס."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"התקשר ישירות למספרי טלפון"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"מאפשר לאפליקציה להתקשר למספרי טלפון ללא התערבותך. פעולה זו עשויה לגרום לשיחות או לחיובים לא צפויים. שים לב שהדבר לא מאפשר לאפליקציה להתקשר למספרי חירום. אפליקציות זדוניות עשויות לגרום לעלויות על ידי ביצוע שיחות ללא התערבותך."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"גישה אל שירות שיחות IMS"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index 764e0cfe60cc..edfab2281b72 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"カメラでの写真と動画の撮影をアプリに許可します。これにより、アプリが確認なしでいつでもカメラを使用できるようになります。"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"バイブレーションの制御"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"バイブレーションの制御をアプリに許可します。"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ライトのコントロール"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ライトの制御をアプリに許可します。"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"電話番号発信"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS通話サービスへのアクセス"</string> diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml index 0fa786cd04fb..ffdd31c14b5d 100644 --- a/core/res/res/values-ka-rGE/strings.xml +++ b/core/res/res/values-ka-rGE/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"აპს შეეძლება კამერით სურათისა და ვიდეოს გადაღება. ეს ნებართვა აპს უფლებას აძლევს, ნებისმიერ დროს გამოიყენოს კამერა თქვენი დადასტურების გარეშე."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ვიბრაციის კონტროლი"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"აპს შეეძლება, მართოს ვიბრირება."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ფანრის მართვა"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"აპს შეეძლება, მართოს განათება."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"პირდაპირი დარეკვა ტელეფონის ნომრებზე"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"აპს შეეძლება დარეკოს ტელეფონის ნომრებზე თქვენი ჩარევის გარეშე. ამან შესაძლოა გამოიწვიოს თქვენს სატელეფონი ქვითარზე მოულოდნელი ხარჯებისა და ზარების გაჩენა. გაითვალისწინეთ, რომ აპს გადაუდებელი დახმარების ნომრებზე დარეკვა არ შეუძლია. მავნე აპებს შეეძლება თქვენი დადასტურების გარეშე ზარების განხორციელება და შესაბამისი საფასურის გადახდაც მოგიწევთ."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ზარების სერვისზე წვდომა"</string> diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml index 275e5bcbab3a..ff58eaadc82d 100644 --- a/core/res/res/values-kk-rKZ/strings.xml +++ b/core/res/res/values-kk-rKZ/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Қолданбаға камераны қолданып, фотосурет немесе бейне жазу мүмкіндігін береді. Бұл рұқсат камераны кез келген уақытта сіздің құптауыңызды қажет етпей қолдану мүмкіндігін береді."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"тербелісті басқару"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Қолданбаға вибраторды басқаруға рұқсат береді."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"сигналдық шамды басқару"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Қолданбаға қалта шамын басқаруға рұқсат береді."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"нөмірлерге тікелей телефон шалу"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Қолданбаға сіздің қатысуыңызсыз қоңырау шалу мүмкіндігін береді. Нәтижесінде қосымша төлем немесе күтпеген қоңырау алуыңыз мүмкін. Есіңізде болсын, қолданба төтенше байланыстарға қоңырау шала алмайды. Залалды қолданбалар сіздің рұқсатыңызсыз қоңыраулар шалып, күтпеген төлемдерге себеп болуы мүмкін."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS қоңырау қызметін пайдалану"</string> diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml index 96abf450cdad..261212fa79bf 100644 --- a/core/res/res/values-km-rKH/strings.xml +++ b/core/res/res/values-km-rKH/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"ឲ្យកម្មវិធីថតរូប និងវីដេអូដោយប្រើម៉ាស៊ីនថត។ វាឲ្យកម្មវិធីប្រើម៉ាស៊ីនថតនៅពេលណាមួយដោយគ្មានការបញ្ជាក់របស់អ្នក។"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ពិនិត្យការញ័រ"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"ឲ្យកម្មវិធីគ្រប់គ្រងកម្មវិធីញ័រ។"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ត្រួតពិនិត្យពិល"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ឲ្យកម្មវិធីពិនិត្យពិល។"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ហៅលេខទូរស័ព្ទដោយផ្ទាល់"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"ឲ្យកម្មវិធីហៅលេខទូរស័ព្ទដោយគ្មានសកម្មភាពរបស់អ្នក។ វាអាចកាត់លុយ ឬហៅដោយមិនរំពឹងទុក។ ចំណាំថា វាមិនអនុញ្ញាតឲ្យកម្មវិធីហៅលេខពេលអាសន្នទេ។ កម្មវិធីព្យាបាទអាចកាត់លុយរបស់អ្នក ដោយធ្វើការហៅដោយគ្មានការបញ្ជាក់របស់អ្នក។"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"ចូលដំណើរការសេវាកម្មការហៅតាម IMS"</string> diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml index d0dac23cb538..f083702d66ae 100644 --- a/core/res/res/values-kn-rIN/strings.xml +++ b/core/res/res/values-kn-rIN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"ಕ್ಯಾಮರಾ ಮೂಲಕ ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ವೈಬ್ರೇಷನ್ ನಿಯಂತ್ರಿಸಿ"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"ವೈಬ್ರೇಟರ್ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ಫ್ಲ್ಯಾಶ್ಲೈಟ್ ನಿಯಂತ್ರಿಸಿ"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ಫ್ಲ್ಯಾಶ್ಲೈಟ್ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ನೇರವಾಗಿ ಕರೆ ಮಾಡಿ"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"ನಿಮ್ಮ ಹಸ್ತಕ್ಷೇಪ ಇಲ್ಲದೆಯೇ ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ಅನಿರೀಕ್ಷಿತ ಶುಲ್ಕಗಳು ಅಥವಾ ಕರೆಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು. ತುರ್ತು ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆಮಾಡಲು ಈ ಅಪ್ಲಿಕೇಶನ್ ಅನುಮತಿಸುವುದಿಲ್ಲ ಎಂಬುದು ಗಮನದಲ್ಲಿರಲಿ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್ಗಳು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಕರೆಗಳನ್ನು ಮಾಡುವುದರ ಮೂಲಕ ನಿಮ್ಮ ಹಣ ಖರ್ಚಾಗಬಹುದು."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ಕರೆ ಸೇವೆಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index b1b45883e977..c8f08c77cf8b 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"앱이 카메라로 사진과 동영상을 찍을 수 있도록 허용합니다. 이 권한을 사용하면 앱이 언제든지 사용자의 확인 없이 카메라를 사용할 수 있습니다."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"진동 제어"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"앱이 진동을 제어할 수 있도록 허용합니다."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"카메라 플래시 제어"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"앱이 카메라 플래시를 제어할 수 있도록 허용합니다."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"전화번호 자동 연결"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"앱이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 허용합니다. 이 경우 예상치 못한 통화 요금이 부과될 수 있습니다. 앱이 비상 전화를 걸도록 하는 권한은 주어지지 않습니다. 악성 앱이 사용자의 확인 없이 전화를 걸어 요금이 부과될 수 있습니다."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS 통화 서비스에 액세스"</string> diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml index 7644a9b32381..4d8493395b07 100644 --- a/core/res/res/values-ky-rKG/strings.xml +++ b/core/res/res/values-ky-rKG/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Колдонмого камера аркылуу видео жана сүрөт тартуу уруксатын берет. Бул уруксат, камераны каалаган убакта, сиздин ырастооңузсуз колдонуу уруксатын берет."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"титирөөнү башкаруу"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Колдонмого дирилдегичти көзөмөлдөө мүмкүнчүлүгүн берет."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"кол чыракты көзөмөлдөө"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Колдонмого колчыракты көзөмөлдөө мүмкүнчүлүгүн берет."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"телефон номерлерине түз чалуу"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Колдонмого сиздин катышууңузсуз телефон номурларга чалуу уруксатын берет. Бул сиз күтпөгөн чыгымдарга же чалууларга алып келиши мүмкүн. Бул куткаруучулардын номурларына чалууга уруксат бербей тургандыгын эске алыңыз. Зыяндуу колдонмолор, сиздин ырастооңузсуз чалууларды аткарып, көп чыгымдарга себепкер болушу мүмкүн."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS чалуу кызматына мүмкүнчүлүк алуу"</string> diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml index a5ff8d18dfa7..12d67bb2d2bf 100644 --- a/core/res/res/values-lo-rLA/strings.xml +++ b/core/res/res/values-lo-rLA/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"ອະນຸຍາດໃຫ້ແອັບຯຖ່າຍຮູບ ແລະວິດີໂອດ້ວຍກ້ອງຖ່າຍຮູບ. ການອະນຸຍາດນີ້ຈະອານຸຍາດໃຫ້ແອັບຯ ສາມາດໃຊ້ກ້ອງຖ່າຍຮູບໄດ້ຕະຫລອດເວລາ ໂດຍບໍ່ຕ້ອງຖ້າການຢືນຢັນຈາກທ່ານ."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ຄວບຄຸມການສັ່ນ"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມໂຕສັ່ນ."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ຄວບຄຸມໄຟແຟລດ"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມໄຟແຟລດ."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ໂທຫາເບີໂທລະສັບໂດຍກົງ"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"ອະນຸຍາດໃຫ້ແອັບຯໂທຫາເບີໂທລະສັບໄດ້ ໂດຍບໍ່ຕ້ອງຖ້າການດຳເນີນການໃດໆຈາກທ່ານ. ຄຸນສົມບັດນີ້ອາດກໍ່ໃຫ້ເກີດຄ່າໃຊ້ຈ່າຍໃນການໂທທີ່ບໍ່ຄາດຄິດໄດ້. ໝາຍເຫດ: ຄຸນສົມບັດນີ້ບໍ່ໄດ້ເປັນການອະນຸຍາດໃຫ້ແອັບຯ ສາມາດໂທຫາເບີສຸກເສີນ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດເຮັດໃຫ້ທ່ານ ຕ້ອງເສຍຄ່າໂທໂດຍທີ່ບໍ່ໄດ້ຄາດຄິດ."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"ເຂົ້າຫາການບໍລິການໂທ IMS"</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index f59e7542f2dd..e35edd6aa539 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Leidžiama programai fotografuoti ir filmuoti kamera. Šis leidimas suteikia teisę programai naudoti kamerą bet kada be jūsų patvirtinimo."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"valdyti vibraciją"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Leidžiama programai valdyti vibravimą."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"valdyti šviesos signalą"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Leidžiama programai valdyti šviesos signalą."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"skambinti tiesiogiai telefono numeriais"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Leidžiama programai skambinti telefonų numeriais be jūsų įsikišimo. Dėl to gali atsirasti nenumatytų apmokestinimų ar skambučių. Atminkite, kad programai neleidžiama skambinti pagalbos telefonų numeriais. Kenkėjiškos programos gali skambinti be jūsų patvirtinimo, o dėl to jums gali būti taikomi mokesčiai."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pasiekti IMS skambučių paslaugą"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index d1993edff0b9..de02a4f86796 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -355,8 +355,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Ļauj lietotnei uzņemt attēlus un videoklipus ar kameru. Ar šo atļauju lietotne var jebkurā brīdī izmantot kameru bez jūsu apstiprinājuma."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kontrolēt vibrosignālu"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Ļauj lietotnei kontrolēt vibrosignālu."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolēt uzliesmojumu"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Ļauj lietotnei kontrolēt zibspuldzi."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"tieši zvanīt uz tālruņa numuriem"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Ļauj lietotnei zvanīt uz tālruņa numuriem bez jūsu iejaukšanās. Tas var radīt neparedzētas izmaksas vai zvanus. Ņemiet vērā, ka lietotnei nav atļauts zvanīt uz tālruņa numuriem ārkārtas situācijām. Ļaunprātīgas lietotnes var radīt jums izmaksas, veicot zvanus bez jūsu apstiprinājuma."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"piekļūt tūlītējās ziņojumapmaiņas pakalpojumam, lai veiktu zvanus"</string> diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml index 672c2b525912..96a29a59bf08 100644 --- a/core/res/res/values-mk-rMK/strings.xml +++ b/core/res/res/values-mk-rMK/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Овозможува апликацијата да прави фотографии и да снима видеа со камерата. Оваа дозвола овозможува апликацијата да ја користи камерата во кое било време без ваша потврда."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"контролирај вибрации"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволува апликацијата да ги контролира вибрациите."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"контролирај сијаличка"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволува апликацијата да ја контролира батериската ламба."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"директно избирај телефонски броеви"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Овозможува апликацијата да повикува телефонски броеви без ваша интервенција. Ова може да предизвика неочекувани трошоци или повици. Имајте на ум дека ова не дозволува апликацијата да повикува броеви на служби за итна помош. Злонамерните апликации може да ве чинат пари поради повици без ваша потврда."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"пристапи до услугата за повици IMS"</string> diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml index c6f6698bbe1d..f6869e38a169 100644 --- a/core/res/res/values-ml-rIN/strings.xml +++ b/core/res/res/values-ml-rIN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ ഏതുസമയത്തും ക്യാമറ ഉപയോഗിക്കാൻ ഈ അനുമതി അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"വൈബ്രേറ്റുചെയ്യൽ നിയന്ത്രിക്കുക"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"വൈബ്രേറ്റർ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ടോർച്ച് നിയന്ത്രിക്കുക"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ഫ്ലാഷ്ലൈറ്റിനെ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ഫോൺ നമ്പറുകളിലേക്ക് നേരിട്ട് വിളിക്കുക"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"നിങ്ങളുടെ ഇടപെടൽ ഇല്ലാതെ ഫോൺ നമ്പറുകളിലേക്ക് കോൾ ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് അപ്രതീക്ഷിത നിരക്കുകൾക്കോ കോളുകൾക്കോ ഇടയാക്കാം. ഇത് അടിയന്തര നമ്പറുകളിലേക്ക് വിളിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കില്ലെന്ന കാര്യം ശ്രദ്ധിക്കുക. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ കോളുകൾ ചെയ്യുന്നത് പണച്ചെലവിനിടയാക്കാം."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS കോൾ സേവനം ആക്സസ് ചെയ്യുക"</string> diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml index c42beca3e221..d982eceb6aac 100644 --- a/core/res/res/values-mn-rMN/strings.xml +++ b/core/res/res/values-mn-rMN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Апп нь камераар зураг авах болон видео бичих боломжтой. Энэ зөвшөөрөл нь апп-д ямар ч үед таны зөвшөөрөлгүйгээр камер ашиглах боломжийг олгоно."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"чичиргээг удирдах"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Апп нь чичиргээг удирдах боломжтой."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"гар чийдэн удирдах"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Апп нь гар чийдэнг удирдах боломжтой."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"утасны дугаарт шууд дуудлага хийх"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Апп нь таны оролцоогүйгээр дуудлага хийх боломжтой. Энэ нь төлөвлөгдөөгүй төлбөрт оруулах эсвэл дуудлага хийнэ. Энэ нь апп-г яаралтай дугаарт дуудлага хийхйг зөвшөөрөхгүй. Хортой апп нь таны зөвшөөрөлгүйгээр дуудлага хийж таныг төлбөрт оруулж болзошгүй"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS дуудлагын үйлчилгээнд хандах"</string> diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml index 8bc86e63d0d0..408719926ba9 100644 --- a/core/res/res/values-mr-rIN/strings.xml +++ b/core/res/res/values-mr-rIN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"कॅमेर्यासह चित्रे आणि व्हिडिओ घेण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपल्या पुष्टीकरणाशिवाय कोणत्याही वेळी कॅमेरा वापरण्यासाठी अॅप ला परवानगी देते."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करा"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"अॅप ला व्हायब्रेटर नियंत्रित करण्यासाठी अनुमती देते."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"फ्लॅशलाइट नियंत्रित करा"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्लॅशलाइट नियंत्रित करण्यासाठी अॅप ला अनुमती देते."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"फोन नंबरवर प्रत्यक्ष कॉल करा"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"आपल्या हस्तक्षेपाशिवाय फोन नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देते. यामुळे अनपेक्षित शुल्क किंवा कॉल लागू शकतात. लक्षात ठेवा की हे आणीबाणीच्या नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देत नाही. दुर्भावनापूर्ण अॅप्स नी आपल्या पुष्टिकरणाशिवाय कॉल केल्यामुळे आपले पैसे खर्च होऊ शकतात."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवेमध्ये प्रवेश करा"</string> diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml index f1249d6201af..0923e912b215 100644 --- a/core/res/res/values-ms-rMY/strings.xml +++ b/core/res/res/values-ms-rMY/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Membenarkan apl mengambil gambar dan video menggunakan kamera. Kebenaran ini membenarkan apl untuk menggunakan kamera pada bila-bila masa tanpa pengesahan anda."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kawal getaran"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Membenarkan apl mengawal penggetar."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"mengawal lampu suluh"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Membenarkan apl mengawal lampu suluh."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"panggil terus nombor telefon"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Membenarkan apl memanggil nombor telefon tanpa campur tangan anda. Ini mungkin menyebabkan caj atau panggilan yang di luar jangkaan. Apl hasad boleh menyebabkan anda kerugian wang dengan membuat panggilan tanpa pengesahan anda."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses perkhidmatan panggilan IMS"</string> diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml index 3393e1289448..3ef7e6cb8d8c 100644 --- a/core/res/res/values-my-rMM/strings.xml +++ b/core/res/res/values-my-rMM/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"အပလီကေးရှင်းအား အလိုအလျောက် ဓာတ်ပုံရိုက်ခွင့်၊ ဗီဒီယို ရိုက်ကူးခွင့် ပြုပါ။ ဒီခွင့်ပြုချက်က အပလီကေးရှင်းကို အချိန်မရွေး ကင်မရာအား ခွင့်ပြုချက် မလိုအပ်ပဲ သုံးခွင့်ပြုပါသည်။"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"တုန်ခုန်မှုအား ထိန်းချုပ်ခြင်း"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"appအား တုန်ခါစက်ကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ဓါတ်မီးအား ထိန်းသိမ်းရန်"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"appအား ကား ဖလက်ရှမီးကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ဖုန်းနံပါတ်များကိုတိုက်ရိုက်ခေါ်ဆိုခြင်း"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"အပလီကေးရှင်းအား အလိုအလျောက် ဖုန်းခေါ်ခွင့် ပြုပါ။ မလိုအပ်သော ဖုန်းခ များ ဖြစ်ပေါ်နိုင်ပါသည်။ ဒီခွင့်ပြုခြင်းမှာ အရေးပေါ်ဖုန်းခေါ်ခြင်း မပါဝင်ပါ။ သံသယဖြစ်စရာ အပလီကေးရှင်းများက သင့်မသိပဲ ဖုန်းခေါ်ခြင်းဖြင့် ဖုန်းခ ပိုမိုကျနိုင်ပါသည်။"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ဖုန်းခေါ်ဆိုမှု ဝန်ဆောင်ဌာန ဝင်ကြည့်ပါ"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index e1ad565bd343..cd65d85255e9 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Appen tillates å ta bilder og filme med kameraet. Det betyr at appen kan bruke kameraet når som helst uten bekreftelse fra deg."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibreringen"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Lar appen kontrollere vibreringsfunksjonen."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Lar appen kontrollere lommelykten."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ringe telefonnummer direkte"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Lar appen ringe telefonnumre uten at du gjør noe. Dette kan resultere i uventede oppringninger og kostnader. Appen kan imidlertid ikke ringe nødnumre. Merk at skadelige apper kan påføre deg kostnader ved å ringe uten bekreftelse fra deg."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"få tilgang til nettprattjenesten for ringing"</string> diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml index f94222b16ce1..301094b75d03 100644 --- a/core/res/res/values-ne-rNP/strings.xml +++ b/core/res/res/values-ne-rNP/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"अनुप्रयोगलाई क्यामेरासँग तस्बिर र भिडियोहरू लिन अनुमति दिन्छ। यस अनुमतिले अनुप्रयोगलाई तपाईंको पुष्टिकरण बिना कुनै पनि समयमा क्यामेरा प्रयोग गर्न स्वीकृति दिन्छ।"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"कम्पन नियन्त्रण गर्नुहोस्"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"अनुप्रयोगलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"फ्ल्यासलाईट नियन्त्रण गर्नुहोस्"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्ल्यास प्रकाशलाई नियन्त्रण गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"फोन नम्बरहरूमा सिधै कल गर्नुहोस्"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"तपाईँको हस्तक्षेप बेगरै फोन नम्बर कल गर्न अनुप्रयोगलाई अनुमति दिन्छ। यसले अनपेक्षित शुल्क वा कलहरू गराउन सक्छ। यसले अनुप्रयोगलाई आपतकालीन नम्बरहरू कल गर्न अनुमति दिँदैन विचार गर्नुहोस्। खराब अनुप्रयोगहरूले तपाईँको स्वीकार बिना कलहरू गरेर तपाईँलाई बढी पैसा तिराउन सक्छ।"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कल सेवा पहुँच गर्नुहोस्"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 1bef95d92ba4..1407991d68bf 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Hiermee kan de app foto\'s en video\'s maken met de camera. Met deze toestemming kan de app de camera altijd gebruiken, zonder je bevestiging."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"trilling beheren"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Hiermee kan de app de trilstand beheren."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Hiermee kan de app de zaklamp bedienen."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Hiermee kan de app zonder je tussenkomst telefoonnummers bellen. Dit kan tot onverwachte kosten of oproepen leiden. De app kan hiermee geen noodnummers bellen. Schadelijke apps kunnen u geld kosten door nummers te bellen zonder om je bevestiging te vragen."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot IMS-service voor bellen"</string> diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml index 168c66f31570..39f20f5fba52 100644 --- a/core/res/res/values-pa-rIN/strings.xml +++ b/core/res/res/values-pa-rIN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"ਐਪ ਨੂੰ ਕੈਮਰੇ ਨਾਲ ਤਸਵੀਰਾਂ ਅਤੇ ਵੀਡੀਓ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਕੈਮਰਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ਵਾਈਬ੍ਰੇਸ਼ਨ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"ਐਪ ਨੂੰ ਵਾਈਬ੍ਰੇਟਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ਐਪ ਨੂੰ ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਸਿੱਧੇ ਕਾਲ ਕਰੋ"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦੇ ਸਿੱਟੇ ਵਜੋਂ ਅਕਲਪਿਤ ਖ਼ਰਚੇ ਜਾਂ ਕਾਲਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਧਿਆਨ ਦਿਓ ਕਿ ਇਹ ਐਪ ਨੂੰ ਐਮਰਜੈਂਸੀ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦਾ। ਖ਼ਰਾਬ ਐਪਸ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਾਲਾਂ ਕਰਕੇ ਤੁਹਾਨੂੰ ਖ਼ਰਚੇ ਪਾ ਸਕਦੇ ਹਨ।"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ਕਾਲ ਸੇਵਾ ਤੱਕ ਪਹੁੰਚ"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index 80ef7df29f74..f3e50b56815f 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Pozwala aplikacji na robienie zdjęć i nagrywanie filmów przy użyciu aparatu. Aplikacja z tym uprawnieniem może użyć aparatu w dowolnym momencie bez Twojego potwierdzenia."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"sterowanie wibracjami"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Pozwala aplikacji na sterowanie wibracjami."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Pozwala aplikacji na sterowanie latarką."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"bezpośrednie wybieranie numerów telefonów"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Pozwala aplikacji na dzwonienie pod numery telefonów bez Twojej wiedzy. Może to skutkować nieoczekiwanymi opłatami lub połączeniami. Aplikacja nie może dzwonić pod numery alarmowe. Złośliwe aplikacje mogą generować koszty, wykonując połączenia bez Twojego potwierdzenia."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"usługa telefoniczna z dostępem do komunikatora"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 11e060a0baf5..89bbbe82d714 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index d76133ab1808..f559dbb3ef1e 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permite que a aplicação tire fotografias e grave vídeos com a câmara. Esta autorização permite que a aplicação utilize a câmara sem a sua confirmação em qualquer altura."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite à aplicação controlar o vibrador."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite à aplicação controlar a lanterna."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que a aplicação ligue para números de telefone sem a intervenção do utilizador. Esta ação pode resultar em cobranças ou chamadas inesperadas. Tenha em atenção que isto não permite que a aplicação ligue para números de emergência. As aplicações maliciosas podem fazer com que incorra em custos, fazendo chamadas sem a sua confirmação."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"aceder ao serviço de chamadas IMS"</string> @@ -1478,7 +1476,7 @@ <item quantity="one">Durante 1 h</item> </plurals> <string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string> - <string name="zen_mode_alarm" msgid="9128205721301330797">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string> + <string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string> <string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string> <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Até desativar Não incomodar"</string> <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 11e060a0baf5..89bbbe82d714 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 8a78f17c380f..4086e69e2e2f 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -355,8 +355,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Permite aplicației să realizeze fotografii și videoclipuri cu camera foto. Cu această permisiune aplicația utilizează camera foto oricând și fără confirmare."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"controlează vibrarea"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite aplicației să controleze mecanismul de vibrare."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"control lanternă"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite aplicației să controleze lanterna."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 0753e93c8307..ee39b83a7166 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Приложение сможет снимать фотографии и видеоролики с помощью камеры в любое время без вашего разрешения."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"Управление функцией вибросигнала"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Приложение сможет контролировать вибросигналы."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"Управление вспышкой"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Приложение сможет контролировать вспышку."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"Осуществление телефонных вызовов"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Приложение сможет без вашего участия звонить на любой номер телефона. Это не относится к номерам экстренных служб. Вредоносные программы смогут совершать вызовы без вашего разрешения, что может привести к непредвиденным расходам."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"совершение звонков с помощью службы IMS"</string> diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml index d66b2453d1d4..5364c98dfd7e 100644 --- a/core/res/res/values-si-rLK/strings.xml +++ b/core/res/res/values-si-rLK/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"කැමරාවෙන් පින්තූර ගැනීමට සහ වීඩියෝ කිරීමට යෙදුමට අවසර දෙන්න. මෙම අවසරය මඟින් ඔබගේ අනුදැනුමකින් තොරව ඕනෑම වේලාවකදී කැමරාව භාවිතා කිරීමට යෙදුමට අවසර දෙන්න."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"කම්පනය පාලනය කිරීම"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"කම්පකය පාලනයට යෙදුමට අවසර දෙන්න."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"සැණෙළි ආලෝකය පාලනය කරන්න"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"සැණෙළිය පාලනයට යෙදුමට අවසර දෙන්න."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"දුරකථන අංක වෙත ඍජුවම අමතන්න"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"ඔබගේ මැදිහත් වීමක් නොමැතිව දුරකථන අංක ඇමතීමට යෙදුමට අවසර දෙන්න. මෙහි ප්රතිඑලය වන්නේ අනපේක්ෂිත අයකිරීම් හෝ ඇමතුම් ඇතිවීමයි. මෙයන් හදිසි අංක වලට ඇමතුම් ගැනීමට යෙදුමට අවසර නොදෙන බවට සටහන් කරගන්න. ඔබගේ අනුදැනුමක් නොමැතිව ඇමතුම් ගැනීමෙන් අනිෂ්ට යෙදුම් ඔබගේ මුදල් නිකරුණේ වැය කරයි."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ඇමතුම් සේවාවට පිවිසෙන්න"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 05c846705bd2..90ccd543a99c 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ovládať vibrovanie"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikácii ovládať vibrácie."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ovládať kontrolku"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikácii ovládať svetlo."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"priamo volať na telefónne čísla"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikácii volať telefónne čísla bez vášho zásahu. V dôsledku toho sa môžu účtovať neočakávané poplatky alebo sa môžu uskutočniť neočakávané hovory. Toto povolenie neumožňuje aplikácii volať na čísla tiesňového volania."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"prístup k službe volania IMS"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index ea5f4c43e192..4e9b1c55c03f 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogoča fotografiranje in snemanje videoposnetkov s kamero. S tem dovoljenjem lahko aplikacija kadar koli uporablja kamero brez vaše potrditve."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"nadzor vibriranja"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogoča nadzor vibriranja."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"nadzor svetilke"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogoča nadzor svetilke."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"neposredno klicanje telefonskih številk"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogoča klicanje telefonskih številk brez vašega posredovanja. Zaradi tega lahko pride do nepričakovanih stroškov ali klicev. Aplikaciji to ne dovoljuje opravljanja klicev v sili. Zlonamerne aplikacije lahko kličejo brez vaše potrditve, kar vas lahko drago stane."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"dostop do storitve za klicanje IMS"</string> diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml index 77e0e62b9229..be9c709cd398 100644 --- a/core/res/res/values-sq-rAL/strings.xml +++ b/core/res/res/values-sq-rAL/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Lejon aplikacion të krijojë fotografi dhe video me kamerën. Kjo leje mundëson përdorimin e kamerës në çdo kohë pa konfirmimin tënd."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollo dridhjen"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Lejon aplikacionin të kontrollojë dridhësin."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollo elektrikun"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Lejon aplikacionin të kontrollojë elektrikun."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"telefono drejtpërdrejt numrat e telefonit"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Lejon aplikacionin të telefonojë numra pa ndërhyrjen tënde. Kjo mund të rezultojë në tarifa ose telefonata të papritura. Ki parasysh se kjo nuk e lejon aplikacionin të telefonojë numra urgjence. Aplikacione keqdashëse mund të të kushtojnë para duke kryer telefonata pa konfirmimin tënd."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"qasje në shërbimin e telefonatave IMS"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index 242341843b0c..a3618ab5e2f2 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -355,8 +355,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Дозвољава апликацији да снима слике и видео снимке камером. Ова дозвола омогућава апликацији да у било ком тренутку користи камеру без ваше потврде."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"контрола вибрације"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозвољава апликацији да контролише вибрацију."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"контрола осветљења"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозвољава апликацији да контролише блиц."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"директно позивање бројева телефона"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Дозвољава апликацији да позива бројеве телефона без ваше дозволе. Ово може да доведе до неочекиваних трошкова или позива. Имајте на уму да ово не дозвољава апликацији да позива бројеве за хитне случајеве. Злонамерне апликације могу да позивају без ваше потврде, што може да доведе до трошкова."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"приступ услузи позива помоћу размене тренутних порука"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index cdf252e7f359..b07dc285e128 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Tillåter att appen tar bilder och spelar in videor med kameran. Med den här behörigheten tillåts appen att använda kameran när som helst utan ditt godkännande."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"styra vibration"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Tillåter att appen styr vibrationen."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillåter att appen styr lampan."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ringa telefonnummer direkt"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Tillåter att appen ringer telefonnummer utan någon aktiv åtgärd från dig. Detta kan leda till oväntade avgifter och samtal. Observera att appen inte tillåts ringa nödsamtal. Skadliga appar kan ringa utan ditt godkännande och detta kan kosta pengar."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"tillgång till tjänsten för snabbmeddelanden vid samtal"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index 5e618bfd0a2c..cf0063c7254a 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Inaruhusu programu kupiga picha na video kwa kamera. Kibali hiki kinaruhusu programu kutumia kamera kwa wakati wowote bila uthibitisho wako."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"Kudhibiti mtetemo"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Inaruhusu programu kudhibiti kitingishi."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"dhibiti tochi"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Inaruhusu programu kudhibiti tochi."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"piga simu moja kwa moja kwa nambari za simu"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Inaruhusu programu kupiga nambari za simu bila ya wewe kuingilia kati. Hii inaweza kusababisha gharama zisizotarajiwa au simu. Kumbuka kuwa hii hairuhusu programu kupiga nambari za dharura. Programu hasidi zinaweza kukugharimu pesa kwa kupiga simu bila uthibitisho wako."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"fikia huduma ya simu ya IMS"</string> @@ -795,7 +793,7 @@ <string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string> <string name="save_password_never" msgid="8274330296785855105">"Katu"</string> <string name="open_permission_deny" msgid="7374036708316629800">"Hauna idhini ya kufungua ukurasa huu."</string> - <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao klipu."</string> + <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao wa kunakili."</string> <string name="more_item_label" msgid="4650918923083320495">"Zaidi"</string> <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menyu+"</string> <string name="menu_space_shortcut_label" msgid="2410328639272162537">"mwanya"</string> diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml index 7e0ab5eb88dc..ecefb7755f4e 100644 --- a/core/res/res/values-ta-rIN/strings.xml +++ b/core/res/res/values-ta-rIN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"கேமரா மூலமாகப் படங்களையும், வீடியோக்களையும் எடுக்க பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இன்றி கேமராவை எந்நேரத்திலும் பயன்படுத்தப் பயன்பாட்டை இது அனுமதிக்கிறது."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"அதிர்வைக் கட்டுப்படுத்துதல்"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"அதிர்வைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ஃப்லாஷ்லைட்டை இயக்குதல்"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ஃப்ளாஷ் லைட்டைக் கட்டுப்படுத்த, பயன்பாட்டை அனுமதிக்கிறது."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"தொலைபேசி எண்களை நேரடியாக அழைத்தல்"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"உங்கள் தலையீட்டின்றி மொபைல் எண்களை அழைக்கப் பயன்பாட்டை அனுமதிக்கிறது. இதன் விளைவாக எதிர்பாராத கட்டணங்களோ அழைப்புகளோ ஏற்படலாம். அவசரகால எண்களை அழைக்க இது பயன்பாட்டை அனுமதிக்காது என்பதை நினைவில்கொள்ளவும். தீங்கிழைக்கும் பயன்பாடுகள், உங்கள் உறுதிப்படுத்தல் இன்றி அழைப்புகளைச் செய்வதால் உங்களுக்குச் செலவு ஏற்படக்கூடும்."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS அழைப்புச் சேவையை அணுகுதல்"</string> diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml index 87b782fff2b9..b1bccd2987d7 100644 --- a/core/res/res/values-te-rIN/strings.xml +++ b/core/res/res/values-te-rIN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"కెమెరాతో చిత్రాలు మరియు వీడియోలను తీయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి మీ నిర్ధారణ లేకుండానే ఎప్పుడైనా కెమెరాను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"వైబ్రేషన్ను నియంత్రించడం"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"వైబ్రేటర్ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ఫ్లాష్కాంతిని నియంత్రించడం"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ఫ్లాష్లైట్ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ఫోన్ నంబర్లకు నేరుగా కాల్ చేయడం"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్లు రావచ్చు. ఇది అత్యవసర నంబర్లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతించదని గుర్తుంచుకోండి. హానికరమైన అనువర్తనాలు మీ నిర్ధారణ లేకుండానే కాల్లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS కాల్ సేవ ప్రాప్యత అనుమతి"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 2ec0f4c51ced..0b8e60d68987 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"อนุญาตให้แอปพลิเคชันถ่ายภาพและวิดีโอด้วยกล้องถ่ายรูปนี้ การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถใช้กล้องถ่ายรูปได้ทุกเมื่อโดยไม่ต้องรอการยืนยันจากคุณ"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ควบคุมการสั่นเตือน"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"ควบคุมไฟฉาย"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"อนุญาตให้แอปพลิเคชันควบคุมไฟฉาย"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"โทรติดต่อหมายเลขโทรศัพท์โดยตรง"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"อนุญาตให้แอปพลิเคชันโทรเข้าโทรศัพท์โดยไม่ต้องให้คุณจัดการ ซึ่งอาจทำให้มีการเรียกเก็บเงินหรือการโทรที่ไม่คาดคิด โปรดทราบว่าการทำงานนี้ไม่ได้อนุญาตให้แอปพลิเคชันโทรไปหมายเลขฉุกเฉิน แอปพลิเคชันที่เป็นอันตรายอาจทำให้คุณต้องเสียค่าบริการด้วยการโทรโดยไม่ขอการยืนยันจากคุณ"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"เข้าถึงบริการโทร IMS"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 36aa9d95dee9..02a3587759d9 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Pinapayagan ang app na kumuha ng mga larawan at video gamit ang camera. Pinapayagan ng pahintulot na ito ang app na gamitin ang camera anumang oras nang wala ng iyong kumpirmasyon."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kontrolin ang pag-vibrate"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Pinapayagan ang app na kontrolin ang vibrator."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolin ang flashlight"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Pinapayagan ang app na kontrolin ang flashlight."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"direktang tawagan ang mga numero ng telepono"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Pinapayagan ang app na tumawag sa mga numero ng telepono nang wala ng iyong panghihimasok. Maaari itong magresulta sa mga hindi inaasahang pagsingil o tawag. Tandaan na hindi nito pinapayagan ang app na tumawag sa mga numerong pang-emergency. Maaaring magpagastos sa iyo ng pera ang nakakahamak na apps sa pamamagitan ng pagtawag nang wala ng iyong kumpirmasyon."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"i-access ang serbisyo sa tawag ng IMS"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 7b0bdc681135..283bcebb887d 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Uygulamaya kamerayla fotoğraf ve video çekme izni verir. Bu izin, uygulamanın sizin onayınız olmadan istediği zaman kamerayı kullanmasına olanak sağlar."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"titreşimi denetleme"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Uygulamaya, titreşimi denetleme izni verir."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"el fenerini denetle"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Uygulamaya, el fenerini denetleme izni verir."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarına doğrudan çağrı yap"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Uygulamaya sizin müdahaleniz olmadan telefon numaralarına çağrı yapma izni verir. Bu durum beklenmeyen ödemelere veya çağrılara neden olabilir. Ancak bu iznin, uygulamanın acil numaralara çağrı yapmasına olanak sağlamadığını unutmayın. Kötü amaçlı uygulamalar onayınız olmadan çağrılar yaparak sizi zarara sokabilir."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS çağrı hizmetine erişme"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 308e50cba07c..fce4cc3909b0 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -356,8 +356,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Дозволяє програмі фотографувати та знімати відео за допомогою камери. Такий дозвіл дає програмі змогу будь-коли використовувати камеру без вашого підтвердження."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"контролювати вібросигнал"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволяє програмі контролювати вібросигнал."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"контр. блим. світло"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволяє програмі контролювати світловий сигнал."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"прямо набирати номери тел."</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Дозволяє програмі набирати номери телефону без вашого відома. Це може спричинити неочікуване стягнення плати чи здійснення дзвінків. Зауважте, що це не дозволяє програмі набирати екстрені номери. Шкідливі програми можуть здійснювати дзвінки без вашого підтвердження, за що з вас стягуватимуться кошти."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"отримувати доступ до телефонної служби IMS"</string> diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml index ca26e9b3bd6a..519f42b67272 100644 --- a/core/res/res/values-ur-rPK/strings.xml +++ b/core/res/res/values-ur-rPK/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"ایپ کو کیمرے سے تصویریں لینے اور ویڈیوز بنانے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو آپ کی تصدیق کے بغیر کسی بھی وقت کیمرا استعمال کرنے کی اجازت دیتی ہے۔"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"ارتعاش کو کنٹرول کریں"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"ایپ کو وائبریٹر کنٹرول کرنے کی اجازت دیتا ہے۔"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"فلیش لائٹ کنٹرول"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"ایپ کو فلیش لائٹ کنٹرول کرنے کی اجازت دیتا ہے۔"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"براہ راست فون نمبرز پر کال کریں"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"ایپ کو آپ کی مداخلت کے بغیر فون نمبروں پر کال کرنے کی اجازت دیتا ہے۔ اس کے نتیجے میں غیر متوقع چارجز یا کالیں ہوسکتی ہیں۔ نوٹ کرلیں کہ یہ ایپ کو ہنگامی نمبروں پر کال کرنے کی اجازت نہیں دیتا ہے۔ نقصان دہ ایپس آپ کی تصدیق کے بغیر کالیں کرکے آپ کی رقم صرف کروا سکتے ہیں۔"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS کال سروس تک رسائی حاصل کریں"</string> diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml index 3f3d151c039b..e90d921dc40b 100644 --- a/core/res/res/values-uz-rUZ/strings.xml +++ b/core/res/res/values-uz-rUZ/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Ilovaga kameradan foydalanib rasm va videoga olishga ruxsat beradi. Bu ruxsat ilovaga sizdan tasdiqlashni so‘ramasdan kameradan foydalanishga imkon beradi."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"tebranishni boshqarish"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Ilova tebranishli signallarni boshqarishi mumkin."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"chiroq chaqnashini boshqarish"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Ilova chaqnoqni boshqarishi mumkin."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"telefon raqamlariga tog‘ridan to‘g‘ri qo‘ng‘iroq qilish"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Ilovaga sizning yordamingizsiz telefonga qo‘ng‘iroq qilish imkonini beradi. Bu kutilmagan qo‘ng‘iroqlarni amalga oshirishi yoki ortiqcha to‘lovlarni yuzaga keltirishi mumkin. Shunga e’tibor qilinki, u favqulodda telefon raqamlariga qo‘ng‘iroqlar qilishga ruxsat bermaydi. Zararli ilovalar sizdan so‘ramasdan qo‘ng‘iroqlarni amalga oshirib, pulingizni sarflashi mumkin."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS qo‘ng‘iroq xizmatiga kirish"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index c538684e06c8..31e090bc6c99 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng sử dụng máy ảnh bất kỳ lúc nào mà không cần sự xác nhận của bạn."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"kiểm soát rung"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Cho phép ứng dụng kiểm soát bộ rung."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"kiểm soát đèn nháy"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Cho phép ứng dụng kiểm soát đèn nháy."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"gọi trực tiếp số điện thoại"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Cho phép ứng dụng gọi các số điện thoại mà không cần sự can thiệp của bạn. Việc này có thể dẫn đến các khoản phí hoặc cuộc gọi không mong muốn. Lưu ý rằng quyền này không cho phép ứng dụng gọi các số khẩn cấp. Các ứng dụng độc hại có thể khiến bạn tốn tiền do thực hiện cuộc gọi mà không cần sự xác nhận của bạn."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"truy cập dịch vụ gọi điện qua IMS"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 77053f2e7bcb..c5cd59af735e 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"允许该应用使用相机拍摄照片和视频。此权限可让该应用随时使用相机,而无需您的确认。"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"控制振动"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"允许应用控制振动器。"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光灯"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"允许应用控制闪光灯。"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电话号码"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"允许该应用在您未执行操作的情况下拨打电话号码。此权限可能会导致意外收费或呼叫。请注意,此权限不允许该应用拨打紧急电话号码。恶意应用可通过拨打电话产生相关费用,而无需您的确认。"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用即时通讯通话服务"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index 612efe4a0248..36ba2ad610f2 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限允許應用程式隨時使用相機,而不需經您確認。"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式繞過您自行撥打電話號碼,但可能會產生未預期的費用或撥打未預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能未經您確認擅自撥打電話,增加您的支出。"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用 IMS 通話服務"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 201cc1e365c2..72ea52395ed2 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限可讓應用程式隨時使用相機,而不需請求您進行確認。"</string> <string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string> <string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式自行撥打電話,但可能產生非預期的費用或撥打非預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能利用此功能擅自撥打電話,增加您不必要的額外支出。"</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"存取 IMS 撥號服務"</string> diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml index 5e835e39df1b..bee7eeaa55c9 100644 --- a/core/res/res/values-zu/strings.xml +++ b/core/res/res/values-zu/strings.xml @@ -354,8 +354,6 @@ <string name="permdesc_camera" msgid="8497216524735535009">"Ivumela uhlelo lokusebenza ukuthatha izithombe namavidiyo ngekhamera. Le mvume ivumela uhlelo lokusebenza ukusebenzisa ikhamera nganoma isiphi isikhathi ngaphandle kwemvume yakho."</string> <string name="permlab_vibrate" msgid="7696427026057705834">"lawula ukudlidliza"</string> <string name="permdesc_vibrate" msgid="6284989245902300945">"Ivumela uhlelo lokusebenza ukulawula isidlidlizi."</string> - <string name="permlab_flashlight" msgid="2155920810121984215">"lawula ukukhanya kwefulashi"</string> - <string name="permdesc_flashlight" msgid="6522284794568368310">"Ivumela uhlelo lokusebenza ukulawula ukukhanya kwefuleshi."</string> <string name="permlab_callPhone" msgid="3925836347681847954">"ngokuqondile shayela izinombolo zocingo"</string> <string name="permdesc_callPhone" msgid="3740797576113760827">"Ivumela uhlelo lokusebenza ukushayela izinombolo zefoni ngaphandle kokuhlanganyela kwakho. Lokhu kungaholela emashajini noma amakholi angalindelekile. Qaphela ukuthi lokhu akuvumeli uhlelo lokusebenza ukushayela izinombolo zesimo esiphuthumayo. Izinhlelo zokusebenza ezingalungile zingabiza imali ngokwenze amakholi ngaphandle kokuqinisekisa kwakho."</string> <string name="permlab_accessImsCallService" msgid="3574943847181793918">"finyelela kusevisi yekholi ye-IMS"</string> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 9f135651cb67..6d505a58ab80 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4039,9 +4039,9 @@ i should always be false for Material and beyond. @hide Developers shouldn't need to change this. --> <attr name="useDisabledAlpha" format="boolean" /> - <!-- Tint to apply to the button graphic. --> + <!-- Tint to apply to the thumb drawable. --> <attr name="thumbTint" format="color" /> - <!-- Blending mode used to apply the button graphic tint. --> + <!-- Blending mode used to apply the thumb tint. --> <attr name="thumbTintMode"> <!-- The tint is drawn on top of the drawable. [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> @@ -4061,6 +4061,30 @@ i result to valid color values. Saturate(S + D) --> <enum name="add" value="16" /> </attr> + <!-- Drawable displayed at each progress position on a seekbar. --> + <attr name="tickMark" format="reference" /> + <!-- Tint to apply to the tick mark drawable. --> + <attr name="tickMarkTint" format="color" /> + <!-- Blending mode used to apply the tick mark tint. --> + <attr name="tickMarkTintMode"> + <!-- The tint is drawn on top of the drawable. + [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] --> + <enum name="src_over" value="3" /> + <!-- The tint is masked by the alpha channel of the drawable. The drawable’s + color channels are thrown out. [Sa * Da, Sc * Da] --> + <enum name="src_in" value="5" /> + <!-- The tint is drawn above the drawable, but with the drawable’s alpha + channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] --> + <enum name="src_atop" value="9" /> + <!-- Multiplies the color and alpha channels of the drawable with those of + the tint. [Sa * Da, Sc * Dc] --> + <enum name="multiply" value="14" /> + <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] --> + <enum name="screen" value="15" /> + <!-- Combines the tint and drawable color and alpha channels, clamping the + result to valid color values. Saturate(S + D) --> + <enum name="add" value="16" /> + </attr> </declare-styleable> <declare-styleable name="StackView"> @@ -7836,6 +7860,12 @@ i <attr name="label" /> <!-- The key character map file resource. --> <attr name="keyboardLayout" format="reference" /> + <!-- The locales the given keyboard layout corresponds to. --> + <attr name="locale" format="string" /> + <!-- The vendor ID of the hardware the given layout corresponds to. @hide --> + <attr name="vendorId" format="integer" /> + <!-- The product ID of the hardware the given layout corresponds to. @hide --> + <attr name="productId" format="integer" /> </declare-styleable> <declare-styleable name="MediaRouteButton"> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index d13a6227c04f..58c4046dde82 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -2417,4 +2417,8 @@ 2 - 1 snap target: 1:1 --> <integer name="config_dockedStackDividerSnapMode">0</integer> + + <!-- List of comma separated package names for which we the system will not show crash, ANR, + etc. dialogs. --> + <string translatable="false" name="config_appsNotReportingCrashes"></string> </resources> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 37b2c1288d91..b2482cdcf82e 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -35,6 +35,13 @@ <dimen name="navigation_bar_height_landscape">48dp</dimen> <!-- Width of the navigation bar when it is placed vertically on the screen --> <dimen name="navigation_bar_width">48dp</dimen> + <!-- Height of the bottom navigation / system bar in car mode. --> + <dimen name="navigation_bar_height_car_mode">96dp</dimen> + <!-- Height of the bottom navigation bar in portrait; often the same as + @dimen/navigation_bar_height_car_mode --> + <dimen name="navigation_bar_height_landscape_car_mode">96dp</dimen> + <!-- Width of the navigation bar when it is placed vertically on the screen in car mode --> + <dimen name="navigation_bar_width_car_mode">96dp</dimen> <!-- Height of notification icons in the status bar --> <dimen name="status_bar_icon_size">24dip</dimen> <!-- Size of the giant number (unread count) in the notifications --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 09c17179b4b5..ebb1b372e717 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2685,8 +2685,12 @@ <public type="attr" name="canControlMagnification" /> <public type="attr" name="languageTag" /> <public type="attr" name="pointerShape" /> + <public type="attr" name="tickMark" /> + <public type="attr" name="tickMarkTint" /> + <public type="attr" name="tickMarkTintMode" /> <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" /> + <public type="style" name="Widget.Material.SeekBar.Discrete" /> <public type="id" name="accessibilityActionSetProgress" /> <public type="id" name="icon_frame" /> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 8485e59be5a9..3d5f6aba9a7b 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -745,6 +745,11 @@ please see styles_device_defaults.xml. <item name="background">@drawable/control_background_32dp_material</item> </style> + <!-- A seek bar with tick marks at each progress value. --> + <style name="Widget.Material.SeekBar.Discrete"> + <item name="tickMark">@drawable/seekbar_tick_mark_material</item> + </style> + <style name="Widget.Material.RatingBar" parent="Widget.RatingBar"> <item name="progressDrawable">@drawable/ratingbar_material</item> <item name="indeterminateDrawable">@drawable/ratingbar_material</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 845c8c935ab9..a4654e8a710f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -575,6 +575,7 @@ <java-symbol type="string" name="config_ntpServer" /> <java-symbol type="string" name="config_useragentprofile_url" /> <java-symbol type="string" name="config_wifi_p2p_device_type" /> + <java-symbol type="string" name="config_appsNotReportingCrashes" /> <java-symbol type="string" name="contentServiceSync" /> <java-symbol type="string" name="contentServiceSyncNotificationTitle" /> <java-symbol type="string" name="contentServiceTooManyDeletesNotificationDesc" /> @@ -1497,6 +1498,9 @@ <java-symbol type="dimen" name="navigation_bar_height" /> <java-symbol type="dimen" name="navigation_bar_height_landscape" /> <java-symbol type="dimen" name="navigation_bar_width" /> + <java-symbol type="dimen" name="navigation_bar_height_car_mode" /> + <java-symbol type="dimen" name="navigation_bar_height_landscape_car_mode" /> + <java-symbol type="dimen" name="navigation_bar_width_car_mode" /> <java-symbol type="dimen" name="status_bar_height" /> <java-symbol type="drawable" name="ic_jog_dial_sound_off" /> <java-symbol type="drawable" name="ic_jog_dial_sound_on" /> diff --git a/core/tests/coretests/src/android/util/PatternsTest.java b/core/tests/coretests/src/android/util/PatternsTest.java index 253eb2585377..d3837756e495 100644 --- a/core/tests/coretests/src/android/util/PatternsTest.java +++ b/core/tests/coretests/src/android/util/PatternsTest.java @@ -17,14 +17,16 @@ package android.util; import android.test.suitebuilder.annotation.SmallTest; import android.test.suitebuilder.annotation.Suppress; -import android.util.Patterns; import java.util.regex.Matcher; +import java.util.regex.Pattern; import junit.framework.TestCase; public class PatternsTest extends TestCase { + //Tests for Patterns.TOP_LEVEL_DOMAIN + @SmallTest public void testTldPattern() throws Exception { boolean t; @@ -40,7 +42,7 @@ public class PatternsTest extends TestCase { t = Patterns.TOP_LEVEL_DOMAIN.matcher("xn--0zwm56d").matches(); assertTrue("Missed valid TLD", t); - // One of the new top level internationalized domain. + // One of the new top level unicode domain. t = Patterns.TOP_LEVEL_DOMAIN.matcher("\uD55C\uAD6D").matches(); assertTrue("Missed valid TLD", t); @@ -54,60 +56,372 @@ public class PatternsTest extends TestCase { assertFalse("Matched invalid TLD!", t); } + //Tests for Patterns.IANA_TOP_LEVEL_DOMAINS + @SmallTest - @Suppress // Failing. - public void testUrlPattern() throws Exception { - boolean t; + public void testIanaTopLevelDomains_matchesValidTld() throws Exception { + Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS); + assertTrue("Should match 'com'", pattern.matcher("com").matches()); + } - t = Patterns.WEB_URL.matcher("http://www.google.com").matches(); - assertTrue("Valid URL", t); + @SmallTest + public void testIanaTopLevelDomains_matchesValidNewTld() throws Exception { + Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS); + assertTrue("Should match 'me'", pattern.matcher("me").matches()); + } - // Google in one of the new top level domain. - t = Patterns.WEB_URL.matcher("http://www.google.me").matches(); - assertTrue("Valid URL", t); - t = Patterns.WEB_URL.matcher("google.me").matches(); - assertTrue("Valid URL", t); + @SmallTest + public void testIanaTopLevelDomains_matchesPunycodeTld() throws Exception { + Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS); + assertTrue("Should match Punycode TLD", pattern.matcher("xn--qxam").matches()); + } - // Test url in Chinese: http://xn--fsqu00a.xn--0zwm56d - t = Patterns.WEB_URL.matcher("http://xn--fsqu00a.xn--0zwm56d").matches(); - assertTrue("Valid URL", t); - t = Patterns.WEB_URL.matcher("xn--fsqu00a.xn--0zwm56d").matches(); - assertTrue("Valid URL", t); + @SmallTest + public void testIanaTopLevelDomains_matchesIriTLD() throws Exception { + Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS); + assertTrue("Should match IRI TLD", pattern.matcher("\uD55C\uAD6D").matches()); + } - // Url for testing top level Arabic country code domain in Punycode: - // http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx - t = Patterns.WEB_URL.matcher("http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches(); - assertTrue("Valid URL", t); - t = Patterns.WEB_URL.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx").matches(); - assertTrue("Valid URL", t); + @SmallTest + public void testIanaTopLevelDomains_doesNotMatchWrongTld() throws Exception { + Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS); + assertFalse("Should not match 'mem'", pattern.matcher("mem").matches()); + } - // Internationalized URL. - t = Patterns.WEB_URL.matcher("http://\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); - assertTrue("Valid URL", t); - t = Patterns.WEB_URL.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); - assertTrue("Valid URL", t); - // URL with international TLD. - t = Patterns.WEB_URL.matcher("\uB3C4\uBA54\uC778.\uD55C\uAD6D").matches(); - assertTrue("Valid URL", t); + @SmallTest + public void testIanaTopLevelDomains_doesNotMatchWrongPunycodeTld() throws Exception { + Pattern pattern = Pattern.compile(Patterns.IANA_TOP_LEVEL_DOMAINS); + assertFalse("Should not match invalid Punycode TLD", pattern.matcher("xn").matches()); + } - t = Patterns.WEB_URL.matcher("http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" + - "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/").matches(); - assertTrue("Valid URL", t); + //Tests for Patterns.WEB_URL - t = Patterns.WEB_URL.matcher("ftp://www.example.com").matches(); - assertFalse("Matched invalid protocol", t); + @SmallTest + public void testWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception { + String url = "http://www.android.com"; + assertTrue("Should match URL with scheme and hostname", + Patterns.WEB_URL.matcher(url).matches()); + } - t = Patterns.WEB_URL.matcher("http://www.example.com:8080").matches(); - assertTrue("Didn't match valid URL with port", t); + @SmallTest + public void testWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception { + String url = "http://www.android.me"; + assertTrue("Should match URL with scheme, hostname and new TLD", + Patterns.WEB_URL.matcher(url).matches()); + } - t = Patterns.WEB_URL.matcher("http://www.example.com:8080/?foo=bar").matches(); - assertTrue("Didn't match valid URL with port and query args", t); + @SmallTest + public void testWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception { + String url = "android.me"; + assertTrue("Should match URL with hostname and new TLD", + Patterns.WEB_URL.matcher(url).matches()); + } - t = Patterns.WEB_URL.matcher("http://www.example.com:8080/~user/?foo=bar").matches(); - assertTrue("Didn't match valid URL with ~", t); + @SmallTest + public void testWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception { + String url = "http://xn--fsqu00a.xn--0zwm56d"; + assertTrue("Should match Chinese Punycode URL with protocol", + Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception { + String url = "xn--fsqu00a.xn--0zwm56d"; + assertTrue("Should match Chinese Punycode URL without protocol", + Patterns.WEB_URL.matcher(url).matches()); + } + + + @SmallTest + public void testWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception { + String url = "http://xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx"; + assertTrue("Should match arabic Punycode URL with protocol", + Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception { + String url = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx"; + assertTrue("Should match Arabic Punycode URL without protocol", + Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesUrlWithUnicodeDomainNameWithProtocol() throws Exception { + String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr"; + assertTrue("Should match URL with Unicode domain name", + Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesUrlWithUnicodeDomainNameWithoutProtocol() throws Exception { + String url = "\uD604\uAE08\uC601\uC218\uC99D.kr"; + assertTrue("Should match URL without protocol and with Unicode domain name", + Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesUrlWithUnicodeTld() throws Exception { + String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D"; + assertTrue("Should match URL with Unicode TLD", + Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesUrlWithUnicodePath() throws Exception { + String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" + + "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/"; + assertTrue("Should match URL with Unicode path", + Patterns.WEB_URL.matcher(url).matches()); } @SmallTest + public void testWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception { + String url = "ftp://www.example.com"; + assertFalse("Should not match URL with invalid protocol", + Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesValidUrlWithPort() throws Exception { + String url = "http://www.example.com:8080"; + assertTrue("Should match URL with port", Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesUrlWithPortAndQuery() throws Exception { + String url = "http://www.example.com:8080/?foo=bar"; + assertTrue("Should match URL with port and query", + Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesUrlWithTilde() throws Exception { + String url = "http://www.example.com:8080/~user/?foo=bar"; + assertTrue("Should match URL with tilde", Patterns.WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testWebUrl_matchesProtocolCaseInsensitive() throws Exception { + String url = "hTtP://android.com"; + assertTrue("Protocol matching should be case insensitive", + Patterns.WEB_URL.matcher(url).matches()); + } + + //Tests for Patterns.AUTOLINK_WEB_URL + + @SmallTest + public void testAutoLinkWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception { + String url = "http://www.android.com"; + assertTrue("Should match URL with scheme and hostname", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesValidUrlWithSchemeHostnameAndNewTld() throws Exception { + String url = "http://www.android.me"; + assertTrue("Should match URL with scheme, hostname and new TLD", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesValidUrlWithHostnameAndNewTld() throws Exception { + String url = "android.me"; + assertTrue("Should match URL with hostname and new TLD", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + + url = "android.camera"; + assertTrue("Should match URL with hostname and new TLD", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithProtocol() throws Exception { + String url = "http://xn--fsqu00a.xn--0zwm56d"; + assertTrue("Should match Chinese Punycode URL with protocol", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesChinesePunycodeUrlWithoutProtocol() throws Exception { + String url = "xn--fsqu00a.xn--0zwm56d"; + assertTrue("Should match Chinese Punycode URL without protocol", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithProtocol() throws Exception { + String url = "http://xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx"; + assertTrue("Should match Arabic Punycode URL with protocol", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesArabicPunycodeUrlWithoutProtocol() throws Exception { + String url = "xn--4gbrim.xn--rmckbbajlc6dj7bxne2c.xn--wgbh1c/ar/default.aspx"; + assertTrue("Should match Arabic Punycode URL without protocol", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatStartsWithDash() throws Exception { + String url = "http://xn--fsqu00a.-xn--0zwm56d"; + assertFalse("Should not match Punycode TLD that starts with dash", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotMatchPunycodeTldThatEndsWithDash() throws Exception { + String url = "http://xn--fsqu00a.xn--0zwm56d-"; + assertFalse("Should not match Punycode TLD that ends with dash", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesUrlWithUnicodeDomainName() throws Exception { + String url = "http://\uD604\uAE08\uC601\uC218\uC99D.kr"; + assertTrue("Should match URL with Unicode domain name", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + + url = "\uD604\uAE08\uC601\uC218\uC99D.kr"; + assertTrue("hould match URL without protocol and with Unicode domain name", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesUrlWithUnicodeTld() throws Exception { + String url = "\uB3C4\uBA54\uC778.\uD55C\uAD6D"; + assertTrue("Should match URL with Unicode TLD", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesUrlWithUnicodePath() throws Exception { + String url = "http://brainstormtech.blogs.fortune.cnn.com/2010/03/11/" + + "top-five-moments-from-eric-schmidt\u2019s-talk-in-abu-dhabi/"; + assertTrue("Should match URL with Unicode path", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotMatchValidUrlWithInvalidProtocol() throws Exception { + String url = "ftp://www.example.com"; + assertFalse("Should not match URL with invalid protocol", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesValidUrlWithPort() throws Exception { + String url = "http://www.example.com:8080"; + assertTrue("Should match URL with port", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesUrlWithPortAndQuery() throws Exception { + String url = "http://www.example.com:8080/?foo=bar"; + assertTrue("Should match URL with port and query", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesUrlWithTilde() throws Exception { + String url = "http://www.example.com:8080/~user/?foo=bar"; + assertTrue("Should match URL with tilde", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesProtocolCaseInsensitive() throws Exception { + String url = "hTtP://android.com"; + assertTrue("Protocol matching should be case insensitive", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesUrlStartingWithHttpAndDoesNotHaveTld() throws Exception { + String url = "http://android/#notld///a/n/d/r/o/i/d&p1=1&p2=2"; + assertTrue("Should match URL without a TLD and starting with http ", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotMatchUrlsWithoutProtocolAndWithUnknownTld() + throws Exception { + String url = "thank.you"; + assertFalse("Should not match URL that does not start with a protocol and " + + "does not contain a known TLD", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotMatchUrlWithInvalidRequestParameter() throws Exception { + String url = "http://android.com?p=value"; + assertFalse("Should not match URL with invalid request parameter", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotPartiallyMatchUnknownProtocol() throws Exception { + String url = "ftp://foo.bar/baz"; + assertFalse("Should not partially match URL with unknown protocol", + Patterns.AUTOLINK_WEB_URL.matcher(url).find()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesValidUrlWithEmoji() throws Exception { + String url = "Thank\u263A.com"; + assertTrue("Should match URL with emoji", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotMatchUrlsWithEmojiWithoutProtocolAndWithoutKnownTld() + throws Exception { + String url = "Thank\u263A.you"; + assertFalse("Should not match URLs containing emoji and with unknown TLD", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotMatchEmailAddress() + throws Exception { + String url = "android@android.com"; + assertFalse("Should not match email address", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesDomainNameWithSurrogatePairs() throws Exception { + String url = "android\uD83C\uDF38.com"; + assertTrue("Should match domain name with Unicode surrogate pairs", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesTldWithSurrogatePairs() throws Exception { + String url = "http://android.\uD83C\uDF38com"; + assertTrue("Should match TLD with Unicode surrogate pairs", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_matchesPathWithSurrogatePairs() throws Exception { + String url = "http://android.com/path-with-\uD83C\uDF38?v=\uD83C\uDF38"; + assertTrue("Should match path and query with Unicode surrogate pairs", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + @SmallTest + public void testAutoLinkWebUrl_doesNotMatchUrlWithExcludedSurrogate() throws Exception { + String url = "http://android\uD83F\uDFFE.com"; + assertFalse("Should not match URL with excluded Unicode surrogate pair", + Patterns.AUTOLINK_WEB_URL.matcher(url).matches()); + } + + //Tests for Patterns.IP_ADDRESS + + @SmallTest public void testIpPattern() throws Exception { boolean t; @@ -118,34 +432,85 @@ public class PatternsTest extends TestCase { assertFalse("Invalid IP", t); } + //Tests for Patterns.DOMAIN_NAME + @SmallTest - @Suppress // Failing. - public void testDomainPattern() throws Exception { - boolean t; + public void testDomain_matchesPunycodeTld() throws Exception { + String domain = "xn--fsqu00a.xn--0zwm56d"; + assertTrue("Should match domain name in Punycode", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } + + @SmallTest + public void testDomain_doesNotMatchPunycodeThatStartsWithDash() throws Exception { + String domain = "xn--fsqu00a.-xn--0zwm56d"; + assertFalse("Should not match Punycode TLD that starts with a dash", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } - t = Patterns.DOMAIN_NAME.matcher("mail.example.com").matches(); - assertTrue("Valid domain", t); + @SmallTest + public void testDomain_doesNotMatchPunycodeThatEndsWithDash() throws Exception { + String domain = "xn--fsqu00a.xn--0zwm56d-"; + assertFalse("Should not match Punycode TLD that ends with a dash", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } - t = Patterns.DOMAIN_NAME.matcher("google.me").matches(); - assertTrue("Valid domain", t); + @SmallTest + public void testDomain_doesNotMatchPunycodeLongerThanAllowed() throws Exception { + String tld = "xn--"; + for(int i=0; i<=6; i++) { + tld += "0123456789"; + } + String domain = "xn--fsqu00a." + tld; + assertFalse("Should not match Punycode TLD that is longer than 63 chars", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } - // Internationalized domains. - t = Patterns.DOMAIN_NAME.matcher("\uD604\uAE08\uC601\uC218\uC99D.kr").matches(); - assertTrue("Valid domain", t); + @SmallTest + public void testDomain_matchesObsoleteTld() throws Exception { + String domain = "test.yu"; + assertTrue("Should match domain names with obsolete TLD", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } - t = Patterns.DOMAIN_NAME.matcher("__+&42.xer").matches(); - assertFalse("Invalid domain", t); + @SmallTest + public void testDomain_matchesWithSubDomain() throws Exception { + String domain = "mail.example.com"; + assertTrue("Should match domain names with subdomains", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } - // Obsolete domain .yu - t = Patterns.DOMAIN_NAME.matcher("test.yu").matches(); - assertFalse("Obsolete country code top level domain", t); + @SmallTest + public void testDomain_matchesWithoutSubDomain() throws Exception { + String domain = "android.me"; + assertTrue("Should match domain names without subdomains", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } + + @SmallTest + public void testDomain_matchesUnicodeDomainNames() throws Exception { + String domain = "\uD604\uAE08\uC601\uC218\uC99D.kr"; + assertTrue("Should match unicodedomain names", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } - // Testing top level Arabic country code domain in Punycode: - t = Patterns.DOMAIN_NAME.matcher("xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c").matches(); - assertTrue("Valid domain", t); + @SmallTest + public void testDomain_doesNotMatchInvalidDomain() throws Exception { + String domain = "__+&42.xer"; + assertFalse("Should not match invalid domain name", + Patterns.DOMAIN_NAME.matcher(domain).matches()); } @SmallTest + public void testDomain_matchesPunycodeArabicDomainName() throws Exception { + String domain = "xn--4gbrim.xn----rmckbbajlc6dj7bxne2c.xn--wgbh1c"; + assertTrue("Should match Punycode Arabic domain name", + Patterns.DOMAIN_NAME.matcher(domain).matches()); + } + + //Tests for Patterns.PHONE + + @SmallTest public void testPhonePattern() throws Exception { boolean t; diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java index c05ea2e1a1e5..704f0ce7624b 100644 --- a/drm/java/android/drm/DrmManagerClient.java +++ b/drm/java/android/drm/DrmManagerClient.java @@ -38,13 +38,14 @@ import java.io.IOException; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.HashMap; +import java.util.concurrent.atomic.AtomicBoolean; /** * The main programming interface for the DRM framework. An application must instantiate this class * to access DRM agents through the DRM framework. * */ -public class DrmManagerClient { +public class DrmManagerClient implements AutoCloseable { /** * Indicates that a request was successful or that no error occurred. */ @@ -61,6 +62,7 @@ public class DrmManagerClient { HandlerThread mEventThread; private static final String TAG = "DrmManagerClient"; + private final AtomicBoolean mClosed = new AtomicBoolean(); private final CloseGuard mCloseGuard = CloseGuard.get(); static { @@ -117,7 +119,6 @@ public class DrmManagerClient { private int mUniqueId; private long mNativeContext; - private volatile boolean mReleased; private Context mContext; private InfoHandler mInfoHandler; private EventHandler mEventHandler; @@ -261,41 +262,47 @@ public class DrmManagerClient { @Override protected void finalize() throws Throwable { try { - if (mCloseGuard != null) { - mCloseGuard.warnIfOpen(); - } - release(); + mCloseGuard.warnIfOpen(); + close(); } finally { super.finalize(); } } /** - * Releases resources associated with the current session of DrmManagerClient. - * - * It is considered good practice to call this method when the {@link DrmManagerClient} object - * is no longer needed in your application. After release() is called, - * {@link DrmManagerClient} is no longer usable since it has lost all of its required resource. + * Releases resources associated with the current session of + * DrmManagerClient. It is considered good practice to call this method when + * the {@link DrmManagerClient} object is no longer needed in your + * application. After this method is called, {@link DrmManagerClient} is no + * longer usable since it has lost all of its required resource. */ - public void release() { - if (mReleased) return; - mReleased = true; - - if (mEventHandler != null) { - mEventThread.quit(); - mEventThread = null; - } - if (mInfoHandler != null) { - mInfoThread.quit(); - mInfoThread = null; - } - mEventHandler = null; - mInfoHandler = null; - mOnEventListener = null; - mOnInfoListener = null; - mOnErrorListener = null; - _release(mUniqueId); + @Override + public void close() { mCloseGuard.close(); + if (mClosed.compareAndSet(false, true)) { + if (mEventHandler != null) { + mEventThread.quit(); + mEventThread = null; + } + if (mInfoHandler != null) { + mInfoThread.quit(); + mInfoThread = null; + } + mEventHandler = null; + mInfoHandler = null; + mOnEventListener = null; + mOnInfoListener = null; + mOnErrorListener = null; + _release(mUniqueId); + } + } + + /** + * @deprecated replaced by {@link #close()}. + */ + @Deprecated + public void release() { + close(); } /** diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 175c726072cc..447a4c4e8345 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -355,6 +355,9 @@ public class BitmapFactory { public byte[] inTempStorage; /** + * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, see + * comments on {@link #requestCancelDecode()}. + * * Flag to indicate that cancel has been called on this object. This * is useful if there's an intermediary that wants to first decode the * bounds and then decode the image. In that case the intermediary diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index d5166ab92179..1cc53469a2f7 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -654,6 +654,12 @@ public class Canvas { /** * Return, in ctm, the current transformation matrix. This does not alter * the matrix in the canvas, but just returns a copy of it. + * + * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any + * matrix when passed to a View or Drawable, as it is implementation defined where in the + * hierarchy such canvases are created. It is recommended in such cases to either draw contents + * irrespective of the current matrix, or to track relevant transform state outside of the + * canvas. */ @Deprecated public void getMatrix(@NonNull Matrix ctm) { @@ -663,6 +669,12 @@ public class Canvas { /** * Return a new matrix with a copy of the canvas' current transformation * matrix. + * + * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any + * matrix when passed to a View or Drawable, as it is implementation defined where in the + * hierarchy such canvases are created. It is recommended in such cases to either draw contents + * irrespective of the current matrix, or to track relevant transform state outside of the + * canvas. */ @Deprecated public final @NonNull Matrix getMatrix() { @@ -812,6 +824,7 @@ public class Canvas { * @deprecated Unlike all other clip calls this API does not respect the * current matrix. Use {@link #clipRect(Rect)} as an alternative. */ + @Deprecated public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) { return native_clipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt); } @@ -829,6 +842,7 @@ public class Canvas { * @deprecated Unlike all other clip calls this API does not respect the * current matrix. Use {@link #clipRect(Rect)} as an alternative. */ + @Deprecated public boolean clipRegion(@NonNull Region region) { return clipRegion(region, Region.Op.INTERSECT); } @@ -1830,16 +1844,16 @@ public class Canvas { * Draw the text in the array, with each character's origin specified by * the pos array. * - * This method does not support glyph composition and decomposition and - * should therefore not be used to render complex scripts. It also doesn't - * handle supplementary characters (eg emoji). - * * @param text The text to be drawn * @param index The index of the first character to draw * @param count The number of characters to draw, starting from index. * @param pos Array of [x,y] positions, used to position each * character * @param paint The paint used for the text (e.g. color, size, style) + * + * @deprecated This method does not support glyph composition and decomposition and + * should therefore not be used to render complex scripts. It also doesn't + * handle supplementary characters (eg emoji). */ @Deprecated public void drawPosText(@NonNull char[] text, int index, int count, @@ -1857,13 +1871,13 @@ public class Canvas { * Draw the text in the array, with each character's origin specified by * the pos array. * - * This method does not support glyph composition and decomposition and - * should therefore not be used to render complex scripts. It also doesn't - * handle supplementary characters (eg emoji). - * * @param text The text to be drawn * @param pos Array of [x,y] positions, used to position each character * @param paint The paint used for the text (e.g. color, size, style) + * + * @deprecated This method does not support glyph composition and decomposition and + * should therefore not be used to render complex scripts. It also doesn't + * handle supplementary characters (eg emoji). */ @Deprecated public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos, diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java index d313aa5b5f65..6bd2646f9299 100644 --- a/graphics/java/android/graphics/drawable/RippleBackground.java +++ b/graphics/java/android/graphics/drawable/RippleBackground.java @@ -33,6 +33,7 @@ import android.view.animation.LinearInterpolator; * Draws a ripple background. */ class RippleBackground extends RippleComponent { + private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator(); private static final int OPACITY_ENTER_DURATION = 600; @@ -48,8 +49,14 @@ class RippleBackground extends RippleComponent { // Software rendering properties. private float mOpacity = 0; - public RippleBackground(RippleDrawable owner, Rect bounds, boolean forceSoftware) { + /** Whether this ripple is bounded. */ + private boolean mIsBounded; + + public RippleBackground(RippleDrawable owner, Rect bounds, boolean isBounded, + boolean forceSoftware) { super(owner, bounds, forceSoftware); + + mIsBounded = isBounded; } public boolean isVisible() { @@ -105,7 +112,8 @@ class RippleBackground extends RippleComponent { final AnimatorSet.Builder builder = set.play(exit); // Linear "fast" enter based on current opacity. - final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST); + final int fastEnterDuration = mIsBounded ? + (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST) : 0; if (fastEnterDuration > 0) { final ObjectAnimator enter = ObjectAnimator.ofFloat(this, RippleBackground.OPACITY, 1); enter.setInterpolator(LINEAR_INTERPOLATOR); @@ -131,15 +139,18 @@ class RippleBackground extends RippleComponent { mPropX = CanvasProperty.createFloat(0); mPropY = CanvasProperty.createFloat(0); - final int fastEnterDuration = (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST); + final int fastEnterDuration = mIsBounded ? + (int) ((1 - mOpacity) * OPACITY_ENTER_DURATION_FAST) : 0; // Linear exit after enter is completed. final RenderNodeAnimator exit = new RenderNodeAnimator( mPropPaint, RenderNodeAnimator.PAINT_ALPHA, 0); exit.setInterpolator(LINEAR_INTERPOLATOR); exit.setDuration(OPACITY_EXIT_DURATION); - exit.setStartDelay(fastEnterDuration); - exit.setStartValue(targetAlpha); + if (fastEnterDuration > 0) { + exit.setStartDelay(fastEnterDuration); + exit.setStartValue(targetAlpha); + } set.add(exit); // Linear "fast" enter based on current opacity. diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 5213e10332c4..9c691e508535 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -540,7 +540,8 @@ public class RippleDrawable extends LayerDrawable { */ private void tryBackgroundEnter(boolean focused) { if (mBackground == null) { - mBackground = new RippleBackground(this, mHotspotBounds, mForceSoftware); + final boolean isBounded = isBounded(); + mBackground = new RippleBackground(this, mHotspotBounds, isBounded, mForceSoftware); } mBackground.setup(mState.mMaxRadius, mDensity); diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp index 332a2044dbfb..195d235fc7c1 100644 --- a/libs/hwui/BakedOpDispatcher.cpp +++ b/libs/hwui/BakedOpDispatcher.cpp @@ -302,26 +302,6 @@ void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer, } } -void BakedOpDispatcher::onRenderNodeOp(BakedOpRenderer&, const RenderNodeOp&, const BakedOpState&) { - LOG_ALWAYS_FATAL("unsupported operation"); -} - -void BakedOpDispatcher::onBeginLayerOp(BakedOpRenderer&, const BeginLayerOp&, const BakedOpState&) { - LOG_ALWAYS_FATAL("unsupported operation"); -} - -void BakedOpDispatcher::onEndLayerOp(BakedOpRenderer&, const EndLayerOp&, const BakedOpState&) { - LOG_ALWAYS_FATAL("unsupported operation"); -} - -void BakedOpDispatcher::onCirclePropsOp(BakedOpRenderer&, const CirclePropsOp&, const BakedOpState&) { - LOG_ALWAYS_FATAL("unsupported operation"); -} - -void BakedOpDispatcher::onRoundRectPropsOp(BakedOpRenderer&, const RoundRectPropsOp&, const BakedOpState&) { - LOG_ALWAYS_FATAL("unsupported operation"); -} - namespace VertexBufferRenderFlags { enum { Offset = 0x1, @@ -756,6 +736,7 @@ void BakedOpDispatcher::onTextureLayerOp(BakedOpRenderer& renderer, const Textur void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, const BakedOpState& state) { OffscreenBuffer* buffer = *op.layerHandle; + // Note that we don't use op->paint here - it's never set on a LayerOp float layerAlpha = op.alpha * state.alpha; Glop glop; GlopBuilder(renderer.renderState(), renderer.caches(), &glop) @@ -773,5 +754,37 @@ void BakedOpDispatcher::onLayerOp(BakedOpRenderer& renderer, const LayerOp& op, } } +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) { + LOG_ALWAYS_FATAL_IF(*op.layerHandle == nullptr, "no layer to draw underneath!"); + if (!state.computedState.clippedBounds.isEmpty()) { + if (op.paint && op.paint->getAlpha() < 255) { + SkPaint layerPaint; + layerPaint.setAlpha(op.paint->getAlpha()); + layerPaint.setXfermodeMode(SkXfermode::kDstIn_Mode); + layerPaint.setColorFilter(op.paint->getColorFilter()); + RectOp rectOp(state.computedState.clippedBounds, Matrix4::identity(), nullptr, &layerPaint); + BakedOpDispatcher::onRectOp(renderer, rectOp, state); + } + + OffscreenBuffer& layer = **(op.layerHandle); + auto mode = PaintUtils::getXfermodeDirect(op.paint); + Glop glop; + GlopBuilder(renderer.renderState(), renderer.caches(), &glop) + .setRoundRectClipState(state.roundRectClipState) + .setMeshTexturedUvQuad(nullptr, layer.getTextureCoordinates()) + .setFillLayer(layer.texture, nullptr, 1.0f, mode, Blend::ModeOrderSwap::Swap) + .setTransform(state.computedState.transform, TransformFlags::None) + .setModelViewMapUnitToRect(state.computedState.clippedBounds) + .build(); + renderer.renderGlop(state, glop); + } +} + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/BakedOpDispatcher.h b/libs/hwui/BakedOpDispatcher.h index ed34ada90272..4dfdd3ff619a 100644 --- a/libs/hwui/BakedOpDispatcher.h +++ b/libs/hwui/BakedOpDispatcher.h @@ -36,13 +36,13 @@ public: // Declares all "onMergedBitmapOps(...)" style methods for mergeable op types #define X(Type) \ static void onMerged##Type##s(BakedOpRenderer& renderer, const MergedBakedOpList& opList); - MAP_MERGED_OPS(X) + MAP_MERGEABLE_OPS(X) #undef X // Declares all "onBitmapOp(...)" style methods for every op type #define X(Type) \ static void on##Type(BakedOpRenderer& renderer, const Type& op, const BakedOpState& state); - MAP_OPS(X) + MAP_RENDERABLE_OPS(X) #undef X }; diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp index a0d5faed270d..b9c13e6cf847 100644 --- a/libs/hwui/BakedOpRenderer.cpp +++ b/libs/hwui/BakedOpRenderer.cpp @@ -79,6 +79,20 @@ void BakedOpRenderer::endLayer() { mRenderTarget.frameBufferId = 0; } +OffscreenBuffer* BakedOpRenderer::copyToLayer(const Rect& area) { + OffscreenBuffer* buffer = mRenderState.layerPool().get(mRenderState, + area.getWidth(), area.getHeight()); + if (!area.isEmpty()) { + mCaches.textureState().activateTexture(0); + mCaches.textureState().bindTexture(buffer->texture.id); + + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, + area.left, mRenderTarget.viewportHeight - area.bottom, + area.getWidth(), area.getHeight()); + } + return buffer; +} + void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) { LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0"); mRenderState.bindFramebuffer(0); @@ -236,12 +250,13 @@ void BakedOpRenderer::setupStencilRegion(const ClipBase* clip) { } void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* clip) { - // prepare scissor / stencil + // Prepare scissor (done before stencil, to simplify filling stencil) mRenderState.scissor().setEnabled(clip != nullptr); if (clip) { mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect); } + // If stencil may be used for clipping, enable it, fill it, or disable it as appropriate if (CC_LIKELY(!Properties::debugOverdraw)) { // only modify stencil mode and content when it's not used for overdraw visualization if (CC_UNLIKELY(clip && clip->mode != ClipMode::Rectangle)) { diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h index 65e8b29a9ed2..e857f6b2a506 100644 --- a/libs/hwui/BakedOpRenderer.h +++ b/libs/hwui/BakedOpRenderer.h @@ -19,6 +19,7 @@ #include "BakedOpState.h" #include "Matrix.h" +#include "utils/Macros.h" namespace android { namespace uirenderer { @@ -61,9 +62,10 @@ public: void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect); void endFrame(const Rect& repaintRect); - OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height); + WARN_UNUSED_RESULT OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height); void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect); void endLayer(); + WARN_UNUSED_RESULT OffscreenBuffer* copyToLayer(const Rect& area); Texture* getTexture(const SkBitmap* bitmap); const LightInfo& getLightInfo() const { return mLightInfo; } diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp index e6b943a606d5..f1cc846593db 100644 --- a/libs/hwui/BakedOpState.cpp +++ b/libs/hwui/BakedOpState.cpp @@ -75,5 +75,11 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s clipSideFlags = OpClipSideFlags::Full; } +ResolvedRenderState::ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect) + : transform(Matrix4::identity()) + , clipState(viewportRect) + , clippedBounds(dstRect) + , clipSideFlags(OpClipSideFlags::None) {} + } // namespace uirenderer } // namespace android diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h index 9df4e3aa5442..5c7b43f5a034 100644 --- a/libs/hwui/BakedOpState.h +++ b/libs/hwui/BakedOpState.h @@ -58,6 +58,9 @@ public: // Constructor for unbounded ops without transform/clip (namely shadows) ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot); + // Constructor for primitive ops provided clip, and no transform + ResolvedRenderState(const ClipRect* viewportRect, const Rect& dstRect); + Rect computeLocalSpaceClip() const { Matrix4 inverse; inverse.loadInverse(transform); @@ -67,22 +70,24 @@ public: return outClip; } - Matrix4 transform; const Rect& clipRect() const { return clipState->rect; } + bool requiresClip() const { return clipSideFlags != OpClipSideFlags::None - || CC_UNLIKELY(clipState->mode != ClipMode::Rectangle); + || 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; } + + Matrix4 transform; const ClipBase* clipState = nullptr; - int clipSideFlags = 0; Rect clippedBounds; + int clipSideFlags = 0; }; /** @@ -135,12 +140,17 @@ public: return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr); } + static BakedOpState* directConstruct(LinearAllocator& allocator, + const ClipRect* clip, const Rect& dstRect, const RecordedOp& recordedOp) { + return new (allocator) BakedOpState(clip, dstRect, recordedOp); + } + static void* operator new(size_t size, LinearAllocator& allocator) { return allocator.alloc(size); } // computed state: - const ResolvedRenderState computedState; + ResolvedRenderState computedState; // simple state (straight pointer/value storage): const float alpha; @@ -163,6 +173,13 @@ private: , roundRectClipState(snapshot.roundRectClipState) , projectionPathMask(snapshot.projectionPathMask) , op(shadowOpPtr) {} + + BakedOpState(const ClipRect* viewportRect, const Rect& dstRect, const RecordedOp& recordedOp) + : computedState(viewportRect, dstRect) + , alpha(1.0f) + , roundRectClipState(nullptr) + , projectionPathMask(nullptr) + , op(&recordedOp) {} }; }; // namespace uirenderer diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp index 11b2c8a8c282..cff4f3c47d60 100644 --- a/libs/hwui/OpReorderer.cpp +++ b/libs/hwui/OpReorderer.cpp @@ -31,7 +31,6 @@ namespace android { namespace uirenderer { class BatchBase { - public: BatchBase(batchid_t batchId, BakedOpState* op, bool merging) : mBatchId(batchId) @@ -213,7 +212,8 @@ OpReorderer::LayerReorderer::LayerReorderer(uint32_t width, uint32_t height, , repaintRect(repaintRect) , offscreenBuffer(renderNode ? renderNode->getLayer() : nullptr) , beginLayerOp(beginLayerOp) - , renderNode(renderNode) {} + , renderNode(renderNode) + , viewportClip(Rect(width, height)) {} // 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 @@ -240,8 +240,51 @@ void OpReorderer::LayerReorderer::locateInsertIndex(int batchId, const Rect& cli } } +void OpReorderer::LayerReorderer::deferLayerClear(const Rect& rect) { + mClearRects.push_back(rect); +} + +void OpReorderer::LayerReorderer::flushLayerClears(LinearAllocator& allocator) { + if (CC_UNLIKELY(!mClearRects.empty())) { + const int vertCount = mClearRects.size() * 4; + // 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.alloc(vertCount * sizeof(Vertex)); + + Vertex* currentVert = verts; + Rect bounds = mClearRects[0]; + for (auto&& rect : mClearRects) { + bounds.unionWith(rect); + Vertex::set(currentVert++, rect.left, rect.top); + Vertex::set(currentVert++, rect.right, rect.top); + 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 + + // 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->setXfermodeMode(SkXfermode::kClear_Mode); + SimpleRectsOp* op = new (allocator) SimpleRectsOp(bounds, + Matrix4::identity(), nullptr, paint, + verts, vertCount); + BakedOpState* bakedState = BakedOpState::directConstruct(allocator, + &viewportClip, bounds, *op); + + + deferUnmergeableOp(allocator, bakedState, OpBatchType::Vertices); + } +} + void OpReorderer::LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId) { + if (batchId != OpBatchType::CopyToLayer) { + // if first op after one or more unclipped saveLayers, flush the layer clears + flushLayerClears(allocator); + } + OpBatch* targetBatch = mBatchLookup[batchId]; size_t insertBatchIndex = mBatches.size(); @@ -260,10 +303,12 @@ void OpReorderer::LayerReorderer::deferUnmergeableOp(LinearAllocator& allocator, } } -// insertion point of a new batch, will hopefully be immediately after similar batch -// (generally, should be similar shader) void OpReorderer::LayerReorderer::deferMergeableOp(LinearAllocator& allocator, BakedOpState* op, batchid_t batchId, mergeid_t mergeId) { + if (batchId != OpBatchType::CopyToLayer) { + // if first op after one or more unclipped saveLayers, flush the layer clears + flushLayerClears(allocator); + } MergingOpBatch* targetBatch = nullptr; // Try to merge with any existing batch with same mergeId @@ -652,9 +697,7 @@ void OpReorderer::deferProjectedChildren(const RenderNode& renderNode) { [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.defer##Type(static_cast<const Type&>(op)); }, void OpReorderer::deferNodeOps(const RenderNode& renderNode) { typedef void (*OpDispatcher) (OpReorderer& reorderer, const RecordedOp& op); - static OpDispatcher receivers[] = { - MAP_OPS(OP_RECEIVER) - }; + static OpDispatcher receivers[] = BUILD_DEFERRABLE_OP_LUT(OP_RECEIVER); // can't be null, since DL=null node rejection happens before deferNodePropsAndOps const DisplayList& displayList = *(renderNode.getDisplayList()); @@ -728,6 +771,11 @@ void OpReorderer::deferArcOp(const ArcOp& op) { deferStrokeableOp(op, tessBatchId(op)); } +static bool hasMergeableClip(const BakedOpState& state) { + return state.computedState.clipState + || state.computedState.clipState->mode == ClipMode::Rectangle; +} + void OpReorderer::deferBitmapOp(const BitmapOp& op) { BakedOpState* bakedState = tryBakeOpState(op); if (!bakedState) return; // quick rejected @@ -738,7 +786,8 @@ void OpReorderer::deferBitmapOp(const BitmapOp& op) { if (bakedState->computedState.transform.isSimple() && bakedState->computedState.transform.positiveScale() && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode - && op.bitmap->colorType() != kAlpha_8_SkColorType) { + && op.bitmap->colorType() != kAlpha_8_SkColorType + && hasMergeableClip(*bakedState)) { mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID(); // TODO: AssetAtlas in mergeId currentLayer().deferMergeableOp(mAllocator, bakedState, OpBatchType::Bitmap, mergeId); @@ -794,7 +843,8 @@ void OpReorderer::deferPatchOp(const PatchOp& op) { if (!bakedState) return; // quick rejected if (bakedState->computedState.transform.isPureTranslate() - && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) { + && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode + && hasMergeableClip(*bakedState)) { mergeid_t mergeId = (mergeid_t) op.bitmap->getGenerationID(); // TODO: AssetAtlas in mergeId @@ -851,7 +901,8 @@ void OpReorderer::deferTextOp(const TextOp& op) { batchid_t batchId = textBatchId(*(op.paint)); if (bakedState->computedState.transform.isPureTranslate() - && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode) { + && PaintUtils::getXfermodeDirect(op.paint) == SkXfermode::kSrcOver_Mode + && hasMergeableClip(*bakedState)) { mergeid_t mergeId = reinterpret_cast<mergeid_t>(op.paint->getColor()); currentLayer().deferMergeableOp(mAllocator, bakedState, batchId, mergeId); } else { @@ -896,7 +947,8 @@ void OpReorderer::restoreForLayer() { mLayerStack.pop_back(); } -// TODO: test rejection at defer time, where the bounds become empty +// TODO: defer time rejection (when bounds become empty) + tests +// Option - just skip layers with no bounds at playback + defer? void OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) { uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth(); uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight(); @@ -906,7 +958,7 @@ void OpReorderer::deferBeginLayerOp(const BeginLayerOp& op) { // Combine all transforms used to present saveLayer content: // parent content transform * canvas transform * bounds offset - Matrix4 contentTransform(*previous->transform); + Matrix4 contentTransform(*(previous->transform)); contentTransform.multiply(op.localMatrix); contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top); @@ -963,17 +1015,54 @@ void OpReorderer::deferEndLayerOp(const EndLayerOp& /* ignored */) { currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap); } else { // Layer won't be drawn - delete its drawing batches to prevent it from doing any work + // TODO: need to prevent any render work from being done + // - create layerop earlier for reject purposes? mLayerReorderers[finishedLayerIndex].clear(); return; } } -void OpReorderer::deferLayerOp(const LayerOp& op) { - LOG_ALWAYS_FATAL("unsupported"); +void OpReorderer::deferBeginUnclippedLayerOp(const BeginUnclippedLayerOp& op) { + Matrix4 boundsTransform(*(mCanvasState.currentSnapshot()->transform)); + boundsTransform.multiply(op.localMatrix); + + Rect dstRect(op.unmappedBounds); + boundsTransform.mapRect(dstRect); + dstRect.doIntersect(mCanvasState.currentSnapshot()->getRenderTargetClip()); + + // 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 = new (mAllocator) CopyToLayerOp(op, layerHandle); + BakedOpState* bakedState = BakedOpState::directConstruct(mAllocator, + &(currentLayer().viewportClip), dstRect, *copyToOp); + currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::CopyToLayer); + + /** + * Defer a clear rect, so that clears from multiple unclipped layers can be drawn + * both 1) simultaneously, and 2) as long after the copyToLayer executes as possible + */ + currentLayer().deferLayerClear(dstRect); + + /** + * And stash an operation to copy that layer back under the rendertarget until + * a balanced EndUnclippedLayerOp is seen + */ + auto copyFromOp = new (mAllocator) CopyFromLayerOp(op, layerHandle); + bakedState = BakedOpState::directConstruct(mAllocator, + &(currentLayer().viewportClip), dstRect, *copyFromOp); + currentLayer().activeUnclippedSaveLayers.push_back(bakedState); } -void OpReorderer::deferShadowOp(const ShadowOp& op) { - LOG_ALWAYS_FATAL("unsupported"); +void OpReorderer::deferEndUnclippedLayerOp(const EndUnclippedLayerOp& /* ignored */) { + LOG_ALWAYS_FATAL_IF(currentLayer().activeUnclippedSaveLayers.empty(), "no layer to end!"); + + BakedOpState* copyFromLayerOp = currentLayer().activeUnclippedSaveLayers.back(); + currentLayer().deferUnmergeableOp(mAllocator, copyFromLayerOp, OpBatchType::CopyFromLayer); + currentLayer().activeUnclippedSaveLayers.pop_back(); } } // namespace uirenderer diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h index 4e9b5e6a91f1..8d9d90be057c 100644 --- a/libs/hwui/OpReorderer.h +++ b/libs/hwui/OpReorderer.h @@ -53,6 +53,8 @@ namespace OpBatchType { Shadow, TextureLayer, Functor, + CopyToLayer, + CopyFromLayer, Count // must be last }; @@ -91,6 +93,8 @@ class OpReorderer : public CanvasStateClient { void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers, MergedOpReceiver*) const; + void deferLayerClear(const Rect& dstRect); + bool empty() const { return mBatches.empty(); } @@ -107,7 +111,13 @@ class OpReorderer : public CanvasStateClient { OffscreenBuffer* offscreenBuffer; const BeginLayerOp* beginLayerOp; const RenderNode* renderNode; + const ClipRect viewportClip; + + // list of deferred CopyFromLayer ops, to be deferred upon encountering EndUnclippedLayerOps + std::vector<BakedOpState*> activeUnclippedSaveLayers; private: + void flushLayerClears(LinearAllocator& allocator); + std::vector<BatchBase*> mBatches; /** @@ -119,6 +129,8 @@ class OpReorderer : public CanvasStateClient { // Maps batch ids to the most recent *non-merging* batch of that id OpBatch* mBatchLookup[OpBatchType::Count] = { nullptr }; + + std::vector<Rect> mClearRects; }; public: @@ -138,7 +150,7 @@ public: template <typename StaticDispatcher, typename Renderer> void replayBakedOps(Renderer& renderer) { /** - * defines a LUT of lambdas which allow a recorded BakedOpState to use state->op->opId to + * 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: @@ -147,31 +159,22 @@ public: */ #define X(Type) \ [](void* renderer, const BakedOpState& state) { \ - StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), static_cast<const Type&>(*(state.op)), state); \ + StaticDispatcher::on##Type(*(static_cast<Renderer*>(renderer)), \ + static_cast<const Type&>(*(state.op)), state); \ }, - static BakedOpReceiver unmergedReceivers[] = { - MAP_OPS(X) - }; + static BakedOpReceiver unmergedReceivers[] = BUILD_RENDERABLE_OP_LUT(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. Unmergeable ops trigger - * a LOG_ALWAYS_FATAL(). + * 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) { \ - LOG_ALWAYS_FATAL("op type %d does not support merging", opList.states[0]->op->opId); \ - }, - #define Y(Type) \ - [](void* renderer, const MergedBakedOpList& opList) { \ StaticDispatcher::onMerged##Type##s(*(static_cast<Renderer*>(renderer)), opList); \ }, - static MergedOpReceiver mergedReceivers[] = { - MAP_OPS_BASED_ON_MERGEABILITY(X, Y) - }; + static MergedOpReceiver mergedReceivers[] = BUILD_MERGEABLE_OP_LUT(X); #undef X - #undef Y // Relay through layers in reverse order, since layers // later in the list will be drawn by earlier ones @@ -243,8 +246,7 @@ private: void replayBakedOpsImpl(void* arg, BakedOpReceiver* receivers); SkPath* createFrameAllocatedPath() { - mFrameAllocatedPaths.emplace_back(new SkPath); - return mFrameAllocatedPaths.back().get(); + return mAllocator.create<SkPath>(); } void deferStrokeableOp(const RecordedOp& op, batchid_t batchId, @@ -256,11 +258,9 @@ private: * These private methods are called from within deferImpl to defer each individual op * type differently. */ -#define INTERNAL_OP_HANDLER(Type) \ - void defer##Type(const Type& op); - MAP_OPS(INTERNAL_OP_HANDLER) - - std::vector<std::unique_ptr<SkPath> > mFrameAllocatedPaths; +#define X(Type) void defer##Type(const Type& op); + MAP_DEFERRABLE_OPS(X) +#undef X // List of every deferred layer's render state. Replayed in reverse order to render a frame. std::vector<LayerReorderer> mLayerReorderers; diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h index 1971530d2caa..30d5c293c4bb 100644 --- a/libs/hwui/RecordedOp.h +++ b/libs/hwui/RecordedOp.h @@ -39,57 +39,104 @@ class RenderNode; struct Vertex; /** - * On of the provided macros is executed for each op type in order. The first will be used for ops - * that cannot merge, and the second for those that can. + * Authoritative op list, used for generating the op ID enum, ID based LUTS, and + * the functions to which they dispatch. Parameter macros are executed for each op, + * in order, based on the op's type. * - * This serves as the authoritative list of ops, used for generating ID enum, and ID based LUTs. + * There are 4 types of op, which defines dispatch/LUT capability: + * + * | DisplayList | Render | Merge | + * -------------|-------------|-------------|-------------| + * PRE RENDER | Yes | | | + * RENDER ONLY | | Yes | | + * UNMERGEABLE | Yes | Yes | | + * MERGEABLE | Yes | Yes | Yes | + * + * PRE RENDER - These ops are recorded into DisplayLists, but can't be directly rendered. This + * may be because they need to be transformed into other op types (e.g. CirclePropsOp), + * be traversed to access multiple renderable ops within (e.g. RenderNodeOp), or because they + * modify renderbuffer lifecycle, instead of directly rendering content (the various LayerOps). + * + * RENDER ONLY - These ops cannot be recorded into DisplayLists, and are instead implicitly + * constructed from other commands/RenderNode properties. They cannot be merged. + * + * UNMERGEABLE - These ops can be recorded into DisplayLists and rendered directly, but do not + * support merged rendering. + * + * MERGEABLE - These ops can be recorded into DisplayLists and rendered individually, or merged + * under certain circumstances. */ -#define MAP_OPS_BASED_ON_MERGEABILITY(U_OP_FN, M_OP_FN) \ - U_OP_FN(ArcOp) \ - M_OP_FN(BitmapOp) \ - U_OP_FN(BitmapMeshOp) \ - U_OP_FN(BitmapRectOp) \ - U_OP_FN(CirclePropsOp) \ - U_OP_FN(FunctorOp) \ - U_OP_FN(LinesOp) \ - U_OP_FN(OvalOp) \ - M_OP_FN(PatchOp) \ - U_OP_FN(PathOp) \ - U_OP_FN(PointsOp) \ - U_OP_FN(RectOp) \ - U_OP_FN(RenderNodeOp) \ - U_OP_FN(RoundRectOp) \ - U_OP_FN(RoundRectPropsOp) \ - U_OP_FN(ShadowOp) \ - U_OP_FN(SimpleRectsOp) \ - M_OP_FN(TextOp) \ - U_OP_FN(TextOnPathOp) \ - U_OP_FN(TextureLayerOp) \ - U_OP_FN(BeginLayerOp) \ - U_OP_FN(EndLayerOp) \ - U_OP_FN(LayerOp) +#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) \ + \ + 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(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) /** - * The provided macro is executed for each op type in order. This is used in cases where - * merge-ability of ops doesn't matter. + * LUT generators, which will insert nullptr for unsupported ops */ -#define MAP_OPS(OP_FN) \ - MAP_OPS_BASED_ON_MERGEABILITY(OP_FN, OP_FN) +#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) } + +#define BUILD_MERGEABLE_OP_LUT(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) } +/** + * Op mapping functions, which skip unsupported ops. + * + * Note: Do not use for LUTS, since these do not preserve ID order. + */ #define NULL_OP_FN(Type) -#define MAP_MERGED_OPS(OP_FN) \ - MAP_OPS_BASED_ON_MERGEABILITY(NULL_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_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(IDENTITY_FN) + MAP_OPS_BASED_ON_TYPE(IDENTITY_FN, IDENTITY_FN, IDENTITY_FN, IDENTITY_FN) Count, }; } -static_assert(RecordedOpId::ArcOp == 0, +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 @@ -380,6 +427,46 @@ struct EndLayerOp : RecordedOp { : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {} }; +struct BeginUnclippedLayerOp : RecordedOp { + BeginUnclippedLayerOp(BASE_PARAMS) + : SUPER(BeginUnclippedLayerOp) {} +}; + +struct EndUnclippedLayerOp : RecordedOp { + EndUnclippedLayerOp() + : 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) + , layerHandle(layerHandle) {} + + // Records a handle to the Layer object, since the Layer itself won't be + // constructed until after this operation is constructed. + 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) + , layerHandle(layerHandle) {} + + // Records a handle to the Layer object, since the Layer itself won't be + // constructed until after this operation is constructed. + OffscreenBuffer** layerHandle; +}; + /** * Draws an OffscreenBuffer. * @@ -397,12 +484,12 @@ struct LayerOp : RecordedOp { , destroy(true) {} LayerOp(RenderNode& node) - : 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()) - , colorFilter(node.properties().layerProperties().colorFilter()) - , destroy(false) {} + : 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()) + , colorFilter(node.properties().layerProperties().colorFilter()) + , destroy(false) {} // Records a handle to the Layer object, since the Layer itself won't be // constructed until after this operation is constructed. diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp index f7f6caff22b6..78855e5d6a0a 100644 --- a/libs/hwui/RecordingCanvas.cpp +++ b/libs/hwui/RecordingCanvas.cpp @@ -43,10 +43,10 @@ void RecordingCanvas::reset(int width, int height) { mDeferredBarrierType = DeferredBarrierType::InOrder; mState.setDirtyClip(false); - mRestoreSaveCount = -1; } DisplayList* RecordingCanvas::finishRecording() { + restoreToCount(1); mPaintMap.clear(); mRegionMap.clear(); mPathMap.clear(); @@ -83,6 +83,8 @@ void RecordingCanvas::onViewportInitialized() { void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) { if (removed.flags & Snapshot::kFlagIsFboLayer) { addOp(new (alloc()) EndLayerOp()); + } else if (removed.flags & Snapshot::kFlagIsLayer) { + addOp(new (alloc()) EndUnclippedLayerOp()); } } @@ -95,28 +97,18 @@ int RecordingCanvas::save(SkCanvas::SaveFlags flags) { } void RecordingCanvas::RecordingCanvas::restore() { - if (mRestoreSaveCount < 0) { - restoreToCount(getSaveCount() - 1); - return; - } - - mRestoreSaveCount--; mState.restore(); } void RecordingCanvas::restoreToCount(int saveCount) { - mRestoreSaveCount = saveCount; mState.restoreToCount(saveCount); } -int RecordingCanvas::saveLayer(float left, float top, float right, float bottom, const SkPaint* paint, - SkCanvas::SaveFlags flags) { - if (!(flags & SkCanvas::kClipToLayer_SaveFlag)) { - LOG_ALWAYS_FATAL("unclipped layers not supported"); - } +int RecordingCanvas::saveLayer(float left, float top, float right, float bottom, + const SkPaint* paint, SkCanvas::SaveFlags flags) { // force matrix/clip isolation for layer flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag; - + bool clippedLayer = flags & SkCanvas::kClipToLayer_SaveFlag; const Snapshot& previous = *mState.currentSnapshot(); @@ -124,53 +116,70 @@ int RecordingCanvas::saveLayer(float left, float top, float right, float bottom, // operations will be able to store and restore the current clip and transform info, and // quick rejection will be correct (for display lists) - const Rect untransformedBounds(left, top, right, bottom); + const Rect unmappedBounds(left, top, right, bottom); // determine clipped bounds relative to previous viewport. - Rect visibleBounds = untransformedBounds; + Rect visibleBounds = unmappedBounds; previous.transform->mapRect(visibleBounds); + 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; + flags |= SkCanvas::kClipToLayer_SaveFlag; + } visibleBounds.doIntersect(previous.getRenderTargetClip()); visibleBounds.snapToPixelBoundaries(); - - Rect previousViewport(0, 0, previous.getViewportWidth(), previous.getViewportHeight()); - visibleBounds.doIntersect(previousViewport); + visibleBounds.doIntersect(Rect(previous.getViewportWidth(), previous.getViewportHeight())); // Map visible bounds back to layer space, and intersect with parameter bounds Rect layerBounds = visibleBounds; Matrix4 inverse; inverse.loadInverse(*previous.transform); inverse.mapRect(layerBounds); - layerBounds.doIntersect(untransformedBounds); + layerBounds.doIntersect(unmappedBounds); int saveValue = mState.save((int) flags); Snapshot& snapshot = *mState.writableSnapshot(); - // layerBounds is now original bounds, but with clipped to clip - // and viewport to ensure it's minimal size. - if (layerBounds.isEmpty() || untransformedBounds.isEmpty()) { + // layerBounds is in original bounds space, but clipped by current recording clip + if (layerBounds.isEmpty() || unmappedBounds.isEmpty()) { // Don't bother recording layer, since it's been rejected - snapshot.resetClip(0, 0, 0, 0); + if (CC_LIKELY(clippedLayer)) { + snapshot.resetClip(0, 0, 0, 0); + } return saveValue; } - auto previousClip = getRecordedClip(); // note: done while snapshot == previous + if (CC_LIKELY(clippedLayer)) { + auto previousClip = getRecordedClip(); // note: done before new snapshot's clip has changed - snapshot.flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer; - snapshot.initializeViewport(untransformedBounds.getWidth(), untransformedBounds.getHeight()); - snapshot.transform->loadTranslate(-untransformedBounds.left, -untransformedBounds.top, 0.0f); + snapshot.flags |= Snapshot::kFlagIsLayer | Snapshot::kFlagIsFboLayer; + snapshot.initializeViewport(unmappedBounds.getWidth(), unmappedBounds.getHeight()); + snapshot.transform->loadTranslate(-unmappedBounds.left, -unmappedBounds.top, 0.0f); - Rect clip = layerBounds; - clip.translate(-untransformedBounds.left, -untransformedBounds.top); - snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom); - snapshot.roundRectClipState = nullptr; + Rect clip = layerBounds; + clip.translate(-unmappedBounds.left, -unmappedBounds.top); + snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom); + snapshot.roundRectClipState = nullptr; - addOp(new (alloc()) BeginLayerOp( - Rect(left, top, right, bottom), - *previous.transform, // transform to *draw* with - previousClip, // clip to *draw* with - refPaint(paint))); + addOp(new (alloc()) BeginLayerOp( + unmappedBounds, + *previous.transform, // transform to *draw* with + previousClip, // clip to *draw* with + refPaint(paint))); + } else { + snapshot.flags |= Snapshot::kFlagIsLayer; + + addOp(new (alloc()) BeginUnclippedLayerOp( + unmappedBounds, + *mState.currentSnapshot()->transform, + getRecordedClip(), + refPaint(paint))); + } return saveValue; } diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h index 1a2ac97f5364..8aa750602972 100644 --- a/libs/hwui/RecordingCanvas.h +++ b/libs/hwui/RecordingCanvas.h @@ -314,7 +314,6 @@ private: DisplayList* mDisplayList = nullptr; bool mHighContrastText = false; SkAutoTUnref<SkDrawFilter> mDrawFilter; - int mRestoreSaveCount = -1; }; // class RecordingCanvas }; // namespace uirenderer diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h index 5fac3a1497c0..dbaa905b0728 100644 --- a/libs/hwui/Snapshot.h +++ b/libs/hwui/Snapshot.h @@ -116,7 +116,7 @@ public: * Indicates that this snapshot or an ancestor snapshot is * an FBO layer. */ - kFlagFboTarget = 0x8, + kFlagFboTarget = 0x8, // TODO: remove for HWUI_NEW_OPS }; /** diff --git a/libs/hwui/renderstate/OffscreenBufferPool.cpp b/libs/hwui/renderstate/OffscreenBufferPool.cpp index 6b44557a377b..227b6409b893 100644 --- a/libs/hwui/renderstate/OffscreenBufferPool.cpp +++ b/libs/hwui/renderstate/OffscreenBufferPool.cpp @@ -54,6 +54,12 @@ OffscreenBuffer::OffscreenBuffer(RenderState& renderState, Caches& caches, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } +Rect OffscreenBuffer::getTextureCoordinates() { + const float texX = 1.0f / float(texture.width); + const float texY = 1.0f / float(texture.height); + return Rect(0, viewportHeight * texY, viewportWidth * texX, 0); +} + void OffscreenBuffer::updateMeshFromRegion() { // avoid T-junctions as they cause artifacts in between the resultant // geometry when complex transforms occur. diff --git a/libs/hwui/renderstate/OffscreenBufferPool.h b/libs/hwui/renderstate/OffscreenBufferPool.h index fac6c35179d5..2d8d5295e1f8 100644 --- a/libs/hwui/renderstate/OffscreenBufferPool.h +++ b/libs/hwui/renderstate/OffscreenBufferPool.h @@ -46,6 +46,8 @@ public: uint32_t viewportWidth, uint32_t viewportHeight); ~OffscreenBuffer(); + Rect getTextureCoordinates(); + // must be called prior to rendering, to construct/update vertex buffer void updateMeshFromRegion(); diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h index ac14fc84b8a3..edde31e502e0 100644 --- a/libs/hwui/tests/common/TestUtils.h +++ b/libs/hwui/tests/common/TestUtils.h @@ -53,6 +53,13 @@ typedef DisplayListCanvas TestCanvas; && 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"; \ + } /** * Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope * (for e.g. accessing its RenderState) diff --git a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp index 78fcd8bf30ac..c89985009fbd 100644 --- a/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp +++ b/libs/hwui/tests/common/scenes/SaveLayerAnimation.cpp @@ -29,14 +29,27 @@ class SaveLayerAnimation : public TestScene { public: sp<RenderNode> card; void createContent(int width, int height, TestCanvas& canvas) override { - canvas.drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); // background + canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode); // background - card = TestUtils::createNode(0, 0, 200, 200, + card = TestUtils::createNode(0, 0, 400, 800, [](RenderProperties& props, TestCanvas& canvas) { - canvas.saveLayerAlpha(0, 0, 200, 200, 128, SkCanvas::kClipToLayer_SaveFlag); - canvas.drawColor(0xFF00FF00, SkXfermode::kSrcOver_Mode); // outer, unclipped - canvas.saveLayerAlpha(50, 50, 150, 150, 128, SkCanvas::kClipToLayer_SaveFlag); - canvas.drawColor(0xFF0000FF, SkXfermode::kSrcOver_Mode); // inner, clipped + // nested clipped saveLayers + canvas.saveLayerAlpha(0, 0, 400, 400, 200, SkCanvas::kClipToLayer_SaveFlag); + canvas.drawColor(Color::Green_700, SkXfermode::kSrcOver_Mode); + canvas.clipRect(50, 50, 350, 350, SkRegion::kIntersect_Op); + canvas.saveLayerAlpha(100, 100, 300, 300, 128, SkCanvas::kClipToLayer_SaveFlag); + canvas.drawColor(Color::Blue_500, SkXfermode::kSrcOver_Mode); + canvas.restore(); + canvas.restore(); + + // single unclipped saveLayer + canvas.save(SkCanvas::kMatrixClip_SaveFlag); + canvas.translate(0, 400); + canvas.saveLayerAlpha(100, 100, 300, 300, 128, SkCanvas::SaveFlags(0)); // unclipped + SkPaint paint; + paint.setAntiAlias(true); + paint.setColor(Color::Green_700); + canvas.drawCircle(200, 200, 200, paint); canvas.restore(); canvas.restore(); }); diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp index 2187654fb36c..e96e9ba55361 100644 --- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp +++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp @@ -15,11 +15,11 @@ */ #include <gtest/gtest.h> +#include <Rect.h> #include <renderstate/OffscreenBufferPool.h> #include <tests/common/TestUtils.h> -using namespace android; using namespace android::uirenderer; TEST(OffscreenBuffer, computeIdealDimension) { @@ -43,6 +43,18 @@ TEST(OffscreenBuffer, construct) { }); } +TEST(OffscreenBuffer, getTextureCoordinates) { + TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) { + OffscreenBuffer layerAligned(thread.renderState(), Caches::getInstance(), 256u, 256u); + EXPECT_EQ(Rect(0, 1, 1, 0), + layerAligned.getTextureCoordinates()); + + OffscreenBuffer layerUnaligned(thread.renderState(), Caches::getInstance(), 200u, 225u); + EXPECT_EQ(Rect(0, 225.0f / 256.0f, 200.0f / 256.0f, 0), + layerUnaligned.getTextureCoordinates()); + }); +} + TEST(OffscreenBufferPool, construct) { TestUtils::runOnRenderThread([] (renderthread::RenderThread& thread) { OffscreenBufferPool pool; @@ -51,7 +63,6 @@ TEST(OffscreenBufferPool, construct) { EXPECT_EQ((uint32_t) Properties::layerPoolSize, pool.getMaxSize()) << "pool must read size from Properties"; }); - } TEST(OffscreenBufferPool, getPutClear) { diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/OpReordererTests.cpp index 0d1311899586..701e4460c35f 100644 --- a/libs/hwui/tests/unit/OpReordererTests.cpp +++ b/libs/hwui/tests/unit/OpReordererTests.cpp @@ -71,7 +71,7 @@ public: virtual void on##Type(const Type&, const BakedOpState&) { \ ADD_FAILURE() << #Type " not expected in this test"; \ } - MAP_OPS(X) + MAP_RENDERABLE_OPS(X) #undef X // define virtual defaults for merged draw methods @@ -79,7 +79,7 @@ public: virtual void onMerged##Type##s(const MergedBakedOpList& opList) { \ ADD_FAILURE() << "Merged " #Type "s not expected in this test"; \ } - MAP_MERGED_OPS(X) + MAP_MERGEABLE_OPS(X) #undef X int getIndex() { return mIndex; } @@ -99,7 +99,7 @@ public: static void on##Type(TestRendererBase& renderer, const Type& op, const BakedOpState& state) { \ renderer.on##Type(op, state); \ } - MAP_OPS(X); + MAP_RENDERABLE_OPS(X); #undef X // define merged op methods, which redirect to TestRendererBase @@ -107,7 +107,7 @@ public: static void onMerged##Type##s(TestRendererBase& renderer, const MergedBakedOpList& opList) { \ renderer.onMerged##Type##s(opList); \ } - MAP_MERGED_OPS(X); + MAP_MERGEABLE_OPS(X); #undef X }; @@ -423,7 +423,7 @@ TEST(OpReorderer, clipped) { reorderer.replayBakedOps<TestDispatcher>(renderer); } -TEST(OpReorderer, saveLayerSimple) { +TEST(OpReorderer, saveLayer_simple) { class SaveLayerSimpleTestRenderer : public TestRendererBase { public: OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override { @@ -466,7 +466,7 @@ TEST(OpReorderer, saveLayerSimple) { EXPECT_EQ(4, renderer.getIndex()); } -TEST(OpReorderer, saveLayerNested) { +TEST(OpReorderer, saveLayer_nested) { /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as: * - startTemporaryLayer2, rect2 endLayer2 * - startTemporaryLayer1, rect1, drawLayer2, endLayer1 @@ -538,7 +538,7 @@ TEST(OpReorderer, saveLayerNested) { EXPECT_EQ(10, renderer.getIndex()); } -TEST(OpReorderer, saveLayerContentRejection) { +TEST(OpReorderer, saveLayer_contentRejection) { auto node = TestUtils::createNode(0, 0, 200, 200, [](RenderProperties& props, RecordingCanvas& canvas) { canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); @@ -559,7 +559,165 @@ TEST(OpReorderer, saveLayerContentRejection) { reorderer.replayBakedOps<TestDispatcher>(renderer); } -RENDERTHREAD_TEST(OpReorderer, hwLayerSimple) { +TEST(OpReorderer, saveLayerUnclipped_simple) { + class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase { + public: + void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { + EXPECT_EQ(0, mIndex++); + EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds); + EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState); + EXPECT_TRUE(state.computedState.transform.isIdentity()); + } + void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override { + EXPECT_EQ(1, mIndex++); + ASSERT_NE(nullptr, op.paint); + ASSERT_EQ(SkXfermode::kClear_Mode, PaintUtils::getXfermodeDirect(op.paint)); + } + void onRectOp(const RectOp& op, const BakedOpState& state) override { + EXPECT_EQ(2, mIndex++); + EXPECT_EQ(Rect(200, 200), op.unmappedBounds); + EXPECT_EQ(Rect(200, 200), state.computedState.clippedBounds); + EXPECT_EQ(Rect(200, 200), state.computedState.clipRect()); + EXPECT_TRUE(state.computedState.transform.isIdentity()); + } + void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override { + EXPECT_EQ(3, mIndex++); + EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds); + EXPECT_CLIP_RECT(Rect(200, 200), state.computedState.clipState); + EXPECT_TRUE(state.computedState.transform.isIdentity()); + } + }; + + auto node = TestUtils::createNode(0, 0, 200, 200, + [](RenderProperties& props, RecordingCanvas& canvas) { + canvas.saveLayerAlpha(10, 10, 190, 190, 128, SkCanvas::kMatrixClip_SaveFlag); + canvas.drawRect(0, 0, 200, 200, SkPaint()); + canvas.restore(); + }); + OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + createSyncedNodeList(node), sLightCenter); + SaveLayerUnclippedSimpleTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(4, renderer.getIndex()); +} + +TEST(OpReorderer, saveLayerUnclipped_mergedClears) { + class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase { + public: + void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { + int index = mIndex++; + EXPECT_GT(4, index); + EXPECT_EQ(5, op.unmappedBounds.getWidth()); + EXPECT_EQ(5, op.unmappedBounds.getHeight()); + if (index == 0) { + EXPECT_EQ(Rect(10, 10), state.computedState.clippedBounds); + } else if (index == 1) { + EXPECT_EQ(Rect(190, 0, 200, 10), state.computedState.clippedBounds); + } else if (index == 2) { + EXPECT_EQ(Rect(0, 190, 10, 200), state.computedState.clippedBounds); + } else if (index == 3) { + EXPECT_EQ(Rect(190, 190, 200, 200), state.computedState.clippedBounds); + } + } + void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override { + EXPECT_EQ(4, mIndex++); + ASSERT_EQ(op.vertexCount, 16u); + for (size_t i = 0; i < op.vertexCount; i++) { + auto v = op.vertices[i]; + EXPECT_TRUE(v.x == 0 || v.x == 10 || v.x == 190 || v.x == 200); + EXPECT_TRUE(v.y == 0 || v.y == 10 || v.y == 190 || v.y == 200); + } + } + void onRectOp(const RectOp& op, const BakedOpState& state) override { + EXPECT_EQ(5, mIndex++); + } + void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override { + EXPECT_LT(5, mIndex++); + } + }; + + auto node = TestUtils::createNode(0, 0, 200, 200, + [](RenderProperties& props, RecordingCanvas& canvas) { + + int restoreTo = canvas.save(SkCanvas::kMatrixClip_SaveFlag); + canvas.scale(2, 2); + canvas.saveLayerAlpha(0, 0, 5, 5, 128, SkCanvas::kMatrixClip_SaveFlag); + canvas.saveLayerAlpha(95, 0, 100, 5, 128, SkCanvas::kMatrixClip_SaveFlag); + canvas.saveLayerAlpha(0, 95, 5, 100, 128, SkCanvas::kMatrixClip_SaveFlag); + canvas.saveLayerAlpha(95, 95, 100, 100, 128, SkCanvas::kMatrixClip_SaveFlag); + canvas.drawRect(0, 0, 100, 100, SkPaint()); + canvas.restoreToCount(restoreTo); + }); + OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, + createSyncedNodeList(node), sLightCenter); + SaveLayerUnclippedMergedClearsTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(10, renderer.getIndex()) + << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect."; +} + +/* saveLayerUnclipped { saveLayer { saveLayerUnclipped { rect } } } will play back as: + * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer + * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe + */ +TEST(OpReorderer, saveLayerUnclipped_complex) { + class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase { + public: + OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) { + EXPECT_EQ(0, mIndex++); // savelayer first + return (OffscreenBuffer*)0xabcd; + } + void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override { + int index = mIndex++; + EXPECT_TRUE(index == 1 || index == 7); + } + void onSimpleRectsOp(const SimpleRectsOp& op, const BakedOpState& state) override { + int index = mIndex++; + EXPECT_TRUE(index == 2 || index == 8); + } + void onRectOp(const RectOp& op, const BakedOpState& state) override { + EXPECT_EQ(3, mIndex++); + Matrix4 expected; + expected.loadTranslate(-100, -100, 0); + EXPECT_EQ(Rect(100, 100, 200, 200), state.computedState.clippedBounds); + EXPECT_MATRIX_APPROX_EQ(expected, state.computedState.transform); + } + void onCopyFromLayerOp(const CopyFromLayerOp& op, const BakedOpState& state) override { + int index = mIndex++; + EXPECT_TRUE(index == 4 || index == 10); + } + void endLayer() override { + EXPECT_EQ(5, mIndex++); + } + void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override { + EXPECT_EQ(6, mIndex++); + } + void onLayerOp(const LayerOp& op, const BakedOpState& state) override { + EXPECT_EQ(9, mIndex++); + } + void endFrame(const Rect& repaintRect) override { + EXPECT_EQ(11, mIndex++); + } + }; + + auto node = TestUtils::createNode(0, 0, 600, 600, // 500x500 triggers clipping + [](RenderProperties& props, RecordingCanvas& canvas) { + canvas.saveLayerAlpha(0, 0, 500, 500, 128, (SkCanvas::SaveFlags)0); // unclipped + canvas.saveLayerAlpha(100, 100, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag); // clipped + canvas.saveLayerAlpha(200, 200, 300, 300, 128, (SkCanvas::SaveFlags)0); // unclipped + canvas.drawRect(200, 200, 300, 300, SkPaint()); + canvas.restore(); + canvas.restore(); + canvas.restore(); + }); + OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(600, 600), 600, 600, + createSyncedNodeList(node), sLightCenter); + SaveLayerUnclippedComplexTestRenderer renderer; + reorderer.replayBakedOps<TestDispatcher>(renderer); + EXPECT_EQ(12, renderer.getIndex()); +} + +RENDERTHREAD_TEST(OpReorderer, hwLayer_simple) { class HwLayerSimpleTestRenderer : public TestRendererBase { public: void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override { @@ -620,7 +778,7 @@ RENDERTHREAD_TEST(OpReorderer, hwLayerSimple) { *layerHandle = nullptr; } -RENDERTHREAD_TEST(OpReorderer, hwLayerComplex) { +RENDERTHREAD_TEST(OpReorderer, hwLayer_complex) { /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as: * - startRepaintLayer(child), rect(grey), endLayer * - startTemporaryLayer, drawLayer(child), endLayer diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp index a63cb18d7c4b..ff098c8bb3d5 100644 --- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp +++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp @@ -33,14 +33,6 @@ static void playbackOps(const DisplayList& displayList, } } -#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"; \ - } - TEST(RecordingCanvas, emptyPlayback) { auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) { canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); @@ -232,7 +224,7 @@ TEST(RecordingCanvas, backgroundAndImage) { TEST(RecordingCanvas, saveLayer_simple) { auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { - canvas.saveLayerAlpha(10, 20, 190, 180, 128, SkCanvas::kARGB_ClipLayer_SaveFlag); + canvas.saveLayerAlpha(10, 20, 190, 180, 128, SkCanvas::kClipToLayer_SaveFlag); canvas.drawRect(10, 20, 190, 180, SkPaint()); canvas.restore(); }); @@ -264,12 +256,78 @@ TEST(RecordingCanvas, saveLayer_simple) { EXPECT_EQ(3, count); } +TEST(RecordingCanvas, saveLayer_missingRestore) { + auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { + canvas.saveLayerAlpha(0, 0, 200, 200, 128, SkCanvas::kClipToLayer_SaveFlag); + canvas.drawRect(0, 0, 200, 200, SkPaint()); + // Note: restore omitted, shouldn't result in unmatched save + }); + int count = 0; + playbackOps(*dl, [&count](const RecordedOp& op) { + if (count++ == 2) { + EXPECT_EQ(RecordedOpId::EndLayerOp, op.opId); + } + }); + EXPECT_EQ(3, count) << "Missing a restore shouldn't result in an unmatched saveLayer"; +} + +TEST(RecordingCanvas, saveLayer_simpleUnclipped) { + auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { + canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SkCanvas::SaveFlags)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(); + } + }); + EXPECT_EQ(3, count); +} + +TEST(RecordingCanvas, saveLayer_addClipFlag) { + auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { + canvas.save(SkCanvas::kMatrixClip_SaveFlag); + canvas.clipRect(10, 20, 190, 180, SkRegion::kIntersect_Op); + canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SkCanvas::SaveFlags)0); // unclipped + canvas.drawRect(10, 20, 190, 180, SkPaint()); + canvas.restore(); + canvas.restore(); + }); + int count = 0; + playbackOps(*dl, [&count](const RecordedOp& op) { + if (count++ == 0) { + EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId) + << "Clip + unclipped saveLayer should result in a clipped layer"; + } + }); + EXPECT_EQ(3, count); +} + TEST(RecordingCanvas, saveLayer_viewportCrop) { auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) { // shouldn't matter, since saveLayer will clip to its bounds canvas.clipRect(-1000, -1000, 1000, 1000, SkRegion::kReplace_Op); - canvas.saveLayerAlpha(100, 100, 300, 300, 128, SkCanvas::kARGB_ClipLayer_SaveFlag); + canvas.saveLayerAlpha(100, 100, 300, 300, 128, SkCanvas::kClipToLayer_SaveFlag); canvas.drawRect(0, 0, 400, 400, SkPaint()); canvas.restore(); }); @@ -295,7 +353,7 @@ TEST(RecordingCanvas, saveLayer_rotateUnclipped) { canvas.rotate(45); canvas.translate(-50, -50); - canvas.saveLayerAlpha(0, 0, 100, 100, 128, SkCanvas::kARGB_ClipLayer_SaveFlag); + canvas.saveLayerAlpha(0, 0, 100, 100, 128, SkCanvas::kClipToLayer_SaveFlag); canvas.drawRect(0, 0, 100, 100, SkPaint()); canvas.restore(); @@ -322,7 +380,7 @@ TEST(RecordingCanvas, saveLayer_rotateClipped) { canvas.translate(-200, -200); // area of saveLayer will be clipped to parent viewport, so we ask for 400x400... - canvas.saveLayerAlpha(0, 0, 400, 400, 128, SkCanvas::kARGB_ClipLayer_SaveFlag); + canvas.saveLayerAlpha(0, 0, 400, 400, 128, SkCanvas::kClipToLayer_SaveFlag); canvas.drawRect(0, 0, 400, 400, SkPaint()); canvas.restore(); diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index c658675d8a7c..a09240852a38 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -176,6 +176,16 @@ public class AudioManager { "android.media.MASTER_MUTE_CHANGED_ACTION"; /** + * @hide Broadcast intent when the master mono state changes. + * Includes the new mono state + * + * @see #EXTRA_MASTER_MONO + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String MASTER_MONO_CHANGED_ACTION = + "android.media.MASTER_MONO_CHANGED_ACTION"; + + /** * The new vibrate setting for a particular type. * * @see #VIBRATE_SETTING_CHANGED_ACTION @@ -254,6 +264,13 @@ public class AudioManager { "android.media.EXTRA_STREAM_VOLUME_MUTED"; /** + * @hide The new master mono state for the master mono changed intent. + * Value is boolean + */ + public static final String EXTRA_MASTER_MONO = + "android.media.EXTRA_MASTER_MONO"; + + /** * Broadcast Action: Wired Headset plugged in or unplugged. * * You <em>cannot</em> receive this through components declared @@ -880,6 +897,17 @@ public class AudioManager { } } + /** @hide */ + public void setMasterMono(boolean mono) { + IAudioService service = getService(); + try { + service.setMasterMono(mono, getContext().getOpPackageName(), + UserHandle.getCallingUserId()); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in setMasterMono", e); + } + } + /** * Returns the current ringtone mode. * @@ -1142,6 +1170,21 @@ public class AudioManager { } /** + * get master mono state. + * + * @hide + */ + public boolean isMasterMono() { + IAudioService service = getService(); + try { + return service.isMasterMono(); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in isMasterMono", e); + return false; + } + } + + /** * forces the stream controlled by hard volume keys * specifying streamType == -1 releases control to the * logic. diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index c59d1c7b9999..7bfd7ca4d56d 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -624,6 +624,11 @@ public class AudioSystem public static native boolean getMasterMute(); public static native int getDevicesForStream(int stream); + /** @hide returns true if master mono is enabled. */ + public static native boolean getMasterMono(); + /** @hide enables or disables the master mono mode. */ + public static native int setMasterMono(boolean mono); + // helpers for android.media.AudioManager.getProperty(), see description there for meaning public static native int getPrimaryOutputSamplingRate(); public static native int getPrimaryOutputFrameCount(); diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index bb4f7d9b7ad9..a810ff1bc2ba 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -97,9 +97,10 @@ public class AudioTrack /** Maximum value for sample rate */ private static final int SAMPLE_RATE_HZ_MAX = 192000; - // FCC_8 - /** Maximum value for AudioTrack channel count */ - private static final int CHANNEL_COUNT_MAX = 8; + /** Maximum value for AudioTrack channel count + * @hide public for MediaCode only, do not un-hide or change to a numeric literal + */ + public static final int CHANNEL_COUNT_MAX = native_get_FCC_8(); /** indicates AudioTrack state is stopped */ public static final int PLAYSTATE_STOPPED = 1; // matches SL_PLAYSTATE_STOPPED @@ -2583,6 +2584,7 @@ public class AudioTrack private native final int native_getRoutedDeviceId(); private native final void native_enableDeviceCallback(); private native final void native_disableDeviceCallback(); + static private native int native_get_FCC_8(); //--------------------------------------------------------- // Utility methods diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 693a519c234f..dbb7661046c3 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -52,6 +52,10 @@ interface IAudioService { void setMasterMute(boolean mute, int flags, String callingPackage, int userId); + boolean isMasterMono(); + + void setMasterMono(boolean mute, String callingPackage, int userId); + int getStreamVolume(int streamType); int getStreamMinVolume(int streamType); diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java index e6bc8f1048b6..9bcb5e35938b 100644 --- a/media/java/android/media/MediaCodecInfo.java +++ b/media/java/android/media/MediaCodecInfo.java @@ -907,7 +907,7 @@ public final class MediaCodecInfo { } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_RAW)) { sampleRateRange = Range.create(1, 96000); bitRates = Range.create(1, 10000000); - maxChannels = 8; + maxChannels = AudioTrack.CHANNEL_COUNT_MAX; } else if (mime.equalsIgnoreCase(MediaFormat.MIMETYPE_AUDIO_FLAC)) { sampleRateRange = Range.create(1, 655350); // lossless codec, so bitrate is ignored diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java index 41b369dc38ae..dd069218463a 100644 --- a/media/java/android/media/MediaInserter.java +++ b/media/java/android/media/MediaInserter.java @@ -16,8 +16,8 @@ package android.media; +import android.content.ContentProviderClient; import android.content.ContentValues; -import android.content.IContentProvider; import android.net.Uri; import android.os.RemoteException; @@ -37,13 +37,11 @@ public class MediaInserter { private final HashMap<Uri, List<ContentValues>> mPriorityRowMap = new HashMap<Uri, List<ContentValues>>(); - private final IContentProvider mProvider; - private final String mPackageName; + private final ContentProviderClient mProvider; private final int mBufferSizePerUri; - public MediaInserter(IContentProvider provider, String packageName, int bufferSizePerUri) { + public MediaInserter(ContentProviderClient provider, int bufferSizePerUri) { mProvider = provider; - mPackageName = packageName; mBufferSizePerUri = bufferSizePerUri; } @@ -90,7 +88,7 @@ public class MediaInserter { if (!list.isEmpty()) { ContentValues[] valuesArray = new ContentValues[list.size()]; valuesArray = list.toArray(valuesArray); - mProvider.bulkInsert(mPackageName, tableUri, valuesArray); + mProvider.bulkInsert(tableUri, valuesArray); list.clear(); } } diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java index 9ea672287d88..96c616be359d 100644 --- a/media/java/android/media/MediaScanner.java +++ b/media/java/android/media/MediaScanner.java @@ -16,14 +16,10 @@ package android.media; -import org.xml.sax.Attributes; -import org.xml.sax.ContentHandler; -import org.xml.sax.SAXException; - +import android.content.ContentProviderClient; import android.content.ContentUris; import android.content.ContentValues; import android.content.Context; -import android.content.IContentProvider; import android.database.Cursor; import android.database.SQLException; import android.drm.DrmManagerClient; @@ -50,6 +46,12 @@ import android.text.TextUtils; import android.util.Log; import android.util.Xml; +import dalvik.system.CloseGuard; + +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.SAXException; + import java.io.BufferedReader; import java.io.File; import java.io.FileDescriptor; @@ -61,6 +63,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; +import java.util.concurrent.atomic.AtomicBoolean; /** * Internal service helper that no-one should use directly. @@ -107,8 +110,7 @@ import java.util.Locale; * * {@hide} */ -public class MediaScanner -{ +public class MediaScanner implements AutoCloseable { static { System.loadLibrary("media_jni"); native_init(); @@ -302,21 +304,23 @@ public class MediaScanner }; private long mNativeContext; - private Context mContext; - private String mPackageName; - private IContentProvider mMediaProvider; - private Uri mAudioUri; - private Uri mVideoUri; - private Uri mImagesUri; - private Uri mThumbsUri; - private Uri mPlaylistsUri; - private Uri mFilesUri; - private Uri mFilesUriNoNotify; - private boolean mProcessPlaylists, mProcessGenres; + private final Context mContext; + private final String mPackageName; + private final String mVolumeName; + private final ContentProviderClient mMediaProvider; + private final Uri mAudioUri; + private final Uri mVideoUri; + private final Uri mImagesUri; + private final Uri mThumbsUri; + private final Uri mPlaylistsUri; + private final Uri mFilesUri; + private final Uri mFilesUriNoNotify; + private final boolean mProcessPlaylists; + private final boolean mProcessGenres; private int mMtpObjectHandle; - private final String mExternalStoragePath; - private final boolean mExternalIsEmulated; + private final AtomicBoolean mClosed = new AtomicBoolean(); + private final CloseGuard mCloseGuard = CloseGuard.get(); /** whether to use bulk inserts or individual inserts for each item */ private static final boolean ENABLE_BULK_INSERTS = true; @@ -345,10 +349,6 @@ public class MediaScanner */ private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config."; - // set to true if file path comparisons should be case insensitive. - // this should be set when scanning files on a case insensitive file system. - private boolean mCaseInsensitivePaths; - private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); private static class FileEntry { @@ -378,26 +378,59 @@ public class MediaScanner int bestmatchlevel; } - private ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<PlaylistEntry>(); + private final ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<>(); + private final ArrayList<FileEntry> mPlayLists = new ArrayList<>(); private MediaInserter mMediaInserter; - private ArrayList<FileEntry> mPlayLists; - private DrmManagerClient mDrmManagerClient = null; - public MediaScanner(Context c) { + public MediaScanner(Context c, String volumeName) { native_setup(); mContext = c; mPackageName = c.getPackageName(); + mVolumeName = volumeName; + mBitmapOptions.inSampleSize = 1; mBitmapOptions.inJustDecodeBounds = true; setDefaultRingtoneFileNames(); - mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath(); - mExternalIsEmulated = Environment.isExternalStorageEmulated(); - //mClient.testGenreNameConverter(); + mMediaProvider = mContext.getContentResolver() + .acquireContentProviderClient(MediaStore.AUTHORITY); + + mAudioUri = Audio.Media.getContentUri(volumeName); + mVideoUri = Video.Media.getContentUri(volumeName); + mImagesUri = Images.Media.getContentUri(volumeName); + mThumbsUri = Images.Thumbnails.getContentUri(volumeName); + mFilesUri = Files.getContentUri(volumeName); + mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build(); + + if (!volumeName.equals("internal")) { + // we only support playlists on external media + mProcessPlaylists = true; + mProcessGenres = true; + mPlaylistsUri = Playlists.getContentUri(volumeName); + } else { + mProcessPlaylists = false; + mProcessGenres = false; + mPlaylistsUri = null; + } + + final Locale locale = mContext.getResources().getConfiguration().locale; + if (locale != null) { + String language = locale.getLanguage(); + String country = locale.getCountry(); + if (language != null) { + if (country != null) { + setLocale(language + "_" + country); + } else { + setLocale(language); + } + } + } + + mCloseGuard.open("close"); } private void setDefaultRingtoneFileNames() { @@ -956,7 +989,7 @@ public class MediaScanner if (inserter != null) { inserter.flushAll(); } - result = mMediaProvider.insert(mPackageName, tableUri, values); + result = mMediaProvider.insert(tableUri, values); } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) { inserter.insertwithPriority(tableUri, values); } else { @@ -988,7 +1021,7 @@ public class MediaScanner } values.put(FileColumns.MEDIA_TYPE, mediaType); } - mMediaProvider.update(mPackageName, result, values, null, null); + mMediaProvider.update(result, values, null, null); } if(needToSetSettings) { @@ -1055,11 +1088,7 @@ public class MediaScanner String where = null; String[] selectionArgs = null; - if (mPlayLists == null) { - mPlayLists = new ArrayList<FileEntry>(); - } else { - mPlayLists.clear(); - } + mPlayLists.clear(); if (filePath != null) { // query for only one file @@ -1077,8 +1106,7 @@ public class MediaScanner // filesystem is mounted and unmounted while the scanner is running). Uri.Builder builder = mFilesUri.buildUpon(); builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false"); - MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, mPackageName, - builder.build()); + MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build()); // Build the list of files from the content provider try { @@ -1097,7 +1125,7 @@ public class MediaScanner c.close(); c = null; } - c = mMediaProvider.query(mPackageName, limitUri, FILES_PRESCAN_PROJECTION, + c = mMediaProvider.query(limitUri, FILES_PRESCAN_PROJECTION, where, selectionArgs, MediaStore.Files.FileColumns._ID, null); if (c == null) { break; @@ -1138,8 +1166,7 @@ public class MediaScanner if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) { deleter.flush(); String parent = new File(path).getParent(); - mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, - parent, null); + mMediaProvider.call(MediaStore.UNHIDE_CALL, parent, null); } } } @@ -1157,7 +1184,7 @@ public class MediaScanner // compute original size of images mOriginalCount = 0; - c = mMediaProvider.query(mPackageName, mImagesUri, ID_PROJECTION, null, null, null, null); + c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null); if (c != null) { mOriginalCount = c.getCount(); c.close(); @@ -1189,7 +1216,6 @@ public class MediaScanner try { c = mMediaProvider.query( - mPackageName, mThumbsUri, new String [] { "_data" }, null, @@ -1225,13 +1251,11 @@ public class MediaScanner static class MediaBulkDeleter { StringBuilder whereClause = new StringBuilder(); ArrayList<String> whereArgs = new ArrayList<String>(100); - final IContentProvider mProvider; - final String mPackageName; + final ContentProviderClient mProvider; final Uri mBaseUri; - public MediaBulkDeleter(IContentProvider provider, String packageName, Uri baseUri) { + public MediaBulkDeleter(ContentProviderClient provider, Uri baseUri) { mProvider = provider; - mPackageName = packageName; mBaseUri = baseUri; } @@ -1250,7 +1274,7 @@ public class MediaScanner if (size > 0) { String [] foo = new String [size]; foo = whereArgs.toArray(foo); - int numrows = mProvider.delete(mPackageName, mBaseUri, + int numrows = mProvider.delete(mBaseUri, MediaStore.MediaColumns._ID + " IN (" + whereClause.toString() + ")", foo); //Log.i("@@@@@@@@@", "rows deleted: " + numrows); @@ -1271,48 +1295,26 @@ public class MediaScanner pruneDeadThumbnailFiles(); // allow GC to clean up - mPlayLists = null; - mMediaProvider = null; + mPlayLists.clear(); } private void releaseResources() { // release the DrmManagerClient resources if (mDrmManagerClient != null) { - mDrmManagerClient.release(); + mDrmManagerClient.close(); mDrmManagerClient = null; } } - private void initialize(String volumeName) { - mMediaProvider = mContext.getContentResolver().acquireProvider("media"); - - mAudioUri = Audio.Media.getContentUri(volumeName); - mVideoUri = Video.Media.getContentUri(volumeName); - mImagesUri = Images.Media.getContentUri(volumeName); - mThumbsUri = Images.Thumbnails.getContentUri(volumeName); - mFilesUri = Files.getContentUri(volumeName); - mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build(); - - if (!volumeName.equals("internal")) { - // we only support playlists on external media - mProcessPlaylists = true; - mProcessGenres = true; - mPlaylistsUri = Playlists.getContentUri(volumeName); - - mCaseInsensitivePaths = true; - } - } - - public void scanDirectories(String[] directories, String volumeName) { + public void scanDirectories(String[] directories) { try { long start = System.currentTimeMillis(); - initialize(volumeName); prescan(null, true); long prescan = System.currentTimeMillis(); if (ENABLE_BULK_INSERTS) { // create MediaInserter for bulk inserts - mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500); + mMediaInserter = new MediaInserter(mMediaProvider, 500); } for (int i = 0; i < directories.length; i++) { @@ -1349,9 +1351,8 @@ public class MediaScanner } // this function is used to scan a single file - public Uri scanSingleFile(String path, String volumeName, String mimeType) { + public Uri scanSingleFile(String path, String mimeType) { try { - initialize(volumeName); prescan(path, true); File file = new File(path); @@ -1464,8 +1465,7 @@ public class MediaScanner return isNoMediaFile(path); } - public void scanMtpFile(String path, String volumeName, int objectHandle, int format) { - initialize(volumeName); + public void scanMtpFile(String path, int objectHandle, int format) { MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path); int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType); File file = new File(path); @@ -1481,7 +1481,7 @@ public class MediaScanner values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds); try { String[] whereArgs = new String[] { Integer.toString(objectHandle) }; - mMediaProvider.update(mPackageName, Files.getMtpObjectsUri(volumeName), values, + mMediaProvider.update(Files.getMtpObjectsUri(mVolumeName), values, "_id=?", whereArgs); } catch (RemoteException e) { Log.e(TAG, "RemoteException in scanMtpFile", e); @@ -1498,7 +1498,7 @@ public class MediaScanner FileEntry entry = makeEntryFor(path); if (entry != null) { - fileList = mMediaProvider.query(mPackageName, mFilesUri, + fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION, null, null, null, null); processPlayList(entry, fileList); } @@ -1529,7 +1529,7 @@ public class MediaScanner try { where = Files.FileColumns.DATA + "=?"; selectionArgs = new String[] { path }; - c = mMediaProvider.query(mPackageName, mFilesUriNoNotify, FILES_PRESCAN_PROJECTION, + c = mMediaProvider.query(mFilesUriNoNotify, FILES_PRESCAN_PROJECTION, where, selectionArgs, null, null); if (c.moveToFirst()) { long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX); @@ -1641,7 +1641,7 @@ public class MediaScanner values.clear(); values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index)); values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid)); - mMediaProvider.insert(mPackageName, playlistUri, values); + mMediaProvider.insert(playlistUri, values); index++; } catch (RemoteException e) { Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e); @@ -1806,16 +1806,16 @@ public class MediaScanner if (rowId == 0) { values.put(MediaStore.Audio.Playlists.DATA, path); - uri = mMediaProvider.insert(mPackageName, mPlaylistsUri, values); + uri = mMediaProvider.insert(mPlaylistsUri, values); rowId = ContentUris.parseId(uri); membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); } else { uri = ContentUris.withAppendedId(mPlaylistsUri, rowId); - mMediaProvider.update(mPackageName, uri, values, null, null); + mMediaProvider.update(uri, values, null, null); // delete members of existing playlist membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY); - mMediaProvider.delete(mPackageName, membersUri, null, null); + mMediaProvider.delete(membersUri, null, null); } String playListDirectory = path.substring(0, lastSlash + 1); @@ -1837,7 +1837,7 @@ public class MediaScanner try { // use the files uri and projection because we need the format column, // but restrict the query to just audio files - fileList = mMediaProvider.query(mPackageName, mFilesUri, FILES_PRESCAN_PROJECTION, + fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION, "media_type=2", null, null, null); while (iterator.hasNext()) { FileEntry entry = iterator.next(); @@ -1856,7 +1856,7 @@ public class MediaScanner private native void processDirectory(String path, MediaScannerClient client); private native void processFile(String path, String mimeType, MediaScannerClient client); - public native void setLocale(String locale); + private native void setLocale(String locale); public native byte[] extractAlbumArt(FileDescriptor fd); @@ -1864,19 +1864,22 @@ public class MediaScanner private native final void native_setup(); private native final void native_finalize(); - /** - * Releases resources associated with this MediaScanner object. - * It is considered good practice to call this method when - * one is done using the MediaScanner object. After this method - * is called, the MediaScanner object can no longer be used. - */ - public void release() { - native_finalize(); + @Override + public void close() { + mCloseGuard.close(); + if (mClosed.compareAndSet(false, true)) { + mMediaProvider.close(); + native_finalize(); + } } @Override - protected void finalize() { - mContext.getContentResolver().releaseProvider(mMediaProvider); - native_finalize(); + protected void finalize() throws Throwable { + try { + mCloseGuard.warnIfOpen(); + close(); + } finally { + super.finalize(); + } } } diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java index d245f5886859..b2a5a444d0f7 100644 --- a/media/java/android/mtp/MtpConstants.java +++ b/media/java/android/mtp/MtpConstants.java @@ -573,4 +573,112 @@ public final class MtpConstants { * Association type for objects representing file system directories. */ public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 0x0001; + + /** Event code for UNDEFINED event */ + public static final int EVENT_UNDEFINED = 0x4000; + /** Event code for CANCEL_TRANSACTION event */ + public static final int EVENT_CANCEL_TRANSACTION = 0x4001; + /** Event code for OBJECT_ADDED event */ + public static final int EVENT_OBJECT_ADDED = 0x4002; + /** Event code for OBJECT_REMOVED event */ + public static final int EVENT_OBJECT_REMOVED = 0x4003; + /** Event code for STORE_ADDED event */ + public static final int EVENT_STORE_ADDED = 0x4004; + /** Event code for STORE_REMOVED event */ + public static final int EVENT_STORE_REMOVED = 0x4005; + /** Event code for DEVICE_PROP_CHANGED event */ + public static final int EVENT_DEVICE_PROP_CHANGED = 0x4006; + /** Event code for OBJECT_INFO_CHANGED event */ + public static final int EVENT_OBJECT_INFO_CHANGED = 0x4007; + /** Event code for DEVICE_INFO_CHANGED event */ + public static final int EVENT_DEVICE_INFO_CHANGED = 0x4008; + /** Event code for REQUEST_OBJECT_TRANSFER event */ + public static final int EVENT_REQUEST_OBJECT_TRANSFER = 0x4009; + /** Event code for STORE_FULL event */ + public static final int EVENT_STORE_FULL = 0x400A; + /** Event code for DEVICE_RESET event */ + public static final int EVENT_DEVICE_RESET = 0x400B; + /** Event code for STORAGE_INFO_CHANGED event */ + public static final int EVENT_STORAGE_INFO_CHANGED = 0x400C; + /** Event code for CAPTURE_COMPLETE event */ + public static final int EVENT_CAPTURE_COMPLETE = 0x400D; + /** Event code for UNREPORTED_STATUS event */ + public static final int EVENT_UNREPORTED_STATUS = 0x400E; + /** Event code for OBJECT_PROP_CHANGED event */ + public static final int EVENT_OBJECT_PROP_CHANGED = 0xC801; + /** Event code for OBJECT_PROP_DESC_CHANGED event */ + public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802; + /** Event code for OBJECT_REFERENCES_CHANGED event */ + public static final int EVENT_OBJECT_REFERENCES_CHANGED = 0xC803; + + /** Operation code for GetDeviceInfo */ + public static final int OPERATION_GET_DEVICE_INFO = 0x1001; + /** Operation code for OpenSession */ + public static final int OPERATION_OPEN_SESSION = 0x1002; + /** Operation code for CloseSession */ + public static final int OPERATION_CLOSE_SESSION = 0x1003; + /** Operation code for GetStorageIDs */ + public static final int OPERATION_GET_STORAGE_I_DS = 0x1004; + /** Operation code for GetStorageInfo */ + public static final int OPERATION_GET_STORAGE_INFO = 0x1005; + /** Operation code for GetNumObjects */ + public static final int OPERATION_GET_NUM_OBJECTS = 0x1006; + /** Operation code for GetObjectHandles */ + public static final int OPERATION_GET_OBJECT_HANDLES = 0x1007; + /** Operation code for GetObjectInfo */ + public static final int OPERATION_GET_OBJECT_INFO = 0x1008; + /** Operation code for GetObject */ + public static final int OPERATION_GET_OBJECT = 0x1009; + /** Operation code for GetThumb */ + public static final int OPERATION_GET_THUMB = 0x100A; + /** Operation code for DeleteObject */ + public static final int OPERATION_DELETE_OBJECT = 0x100B; + /** Operation code for SendObjectInfo */ + public static final int OPERATION_SEND_OBJECT_INFO = 0x100C; + /** Operation code for SendObject */ + public static final int OPERATION_SEND_OBJECT = 0x100D; + /** Operation code for InitiateCapture */ + public static final int OPERATION_INITIATE_CAPTURE = 0x100E; + /** Operation code for FormatStore */ + public static final int OPERATION_FORMAT_STORE = 0x100F; + /** Operation code for ResetDevice */ + public static final int OPERATION_RESET_DEVICE = 0x1010; + /** Operation code for SelfTest */ + public static final int OPERATION_SELF_TEST = 0x1011; + /** Operation code for SetObjectProtection */ + public static final int OPERATION_SET_OBJECT_PROTECTION = 0x1012; + /** Operation code for PowerDown */ + public static final int OPERATION_POWER_DOWN = 0x1013; + /** Operation code for GetDevicePropDesc */ + public static final int OPERATION_GET_DEVICE_PROP_DESC = 0x1014; + /** Operation code for GetDevicePropValue */ + public static final int OPERATION_GET_DEVICE_PROP_VALUE = 0x1015; + /** Operation code for SetDevicePropValue */ + public static final int OPERATION_SET_DEVICE_PROP_VALUE = 0x1016; + /** Operation code for ResetDevicePropValue */ + public static final int OPERATION_RESET_DEVICE_PROP_VALUE = 0x1017; + /** Operation code for TerminateOpenCapture */ + public static final int OPERATION_TERMINATE_OPEN_CAPTURE = 0x1018; + /** Operation code for MoveObject */ + public static final int OPERATION_MOVE_OBJECT = 0x1019; + /** Operation code for CopyObject */ + public static final int OPERATION_COPY_OBJECT = 0x101A; + /** Operation code for GetPartialObject */ + public static final int OPERATION_GET_PARTIAL_OBJECT = 0x101B; + /** Operation code for InitiateOpenCapture */ + public static final int OPERATION_INITIATE_OPEN_CAPTURE = 0x101C; + /** Operation code for GetObjectPropsSupported */ + public static final int OPERATION_GET_OBJECT_PROPS_SUPPORTED = 0x9801; + /** Operation code for GetObjectPropDesc */ + public static final int OPERATION_GET_OBJECT_PROP_DESC = 0x9802; + /** Operation code for GetObjectPropValue */ + public static final int OPERATION_GET_OBJECT_PROP_VALUE = 0x9803; + /** Operation code for SetObjectPropValue */ + public static final int OPERATION_SET_OBJECT_PROP_VALUE = 0x9804; + /** Operation code for GetObjectReferences */ + public static final int OPERATION_GET_OBJECT_REFERENCES = 0x9810; + /** Operation code for SetObjectReferences */ + public static final int OPERATION_SET_OBJECT_REFERENCES = 0x9811; + /** Operation code for Skip */ + public static final int OPERATION_SKIP = 0x9820; } diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java index 3541fba7f3b1..bc96e2ea8989 100755 --- a/media/java/android/mtp/MtpDatabase.java +++ b/media/java/android/mtp/MtpDatabase.java @@ -17,9 +17,9 @@ package android.mtp; import android.content.BroadcastReceiver; -import android.content.Context; +import android.content.ContentProviderClient; import android.content.ContentValues; -import android.content.IContentProvider; +import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; @@ -37,23 +37,30 @@ import android.util.Log; import android.view.Display; import android.view.WindowManager; +import dalvik.system.CloseGuard; + import java.io.File; import java.io.IOException; import java.util.HashMap; import java.util.Locale; +import java.util.concurrent.atomic.AtomicBoolean; /** * {@hide} */ -public class MtpDatabase { - +public class MtpDatabase implements AutoCloseable { private static final String TAG = "MtpDatabase"; private final Context mContext; private final String mPackageName; - private final IContentProvider mMediaProvider; + private final ContentProviderClient mMediaProvider; private final String mVolumeName; private final Uri mObjectsUri; + private final MediaScanner mMediaScanner; + + private final AtomicBoolean mClosed = new AtomicBoolean(); + private final CloseGuard mCloseGuard = CloseGuard.get(); + // path to primary storage private final String mMediaStoragePath; // if not null, restrict all queries to these subdirectories @@ -120,7 +127,6 @@ public class MtpDatabase { private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND " + Files.FileColumns.PARENT + "=?"; - private final MediaScanner mMediaScanner; private MtpServer mServer; // read from native code @@ -156,11 +162,12 @@ public class MtpDatabase { mContext = context; mPackageName = context.getPackageName(); - mMediaProvider = context.getContentResolver().acquireProvider("media"); + mMediaProvider = context.getContentResolver() + .acquireContentProviderClient(MediaStore.AUTHORITY); mVolumeName = volumeName; mMediaStoragePath = storagePath; mObjectsUri = Files.getMtpObjectsUri(volumeName); - mMediaScanner = new MediaScanner(context); + mMediaScanner = new MediaScanner(context, mVolumeName); mSubDirectories = subDirectories; if (subDirectories != null) { @@ -187,20 +194,9 @@ public class MtpDatabase { } } - // Set locale to MediaScanner. - Locale locale = context.getResources().getConfiguration().locale; - if (locale != null) { - String language = locale.getLanguage(); - String country = locale.getCountry(); - if (language != null) { - if (country != null) { - mMediaScanner.setLocale(language + "_" + country); - } else { - mMediaScanner.setLocale(language); - } - } - } initDeviceProperties(context); + + mCloseGuard.open("close"); } public void setServer(MtpServer server) { @@ -221,9 +217,20 @@ public class MtpDatabase { } @Override + public void close() { + mCloseGuard.close(); + if (mClosed.compareAndSet(false, true)) { + mMediaScanner.close(); + mMediaProvider.close(); + native_finalize(); + } + } + + @Override protected void finalize() throws Throwable { try { - native_finalize(); + mCloseGuard.warnIfOpen(); + close(); } finally { super.finalize(); } @@ -334,7 +341,7 @@ public class MtpDatabase { if (path != null) { Cursor c = null; try { - c = mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, PATH_WHERE, + c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE, new String[] { path }, null, null); if (c != null && c.getCount() > 0) { Log.w(TAG, "file already exists in beginSendObject: " + path); @@ -359,7 +366,7 @@ public class MtpDatabase { values.put(Files.FileColumns.DATE_MODIFIED, modified); try { - Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values); + Uri uri = mMediaProvider.insert(mObjectsUri, values); if (uri != null) { return Integer.parseInt(uri.getPathSegments().get(2)); } else { @@ -394,13 +401,13 @@ public class MtpDatabase { values.put(Files.FileColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000); values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle); try { - Uri uri = mMediaProvider.insert(mPackageName, + Uri uri = mMediaProvider.insert( Audio.Playlists.EXTERNAL_CONTENT_URI, values); } catch (RemoteException e) { Log.e(TAG, "RemoteException in endSendObject", e); } } else { - mMediaScanner.scanMtpFile(path, mVolumeName, handle, format); + mMediaScanner.scanMtpFile(path, handle, format); } } else { deleteFile(handle); @@ -503,7 +510,7 @@ public class MtpDatabase { } } - return mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, where, + return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where, whereArgs, null, null); } @@ -721,7 +728,7 @@ public class MtpDatabase { propertyGroup = mPropertyGroupsByFormat.get(format); if (propertyGroup == null) { int[] propertyList = getSupportedObjectProperties(format); - propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName, + propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mVolumeName, propertyList); mPropertyGroupsByFormat.put(new Integer(format), propertyGroup); } @@ -729,7 +736,7 @@ public class MtpDatabase { propertyGroup = mPropertyGroupsByProperty.get(property); if (propertyGroup == null) { int[] propertyList = new int[] { (int)property }; - propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName, + propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mVolumeName, propertyList); mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup); } @@ -745,7 +752,7 @@ public class MtpDatabase { String path = null; String[] whereArgs = new String[] { Integer.toString(handle) }; try { - c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_PROJECTION, ID_WHERE, + c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE, whereArgs, null, null); if (c != null && c.moveToNext()) { path = c.getString(1); @@ -788,7 +795,7 @@ public class MtpDatabase { try { // note - we are relying on a special case in MediaProvider.update() to update // the paths for all children in the case where this is a directory. - updated = mMediaProvider.update(mPackageName, mObjectsUri, values, ID_WHERE, whereArgs); + updated = mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs); } catch (RemoteException e) { Log.e(TAG, "RemoteException in mMediaProvider.update", e); } @@ -805,7 +812,7 @@ public class MtpDatabase { if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) { // directory was unhidden try { - mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, newPath, null); + mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null); } catch (RemoteException e) { Log.e(TAG, "failed to unhide/rescan for " + newPath); } @@ -815,7 +822,7 @@ public class MtpDatabase { if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia") && !newPath.toLowerCase(Locale.US).equals(".nomedia")) { try { - mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, oldFile.getParent(), null); + mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null); } catch (RemoteException e) { Log.e(TAG, "failed to unhide/rescan for " + newPath); } @@ -886,7 +893,7 @@ public class MtpDatabase { char[] outName, long[] outCreatedModified) { Cursor c = null; try { - c = mMediaProvider.query(mPackageName, mObjectsUri, OBJECT_INFO_PROJECTION, + c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION, ID_WHERE, new String[] { Integer.toString(handle) }, null, null); if (c != null && c.moveToNext()) { outStorageFormatParent[0] = c.getInt(1); @@ -933,7 +940,7 @@ public class MtpDatabase { } Cursor c = null; try { - c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION, + c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION, ID_WHERE, new String[] { Integer.toString(handle) }, null, null); if (c != null && c.moveToNext()) { String path = c.getString(1); @@ -960,7 +967,7 @@ public class MtpDatabase { private int getObjectFormat(int handle) { Cursor c = null; try { - c = mMediaProvider.query(mPackageName, mObjectsUri, FORMAT_PROJECTION, + c = mMediaProvider.query(mObjectsUri, FORMAT_PROJECTION, ID_WHERE, new String[] { Integer.toString(handle) }, null, null); if (c != null && c.moveToNext()) { return c.getInt(1); @@ -984,7 +991,7 @@ public class MtpDatabase { Cursor c = null; try { - c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION, + c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION, ID_WHERE, new String[] { Integer.toString(handle) }, null, null); if (c != null && c.moveToNext()) { // don't convert to media path here, since we will be matching @@ -1007,7 +1014,7 @@ public class MtpDatabase { if (format == MtpConstants.FORMAT_ASSOCIATION) { // recursive case - delete all children first Uri uri = Files.getMtpObjectsUri(mVolumeName); - int count = mMediaProvider.delete(mPackageName, uri, + int count = mMediaProvider.delete(uri, // the 'like' makes it use the index, the 'lower()' makes it correct // when the path contains sqlite wildcard characters "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)", @@ -1015,12 +1022,12 @@ public class MtpDatabase { } Uri uri = Files.getMtpObjectsUri(mVolumeName, handle); - if (mMediaProvider.delete(mPackageName, uri, null, null) > 0) { + if (mMediaProvider.delete(uri, null, null) > 0) { if (format != MtpConstants.FORMAT_ASSOCIATION && path.toLowerCase(Locale.US).endsWith("/.nomedia")) { try { String parentPath = path.substring(0, path.lastIndexOf("/")); - mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, parentPath, null); + mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null); } catch (RemoteException e) { Log.e(TAG, "failed to unhide/rescan for " + path); } @@ -1043,7 +1050,7 @@ public class MtpDatabase { Uri uri = Files.getMtpReferencesUri(mVolumeName, handle); Cursor c = null; try { - c = mMediaProvider.query(mPackageName, uri, ID_PROJECTION, null, null, null, null); + c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null); if (c == null) { return null; } @@ -1077,7 +1084,7 @@ public class MtpDatabase { valuesList[i] = values; } try { - if (mMediaProvider.bulkInsert(mPackageName, uri, valuesList) > 0) { + if (mMediaProvider.bulkInsert(uri, valuesList) > 0) { return MtpConstants.RESPONSE_OK; } } catch (RemoteException e) { diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java index 95cb5206b9b5..d24c5e825fa7 100644 --- a/media/java/android/mtp/MtpDevice.java +++ b/media/java/android/mtp/MtpDevice.java @@ -19,9 +19,10 @@ package android.mtp; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.os.CancellationSignal; -import android.os.OperationCanceledException; import android.os.ParcelFileDescriptor; +import java.io.IOException; + /** * This class represents an MTP or PTP device connected on the USB host bus. An application can * instantiate an object of this type, by referencing an attached {@link @@ -158,6 +159,22 @@ public final class MtpDevice { } /** + * Obtains object bytes in the specified range and writes it to an array. + * This call may block for an arbitrary amount of time depending on the size + * of the data and speed of the devices. + * + * @param objectHandle handle of the object to read + * @param offset Start index of reading range. + * @param size Size of reading range. + * @param buffer Array to write data. + * @return Size of bytes that are actually read. + */ + public int getPartialObject(int objectHandle, int offset, int size, byte[] buffer) + throws IOException { + return native_get_partial_object(objectHandle, offset, size, buffer); + } + + /** * Returns the thumbnail data for an object as a byte array. * The size and format of the thumbnail data can be determined via * {@link MtpObjectInfo#getThumbCompressedSize} and @@ -323,6 +340,8 @@ public final class MtpDevice { private native int[] native_get_object_handles(int storageId, int format, int objectHandle); private native MtpObjectInfo native_get_object_info(int objectHandle); private native byte[] native_get_object(int objectHandle, int objectSize); + private native int native_get_partial_object( + int objectHandle, int offset, int objectSize, byte[] buffer) throws IOException; private native byte[] native_get_thumbnail(int objectHandle); private native boolean native_delete_object(int objectHandle); private native long native_get_parent(int objectHandle); diff --git a/media/java/android/mtp/MtpDeviceInfo.java b/media/java/android/mtp/MtpDeviceInfo.java index ef9436dfa2ce..1ceca845c30a 100644 --- a/media/java/android/mtp/MtpDeviceInfo.java +++ b/media/java/android/mtp/MtpDeviceInfo.java @@ -16,6 +16,8 @@ package android.mtp; +import android.annotation.Nullable; + /** * This class encapsulates information about an MTP device. * This corresponds to the DeviceInfo Dataset described in @@ -27,6 +29,7 @@ public class MtpDeviceInfo { private String mModel; private String mVersion; private String mSerialNumber; + private int[] mOperationsSupported; // only instantiated via JNI private MtpDeviceInfo() { @@ -67,4 +70,13 @@ public class MtpDeviceInfo { public final String getSerialNumber() { return mSerialNumber; } -}
\ No newline at end of file + + /** + * Returns operation code supported by the device. + * + * @return supported operation code + */ + public final @Nullable int[] getOperationsSupported() { + return mOperationsSupported; + } +} diff --git a/media/java/android/mtp/MtpEvent.java b/media/java/android/mtp/MtpEvent.java index 4c8a74200ee0..6ec16dba42ac 100644 --- a/media/java/android/mtp/MtpEvent.java +++ b/media/java/android/mtp/MtpEvent.java @@ -21,26 +21,7 @@ package android.mtp; * Event constants are defined by the USB-IF MTP specification. */ public class MtpEvent { - public static final int EVENT_UNDEFINED = 0x4000; - public static final int EVENT_CANCEL_TRANSACTION = 0x4001; - public static final int EVENT_OBJECT_ADDED = 0x4002; - public static final int EVENT_OBJECT_REMOVED = 0x4003; - public static final int EVENT_STORE_ADDED = 0x4004; - public static final int EVENT_STORE_REMOVED = 0x4005; - public static final int EVENT_DEVICE_PROP_CHANGED = 0x4006; - public static final int EVENT_OBJECT_INFO_CHANGED = 0x4007; - public static final int EVENT_DEVICE_INFO_CHANGED = 0x4008; - public static final int EVENT_REQUEST_OBJECT_TRANSFER = 0x4009; - public static final int EVENT_STORE_FULL = 0x400A; - public static final int EVENT_DEVICE_RESET = 0x400B; - public static final int EVENT_STORAGE_INFO_CHANGED = 0x400C; - public static final int EVENT_CAPTURE_COMPLETE = 0x400D; - public static final int EVENT_UNREPORTED_STATUS = 0x400E; - public static final int EVENT_OBJECT_PROP_CHANGED = 0xC801; - public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802; - public static final int EVENT_OBJECT_REFERENCES_CHANGED = 0xC803; - - private int mEventCode = EVENT_UNDEFINED; + private int mEventCode = MtpConstants.EVENT_UNDEFINED; /** * Returns event code of MTP event. diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java index c80adfa80fc9..dea300838385 100644 --- a/media/java/android/mtp/MtpPropertyGroup.java +++ b/media/java/android/mtp/MtpPropertyGroup.java @@ -16,7 +16,7 @@ package android.mtp; -import android.content.IContentProvider; +import android.content.ContentProviderClient; import android.database.Cursor; import android.net.Uri; import android.os.RemoteException; @@ -48,8 +48,7 @@ class MtpPropertyGroup { } private final MtpDatabase mDatabase; - private final IContentProvider mProvider; - private final String mPackageName; + private final ContentProviderClient mProvider; private final String mVolumeName; private final Uri mUri; @@ -65,13 +64,12 @@ class MtpPropertyGroup { private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?"; private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + FORMAT_WHERE; // constructs a property group for a list of properties - public MtpPropertyGroup(MtpDatabase database, IContentProvider provider, String packageName, - String volume, int[] properties) { + public MtpPropertyGroup(MtpDatabase database, ContentProviderClient provider, String volumeName, + int[] properties) { mDatabase = database; mProvider = provider; - mPackageName = packageName; - mVolumeName = volume; - mUri = Files.getMtpObjectsUri(volume); + mVolumeName = volumeName; + mUri = Files.getMtpObjectsUri(volumeName); int count = properties.length; ArrayList<String> columns = new ArrayList<String>(count); @@ -201,7 +199,7 @@ class MtpPropertyGroup { Cursor c = null; try { // for now we are only reading properties from the "objects" table - c = mProvider.query(mPackageName, mUri, + c = mProvider.query(mUri, new String [] { Files.FileColumns._ID, column }, ID_WHERE, new String[] { Integer.toString(id) }, null, null); if (c != null && c.moveToNext()) { @@ -221,7 +219,7 @@ class MtpPropertyGroup { private String queryAudio(int id, String column) { Cursor c = null; try { - c = mProvider.query(mPackageName, Audio.Media.getContentUri(mVolumeName), + c = mProvider.query(Audio.Media.getContentUri(mVolumeName), new String [] { Files.FileColumns._ID, column }, ID_WHERE, new String[] { Integer.toString(id) }, null, null); if (c != null && c.moveToNext()) { @@ -242,7 +240,7 @@ class MtpPropertyGroup { Cursor c = null; try { Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id); - c = mProvider.query(mPackageName, uri, + c = mProvider.query(uri, new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME }, null, null, null, null); if (c != null && c.moveToNext()) { @@ -264,7 +262,7 @@ class MtpPropertyGroup { Cursor c = null; try { // for now we are only reading properties from the "objects" table - c = mProvider.query(mPackageName, mUri, + c = mProvider.query(mUri, new String [] { Files.FileColumns._ID, column }, ID_WHERE, new String[] { Integer.toString(id) }, null, null); if (c != null && c.moveToNext()) { @@ -335,7 +333,7 @@ class MtpPropertyGroup { try { // don't query if not necessary if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) { - c = mProvider.query(mPackageName, mUri, mColumns, where, whereArgs, null, null); + c = mProvider.query(mUri, mColumns, where, whereArgs, null, null); if (c == null) { return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE); } diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp index 3f4d18386afa..4aa12c2d6ffc 100644 --- a/media/jni/android_mtp_MtpDevice.cpp +++ b/media/jni/android_mtp_MtpDevice.cpp @@ -27,8 +27,11 @@ #include "jni.h" #include "JNIHelp.h" +#include "ScopedPrimitiveArray.h" + #include "android_runtime/AndroidRuntime.h" #include "android_runtime/Log.h" +#include "nativehelper/ScopedLocalRef.h" #include "private/android_filesystem_config.h" #include "MtpTypes.h" @@ -41,6 +44,8 @@ using namespace android; // ---------------------------------------------------------------------------- +namespace { + static jfieldID field_context; jclass clazz_deviceInfo; @@ -60,6 +65,7 @@ static jfieldID field_deviceInfo_manufacturer; static jfieldID field_deviceInfo_model; static jfieldID field_deviceInfo_version; static jfieldID field_deviceInfo_serialNumber; +static jfieldID field_deviceInfo_operationsSupported; // MtpStorageInfo fields static jfieldID field_storageInfo_storageId; @@ -93,6 +99,29 @@ static jfieldID field_objectInfo_keywords; // MtpEvent fields static jfieldID field_event_eventCode; +class JavaArrayWriter { +public: + JavaArrayWriter(JNIEnv* env, jbyteArray array) : + mEnv(env), mArray(array), mSize(mEnv->GetArrayLength(mArray)) {} + bool write(void* data, uint32_t offset, uint32_t length) { + if (static_cast<uint32_t>(mSize) < offset + length) { + return false; + } + mEnv->SetByteArrayRegion(mArray, offset, length, static_cast<jbyte*>(data)); + return true; + } + static bool writeTo(void* data, uint32_t offset, uint32_t length, void* clientData) { + return static_cast<JavaArrayWriter*>(clientData)->write(data, offset, length); + } + +private: + JNIEnv* mEnv; + jbyteArray mArray; + jsize mSize; +}; + +} + MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice) { return (MtpDevice*)env->GetLongField(javaDevice, field_context); @@ -208,6 +237,17 @@ android_mtp_MtpDevice_get_device_info(JNIEnv *env, jobject thiz) if (deviceInfo->mSerial) env->SetObjectField(info, field_deviceInfo_serialNumber, env->NewStringUTF(deviceInfo->mSerial)); + if (deviceInfo->mOperations) { + const size_t size = deviceInfo->mOperations->size(); + const jintArray operations = env->NewIntArray(size); + { + ScopedIntArrayRW elements(env, operations); + for (size_t i = 0; i < size; ++i) { + elements[i] = deviceInfo->mOperations->itemAt(i); + } + } + env->SetObjectField(info, field_deviceInfo_operationsSupported, operations); + } delete deviceInfo; return info; @@ -307,38 +347,59 @@ android_mtp_MtpDevice_get_object_info(JNIEnv *env, jobject thiz, jint objectID) return info; } -struct get_object_callback_data { - JNIEnv *env; - jbyteArray array; -}; - -static bool get_object_callback(void* data, int offset, int length, void* clientData) -{ - get_object_callback_data* cbData = (get_object_callback_data *)clientData; - cbData->env->SetByteArrayRegion(cbData->array, offset, length, (jbyte *)data); - return true; -} - static jbyteArray android_mtp_MtpDevice_get_object(JNIEnv *env, jobject thiz, jint objectID, jint objectSize) { MtpDevice* device = get_device_from_object(env, thiz); - if (!device) - return NULL; + if (!device) { + return nullptr; + } - jbyteArray array = env->NewByteArray(objectSize); - if (!array) { + ScopedLocalRef<jbyteArray> array(env, env->NewByteArray(objectSize)); + if (!array.get()) { jniThrowException(env, "java/lang/OutOfMemoryError", NULL); - return NULL; + return nullptr; + } + + JavaArrayWriter writer(env, array.get()); + + if (device->readObject(objectID, JavaArrayWriter::writeTo, objectSize, &writer)) { + return array.release(); + } + return nullptr; +} + +static jint +android_mtp_MtpDevice_get_partial_object(JNIEnv *env, + jobject thiz, + jint objectID, + jint offset, + jint size, + jbyteArray array) +{ + if (!array) { + jniThrowException(env, "java/lang/IllegalArgumentException", "Array must not be null."); + return -1; } - get_object_callback_data data; - data.env = env; - data.array = array; + MtpDevice* const device = get_device_from_object(env, thiz); + if (!device) { + jniThrowException(env, "java/io/IOException", "Failed to obtain MtpDevice."); + return -1; + } - if (device->readObject(objectID, get_object_callback, objectSize, &data)) - return array; - return NULL; + JavaArrayWriter writer(env, array); + uint32_t written_size; + bool success = device->readPartialObject( + objectID, offset, size, &written_size, JavaArrayWriter::writeTo, &writer); + if (!success) { + jniThrowException(env, "java/io/IOException", "Failed to read data."); + return -1; + } + // Note: assumption here is that a negative value will be treated as unsigned on the Java + // level. + // TODO: Make sure that actually holds. + return static_cast<jint>(written_size); } static jbyteArray @@ -547,6 +608,7 @@ static const JNINativeMethod gMethods[] = { {"native_get_object_info", "(I)Landroid/mtp/MtpObjectInfo;", (void *)android_mtp_MtpDevice_get_object_info}, {"native_get_object", "(II)[B",(void *)android_mtp_MtpDevice_get_object}, + {"native_get_partial_object", "(III[B)I", (void *)android_mtp_MtpDevice_get_partial_object}, {"native_get_thumbnail", "(I)[B",(void *)android_mtp_MtpDevice_get_thumbnail}, {"native_delete_object", "(I)Z", (void *)android_mtp_MtpDevice_delete_object}, {"native_get_parent", "(I)J", (void *)android_mtp_MtpDevice_get_parent}, @@ -599,6 +661,11 @@ int register_android_mtp_MtpDevice(JNIEnv *env) ALOGE("Can't find MtpDeviceInfo.mSerialNumber"); return -1; } + field_deviceInfo_operationsSupported = env->GetFieldID(clazz, "mOperationsSupported", "[I"); + if (field_deviceInfo_operationsSupported == NULL) { + ALOGE("Can't find MtpDeviceInfo.mOperationsSupported"); + return -1; + } clazz_deviceInfo = (jclass)env->NewGlobalRef(clazz); clazz = env->FindClass("android/mtp/MtpStorageInfo"); diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp index 70d651f2c24a..b63df6fe7ff1 100644 --- a/media/jni/soundpool/SoundPool.cpp +++ b/media/jni/soundpool/SoundPool.cpp @@ -655,7 +655,7 @@ status_t Sample::doLoad() goto error; } - if ((numChannels < 1) || (numChannels > 8)) { + if ((numChannels < 1) || (numChannels > FCC_8)) { ALOGE("Sample channel count (%d) out of range", numChannels); status = BAD_VALUE; goto error; diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java index 05df014ad611..06efa906af04 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java @@ -16,6 +16,7 @@ package com.android.mediaframeworktest.unit; +import android.content.ContentProviderClient; import android.content.ContentValues; import android.content.IContentProvider; import android.media.MediaInserter; @@ -81,8 +82,9 @@ public class MediaInserterTest extends InstrumentationTestCase { protected void setUp() throws Exception { super.setUp(); mMockProvider = EasyMock.createMock(IContentProvider.class); - mMediaInserter = new MediaInserter(mMockProvider, - mPackageName, TEST_BUFFER_SIZE); + final ContentProviderClient client = new ContentProviderClient( + getInstrumentation().getContext().getContentResolver(), mMockProvider, true); + mMediaInserter = new MediaInserter(client, TEST_BUFFER_SIZE); mPackageName = getInstrumentation().getContext().getPackageName(); mFilesCounter = 0; mAudioCounter = 0; diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml index 5e634a4df3d3..6beef4415f99 100644 --- a/packages/DocumentsUI/AndroidManifest.xml +++ b/packages/DocumentsUI/AndroidManifest.xml @@ -92,7 +92,7 @@ </receiver> <service - android:name=".CopyService" + android:name=".services.FileOperationService" android:exported="false"> </service> </application> diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png Binary files differdeleted file mode 100644 index 2b21c12d671d..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_album_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png Binary files differdeleted file mode 100644 index ed3ee454dfa2..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_apk_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png Binary files differdeleted file mode 100644 index 1a3ebc47fb4d..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_audio_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png Binary files differdeleted file mode 100644 index 3086a6923f2d..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_certificate_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png Binary files differdeleted file mode 100644 index b86f0f7322db..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_codes_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png Binary files differdeleted file mode 100644 index 9d0988da305e..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_compressed_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png Binary files differdeleted file mode 100644 index 6c3136030d6f..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_contact_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png Binary files differdeleted file mode 100644 index 1450ff03d7d7..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_event_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png Binary files differdeleted file mode 100644 index 4ad54bb63c97..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_excel_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png Binary files differdeleted file mode 100644 index 7f7c6361c34b..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_folder_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png Binary files differdeleted file mode 100644 index d867847e9174..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_font_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png Binary files differdeleted file mode 100644 index 545976765809..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_generic_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png Binary files differdeleted file mode 100644 index 0cbd992aaad9..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_image_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png Binary files differdeleted file mode 100644 index db4670259ff3..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_pdf_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png Binary files differdeleted file mode 100644 index b9f7af5754d5..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_powerpoint_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png Binary files differdeleted file mode 100644 index 1218c2f7b432..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_presentation_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png Binary files differdeleted file mode 100644 index 46d755f212ef..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_spreadsheet_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png Binary files differdeleted file mode 100644 index 933570bb7469..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_text_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png Binary files differdeleted file mode 100644 index 30cea25f1fc2..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_video_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png Binary files differdeleted file mode 100644 index 67b60ded5656..000000000000 --- a/packages/DocumentsUI/res/drawable-hdpi/ic_doc_word_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png Binary files differdeleted file mode 100644 index ac27eea8de76..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_album_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png Binary files differdeleted file mode 100644 index a4add51490af..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_apk_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png Binary files differdeleted file mode 100644 index a9a7f2014284..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_audio_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png Binary files differdeleted file mode 100644 index 26beb794a792..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_certificate_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png Binary files differdeleted file mode 100644 index ed9cab7294de..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_codes_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png Binary files differdeleted file mode 100644 index 451d2873279e..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_compressed_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png Binary files differdeleted file mode 100644 index 7bc02c948618..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_contact_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png Binary files differdeleted file mode 100644 index de39cd461c02..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_event_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png Binary files differdeleted file mode 100644 index c3eb8456549e..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_excel_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png Binary files differdeleted file mode 100644 index 97f6e5071dee..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_folder_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png Binary files differdeleted file mode 100644 index b2f043f8a81d..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_font_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png Binary files differdeleted file mode 100644 index 483d7fb4d184..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_generic_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png Binary files differdeleted file mode 100644 index 2941b8a70135..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_image_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png Binary files differdeleted file mode 100644 index d3ac07264dc5..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_pdf_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png Binary files differdeleted file mode 100644 index a43f9022a4bc..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_powerpoint_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png Binary files differdeleted file mode 100644 index c572cd1cbbf2..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_presentation_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png Binary files differdeleted file mode 100644 index 7ae671ba1c7a..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_spreadsheet_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png Binary files differdeleted file mode 100644 index a5ebd513292b..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_text_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png Binary files differdeleted file mode 100644 index 89ac4340bcda..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_video_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png Binary files differdeleted file mode 100644 index 855c44b329d8..000000000000 --- a/packages/DocumentsUI/res/drawable-mdpi/ic_doc_word_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png Binary files differdeleted file mode 100644 index 4203d35614c1..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_album_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png Binary files differdeleted file mode 100644 index 41558f251fd6..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_apk_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png Binary files differdeleted file mode 100644 index e190c4d4207e..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_audio_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png Binary files differdeleted file mode 100644 index fabc8c3505e6..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_certificate_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png Binary files differdeleted file mode 100644 index d8ba6e0be330..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_codes_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png Binary files differdeleted file mode 100644 index 1b5111a577a4..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_compressed_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png Binary files differdeleted file mode 100644 index e7b7460dd8c5..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_contact_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png Binary files differdeleted file mode 100644 index 3183bfca62da..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_event_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png Binary files differdeleted file mode 100644 index 9a4e844f5ff2..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_excel_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png Binary files differdeleted file mode 100644 index 96d5721866c7..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_folder_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png Binary files differdeleted file mode 100644 index 23a130236996..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_font_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png Binary files differdeleted file mode 100644 index b0811f18ebbe..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_generic_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png Binary files differdeleted file mode 100644 index 5f1f53761805..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_image_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png Binary files differdeleted file mode 100644 index 8083584eb8d2..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_pdf_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png Binary files differdeleted file mode 100644 index 898e26ae0092..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_powerpoint_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png Binary files differdeleted file mode 100644 index 2e9c66721413..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_presentation_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png Binary files differdeleted file mode 100644 index 56951c3cad10..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_spreadsheet_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png Binary files differdeleted file mode 100644 index 08ed9f0888e9..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_text_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png Binary files differdeleted file mode 100644 index cd64e56b4c42..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_video_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png Binary files differdeleted file mode 100644 index 0bc40deb6a75..000000000000 --- a/packages/DocumentsUI/res/drawable-xhdpi/ic_doc_word_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png Binary files differdeleted file mode 100644 index 60f59f532abd..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_album_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png Binary files differdeleted file mode 100644 index 6006b1207e3c..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_apk_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png Binary files differdeleted file mode 100644 index 7926188aa0fd..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_audio_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png Binary files differdeleted file mode 100644 index e65d74c2a008..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_certificate_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png Binary files differdeleted file mode 100644 index 7d32801f79d4..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_codes_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png Binary files differdeleted file mode 100644 index d528708242f5..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_compressed_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png Binary files differdeleted file mode 100644 index 274c52468599..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_contact_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png Binary files differdeleted file mode 100644 index 6053b0a65213..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_event_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png Binary files differdeleted file mode 100644 index 78ee13b3ca7e..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_excel_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png Binary files differdeleted file mode 100644 index dcf9cc265354..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_folder_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png Binary files differdeleted file mode 100644 index 74fbbbc5de9b..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_font_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png Binary files differdeleted file mode 100644 index 11a219afc3f6..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_generic_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png Binary files differdeleted file mode 100644 index 9a461c96f785..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_image_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png Binary files differdeleted file mode 100644 index 9a67956b6288..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_pdf_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png Binary files differdeleted file mode 100644 index 853aa8c0ccbc..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_powerpoint_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png Binary files differdeleted file mode 100644 index 84ae9aef1760..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_presentation_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png Binary files differdeleted file mode 100644 index 111439e86b03..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_spreadsheet_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png Binary files differdeleted file mode 100644 index b876f86d7f3c..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_text_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png Binary files differdeleted file mode 100644 index 7cf656a5bf0b..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_video_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png Binary files differdeleted file mode 100644 index acc3d7b29af0..000000000000 --- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_doc_word_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png Binary files differdeleted file mode 100644 index d2dd494d2718..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_album_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png Binary files differdeleted file mode 100644 index 4f935bf59b26..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_apk_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png Binary files differdeleted file mode 100644 index 7499cbc6d24e..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_audio_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png Binary files differdeleted file mode 100644 index ca129289f408..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_certificate_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png Binary files differdeleted file mode 100644 index c4afa37bc362..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_codes_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png Binary files differdeleted file mode 100644 index 0b0aa040736c..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_compressed_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png Binary files differdeleted file mode 100644 index ebd0535a884d..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_contact_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png Binary files differdeleted file mode 100644 index 29cdbb7ad7df..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_event_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png Binary files differdeleted file mode 100644 index ca349b659fe5..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_excel_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png Binary files differdeleted file mode 100644 index 02249d2058da..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_folder_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png Binary files differdeleted file mode 100644 index 469b911bc1ee..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_font_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png Binary files differdeleted file mode 100644 index ef479c3c897e..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_generic_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png Binary files differdeleted file mode 100644 index 3168d6f78e95..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_image_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png Binary files differdeleted file mode 100644 index 9bb4d66d9493..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_pdf_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png Binary files differdeleted file mode 100644 index 88ba9ad5daff..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_powerpoint_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png Binary files differdeleted file mode 100644 index 5fe18da00879..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_presentation_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png Binary files differdeleted file mode 100644 index 1d05f6f58ad0..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_spreadsheet_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png Binary files differdeleted file mode 100644 index c2308fe0253f..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_text_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png Binary files differdeleted file mode 100644 index 9a173bef611d..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_video_am_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png Binary files differdeleted file mode 100644 index a564f5a76db0..000000000000 --- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_doc_word_alpha.png +++ /dev/null diff --git a/packages/DocumentsUI/res/drawable/ic_check_circle.xml b/packages/DocumentsUI/res/drawable/ic_check_circle.xml new file mode 100644 index 000000000000..d49ba6ab0526 --- /dev/null +++ b/packages/DocumentsUI/res/drawable/ic_check_circle.xml @@ -0,0 +1,24 @@ +<!-- +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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF009688" + android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10,-4.48 10,-10S17.52 2 12 2zm-2 15l-5,-5 1.41,-1.41L10 14.17l7.59,-7.59L19 8l-9 9z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_album.xml b/packages/DocumentsUI/res/drawable/ic_doc_album.xml index e7965e621b05..1ce3f023dfb7 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_album.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_album.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_album_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10,-4.48 10,-10S17.52 2 12 2zm0 14.5c-2.49 0,-4.5,-2.01,-4.5,-4.5S9.51 7.5 12 7.5s4.5 2.01 4.5 4.5,-2.01 4.5,-4.5 4.5zm0,-5.5c-.55 0,-1 .45,-1 1s.45 1 1 1 1,-.45 1,-1,-.45,-1,-1,-1z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_apk.xml b/packages/DocumentsUI/res/drawable/ic_doc_apk.xml index 4f8f06e86bb7..197445ef598d 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_apk.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_apk.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_apk_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M6 18c0 .55.45 1 1 1h1v3.5c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5V19h2v3.5c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5V19h1c.55 0 1,-.45 1,-1V8H6v10zM3.5 8C2.67 8 2 8.67 2 9.5v7c0 .83.67 1.5 1.5 1.5S5 17.33 5 16.5v-7C5 8.67 4.33 8 3.5 8zm17 0c-.83 0,-1.5.67,-1.5 1.5v7c0 .83.67 1.5 1.5 1.5s1.5,-.67 1.5,-1.5v-7c0,-.83,-.67,-1.5,-1.5,-1.5zm-4.97,-5.84l1.3,-1.3c.2,-.2.2,-.51 0,-.71,-.2,-.2,-.51,-.2,-.71 0l-1.48 1.48C13.85 1.23 12.95 1 12 1c-.96 0,-1.86.23,-2.66.63L7.85.15c-.2,-.2,-.51,-.2,-.71 0,-.2.2,-.2.51 0 .71l1.31 1.31C6.97 3.26 6 5.01 6 7h12c0,-1.99,-.97,-3.75,-2.47,-4.84zM10 5H9V4h1v1zm5 0h-1V4h1v1z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml index cf18b4f0e2f6..454eea3bbad9 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_audio.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_audio.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_audio_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFDB4437" + android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zM7.2 18c-.66 0,-1.2,-.54,-1.2,-1.2V12c0,-3.31 2.69,-6 6,-6s6 2.69 6 6v4.8c0 .66,-.54 1.2,-1.2 1.2H14v-4h2v-2c0,-2.21,-1.79,-4,-4,-4s-4 1.79,-4 4v2h2v4H7.2z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml b/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml index c28ed4fe44df..b99baf6f4cd3 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_certificate.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_certificate_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M17.81 4.47c-.08 0,-.16,-.02,-.23,-.06C15.66 3.42 14 3 12.01 3c-1.98 0,-3.86.47,-5.57 1.41,-.24.13,-.54.04,-.68,-.2,-.13,-.24,-.04,-.55.2,-.68C7.82 2.52 9.86 2 12.01 2c2.13 0 3.99.47 6.03 1.52.25.13.34.43.21.67,-.09.18,-.26.28,-.44.28zM3.5 9.72c-.1 0,-.2,-.03,-.29,-.09,-.23,-.16,-.28,-.47,-.12,-.7.99,-1.4 2.25,-2.5 3.75,-3.27C9.98 4.04 14 4.03 17.15 5.65c1.5.77 2.76 1.86 3.75 3.25.16.22.11.54,-.12.7,-.23.16,-.54.11,-.7,-.12,-.9,-1.26,-2.04,-2.25,-3.39,-2.94,-2.87,-1.47,-6.54,-1.47,-9.4.01,-1.36.7,-2.5 1.7,-3.4 2.96,-.08.14,-.23.21,-.39.21zm6.25 12.07c-.13 0,-.26,-.05,-.35,-.15,-.87,-.87,-1.34,-1.43,-2.01,-2.64,-.69,-1.23,-1.05,-2.73,-1.05,-4.34 0,-2.97 2.54,-5.39 5.66,-5.39s5.66 2.42 5.66 5.39c0 .28,-.22.5,-.5.5s-.5,-.22,-.5,-.5c0,-2.42,-2.09,-4.39,-4.66,-4.39,-2.57 0,-4.66 1.97,-4.66 4.39 0 1.44.32 2.77.93 3.85.64 1.15 1.08 1.64 1.85 2.42.19.2.19.51 0 .71,-.11.1,-.24.15,-.37.15zm7.17,-1.85c-1.19 0,-2.24,-.3,-3.1,-.89,-1.49,-1.01,-2.38,-2.65,-2.38,-4.39 0,-.28.22,-.5.5,-.5s.5.22.5.5c0 1.41.72 2.74 1.94 3.56.71.48 1.54.71 2.54.71.24 0 .64,-.03 1.04,-.1.27,-.05.53.13.58.41.05.27,-.13.53,-.41.58,-.57.11,-1.07.12,-1.21.12zM14.91 22c-.04 0,-.09,-.01,-.13,-.02,-1.59,-.44,-2.63,-1.03,-3.72,-2.1,-1.4,-1.39,-2.17,-3.24,-2.17,-5.22 0,-1.62 1.38,-2.94 3.08,-2.94 1.7 0 3.08 1.32 3.08 2.94 0 1.07.93 1.94 2.08 1.94s2.08,-.87 2.08,-1.94c0,-3.77,-3.25,-6.83,-7.25,-6.83,-2.84 0,-5.44 1.58,-6.61 4.03,-.39.81,-.59 1.76,-.59 2.8 0 .78.07 2.01.67 3.61.1.26,-.03.55,-.29.64,-.26.1,-.55,-.04,-.64,-.29,-.49,-1.31,-.73,-2.61,-.73,-3.96 0,-1.2.23,-2.29.68,-3.24 1.33,-2.79 4.28,-4.6 7.51,-4.6 4.55 0 8.25 3.51 8.25 7.83 0 1.62,-1.38 2.94,-3.08 2.94s-3.08,-1.32,-3.08,-2.94c0,-1.07,-.93,-1.94,-2.08,-1.94s-2.08.87,-2.08 1.94c0 1.71.66 3.31 1.87 4.51.95.94 1.86 1.46 3.27 1.85.27.07.42.35.35.61,-.05.23,-.26.38,-.47.38z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_codes.xml b/packages/DocumentsUI/res/drawable/ic_doc_codes.xml index 0de721a90002..ea1c464890e7 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_codes.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_codes.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_codes_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M9.4 16.6L4.8 12l4.6,-4.6L8 6l-6 6 6 6 1.4,-1.4zm5.2 0l4.6,-4.6,-4.6,-4.6L16 6l6 6,-6 6,-1.4,-1.4z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml b/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml index a49cfa42438c..e0eb669af33a 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_compressed.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_compressed_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-5 6h-2v2h2v2h-2v-2h-2V9h2V7h-2V5h2v2h2v2zm0 8h-2v-2h-2v-2h2v2h2v2z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml index bf550cbf0780..a77cb6ba1152 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_contact.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_contact.xml @@ -1,5 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_contact_am_alpha" - android:tint="?android:attr/colorControlNormal" - android:autoMirrored="true" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M19 3H5c-1.11 0,-2 .89,-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.11,-.9,-2,-2,-2zm-7 3c1.65 0 3 1.35 3 3 0 1.66,-1.35 3,-3 3s-3,-1.34,-3,-3c0,-1.65 1.35,-3 3,-3zm6 12H6v-1c0,-2 4,-3.1 6,-3.1s6 1.1 6 3.1v1z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_document.xml b/packages/DocumentsUI/res/drawable/ic_doc_document.xml new file mode 100644 index 000000000000..29251ad799f0 --- /dev/null +++ b/packages/DocumentsUI/res/drawable/ic_doc_document.xml @@ -0,0 +1,24 @@ +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF4883F3" + android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-1.99 6H7V7h10.01v2zm0 4H7v-2h10.01v2zm-3 4H7v-2h7.01v2z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_event.xml b/packages/DocumentsUI/res/drawable/ic_doc_event.xml index 25cf0f35c7f9..113f079c8670 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_event.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_event.xml @@ -1,5 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_event_am_alpha" - android:tint="?android:attr/colorControlNormal" - android:autoMirrored="true" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M17 12h-5v5h5v-5zM16 1v2H8V1H6v2H5c-1.11 0,-1.99.9,-1.99 2L3 19c0 1.1.89 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2h-1V1h-2zm3 18H5V8h14v11z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_excel.xml b/packages/DocumentsUI/res/drawable/ic_doc_excel.xml index 33547250e755..3ed27e1f7f62 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_excel.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_excel.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_excel_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF16A765" + android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-2.8 14h-2L12 13.2 9.8 17h-2l3.2,-5,-3.2,-5h2l2.2 3.8L14.2 7h2L13 12l3.2 5z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_folder.xml b/packages/DocumentsUI/res/drawable/ic_doc_folder.xml index 73de60e99ade..dcbce010810e 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_folder.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_folder.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_folder_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M10 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V8c0,-1.1,-.9,-2,-2,-2h-8l-2,-2z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_font.xml b/packages/DocumentsUI/res/drawable/ic_doc_font.xml index c74cb9ca07e6..4c13d71e47d0 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_font.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_font.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_font_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M9.93 13.5h4.14L12 7.98zM20 2H4c-1.1 0,-2 .9,-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V4c0,-1.1,-.9,-2,-2,-2zm-4.05 16.5l-1.14,-3H9.17l-1.12 3H5.96l5.11,-13h1.86l5.11 13h-2.09z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml index a4ee29d6db5b..006dfba4a3bb 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_generic.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_generic.xml @@ -1,5 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_generic_am_alpha" - android:tint="?android:attr/colorControlNormal" - android:autoMirrored="true" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M6 2c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6H6zm7 7V3.5L18.5 9H13z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_image.xml b/packages/DocumentsUI/res/drawable/ic_doc_image.xml index 9d4c3591a2b7..23953f71fd5e 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_image.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_image.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_image_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFDB4437" + android:pathData="M21 19V5c0,-1.1,-.9,-2,-2,-2H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5,-4.5z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml b/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml index 5c3749892833..b2d01938c480 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_pdf.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_pdf_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFDB4437" + android:pathData="M7 11.5h1v-1H7v1zM19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-9.5 8.5c0 .83,-.67 1.5,-1.5 1.5H7v2H5.5V9H8c.83 0 1.5.67 1.5 1.5v1zm10,-1H17v1h1.5V13H17v2h-1.5V9h4v1.5zm-5 3c0 .83,-.67 1.5,-1.5 1.5h-2.5V9H13c.83 0 1.5.67 1.5 1.5v3zm-2.5 0h1v-3h-1v3z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml b/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml index f0a6c3935eec..aa5bfc818692 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_powerpoint.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_powerpoint_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFFF7537" + android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zM9.8 13.4V17H8V7h4.3c1.53 0 2.15.3 2.8.89.65.59.9 1.37.9 2.34 0 1.02,-.26 1.8,-.9 2.35s-1.3.82,-2.8.82H9.8zm0,-1.4V8.4h2.3c.66 0 1.17.25 1.5.6.33.35.5.72.5 1.25 0 .55,-.18.95,-.5 1.25,-.32.31,-.7.5,-1.38.5H9.8z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml b/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml index a14f86601753..7937bc12aa3b 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_presentation.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_presentation_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFF4B400" + android:pathData="M19 3H5c-1.1 0,-1.99.9,-1.99 2v14c0 1.1.89 2 1.99 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm0 13H5V8h14v8z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml index 40f25152af6b..1663c0a1ae1b 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_spreadsheet.xml @@ -1,5 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_spreadsheet_am_alpha" - android:tint="?android:attr/colorControlNormal" - android:autoMirrored="true" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF16A765" + android:pathData="M19 3H5c-1.1 0,-1.99.9,-1.99 2L3 8v11c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm0 8h-8v8H9v-8H5V9h4V5h2v4h8v2z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_text.xml b/packages/DocumentsUI/res/drawable/ic_doc_text.xml index ffa9e70b16e9..7fc04e811b1c 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_text.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_text.xml @@ -1,5 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_text_am_alpha" - android:tint="?android:attr/colorControlNormal" - android:autoMirrored="true" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF737373" + android:pathData="M14 2H6c-1.1 0,-1.99.9,-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2,-.9 2,-2V8l-6,-6zm2 16H8v-2h8v2zm0,-4H8v-2h8v2zm-3,-5V3.5L18.5 9H13z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_video.xml b/packages/DocumentsUI/res/drawable/ic_doc_video.xml index 2d048c2ffb93..ad4dae89ccdc 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_video.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_video.xml @@ -1,5 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_video_am_alpha" - android:tint="?android:attr/colorControlNormal" - android:autoMirrored="true" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FFDB4437" + android:pathData="M18 4l2 4h-3l-2,-4h-2l2 4h-3l-2,-4H8l2 4H7L5 4H4c-1.1 0,-1.99.9,-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2,-.9 2,-2V4h-4z"/> +</vector> diff --git a/packages/DocumentsUI/res/drawable/ic_doc_word.xml b/packages/DocumentsUI/res/drawable/ic_doc_word.xml index afcc533ecf55..7a3a0ec9b5e0 100644 --- a/packages/DocumentsUI/res/drawable/ic_doc_word.xml +++ b/packages/DocumentsUI/res/drawable/ic_doc_word.xml @@ -1,4 +1,24 @@ -<?xml version="1.0" encoding="utf-8"?> -<bitmap xmlns:android="http://schemas.android.com/apk/res/android" - android:src="@drawable/ic_doc_word_alpha" - android:tint="?android:attr/colorControlNormal" /> +<!-- +Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24.0" + android:viewportHeight="24.0"> + <path + android:fillColor="#FF4883F3" + android:pathData="M19 3H5c-1.1 0,-2 .9,-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2,-.9 2,-2V5c0,-1.1,-.9,-2,-2,-2zm-3.5 14H14l-2,-7.5,-2 7.5H8.5L6.1 7h1.7l1.54 7.51L11.3 7h1.4l1.97 7.51L16.2 7h1.7l-2.4 10z"/> +</vector> diff --git a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml index fe06eafea713..ecc26e196e2a 100644 --- a/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml +++ b/packages/DocumentsUI/res/layout-sw720dp-land/item_doc_list.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project +<!-- + Copyright (C) 2013 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,8 +19,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/item_doc_background" - android:orientation="horizontal" - android:focusable="true"> + android:focusable="true" + android:orientation="horizontal" > <View android:id="@+id/focus_indicator" @@ -29,71 +30,76 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="@dimen/list_item_height" - android:paddingStart="@dimen/list_item_padding" - android:paddingEnd="@dimen/list_item_padding" + android:baselineAligned="false" android:gravity="center_vertical" + android:minHeight="@dimen/list_item_height" android:orientation="horizontal" - android:baselineAligned="false"> + android:paddingEnd="@dimen/list_item_padding" + android:paddingStart="@dimen/list_item_padding" > <FrameLayout android:id="@android:id/icon" - android:layout_width="@dimen/icon_size" - android:layout_height="@dimen/icon_size" - android:layout_marginStart="0dp" - android:layout_marginEnd="16dp"> + android:layout_width="@dimen/list_item_thumbnail_size" + android:layout_height="@dimen/list_item_thumbnail_size" + android:layout_marginEnd="16dp" + android:layout_marginStart="0dp" > <ImageView android:id="@+id/icon_mime" android:layout_width="wrap_content" - android:layout_height="match_parent" - android:scaleType="centerInside" - android:contentDescription="@null" /> + android:layout_height="wrap_content" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="centerInside" /> <ImageView android:id="@+id/icon_thumb" android:layout_width="match_parent" android:layout_height="match_parent" - android:scaleType="centerCrop" - android:contentDescription="@null" /> + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="centerCrop" /> + + <ImageView + android:id="@+id/icon_check" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:alpha="0" + android:contentDescription="@null" + android:scaleType="fitCenter" + android:src="@drawable/ic_check_circle" /> </FrameLayout> <!-- This is the one special case where we want baseline alignment! --> + <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:orientation="horizontal"> + android:orientation="horizontal" > <TextView android:id="@android:id/title" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_weight="0.5" android:layout_marginEnd="12dp" - android:singleLine="true" + android:layout_weight="0.5" android:ellipsize="middle" + android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@android:style/TextAppearance.Material.Subhead" android:textColor="?android:attr/textColorPrimary" /> - <ImageView - android:id="@android:id/icon1" - android:layout_width="@dimen/root_icon_size" - android:layout_height="@dimen/root_icon_size" - android:layout_marginEnd="8dp" - android:scaleType="centerInside" - android:contentDescription="@null" /> - <TextView android:id="@android:id/summary" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_weight="0.25" android:layout_marginEnd="12dp" - android:singleLine="true" + android:layout_weight="0.25" android:ellipsize="end" + android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@android:style/TextAppearance.Material.Body1" android:textColor="?android:attr/textColorSecondary" /> @@ -102,11 +108,11 @@ android:id="@+id/size" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_weight="0.125" android:layout_marginEnd="12dp" + android:layout_weight="0.125" + android:ellipsize="end" android:minWidth="70dp" android:singleLine="true" - android:ellipsize="end" android:textAlignment="viewEnd" android:textAppearance="@android:style/TextAppearance.Material.Body1" android:textColor="?android:attr/textColorSecondary" /> @@ -115,17 +121,15 @@ android:id="@+id/date" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_weight="0.125" android:layout_marginEnd="12dp" + android:layout_weight="0.125" + android:ellipsize="end" android:minWidth="70dp" android:singleLine="true" - android:ellipsize="end" android:textAlignment="viewEnd" android:textAppearance="@android:style/TextAppearance.Material.Body1" android:textColor="?android:attr/textColorSecondary" /> - </LinearLayout> - </LinearLayout> </com.android.documentsui.ListItem> diff --git a/packages/DocumentsUI/res/layout/item_dir_grid.xml b/packages/DocumentsUI/res/layout/item_dir_grid.xml index c17b4c88d8a1..a08e02987292 100644 --- a/packages/DocumentsUI/res/layout/item_dir_grid.xml +++ b/packages/DocumentsUI/res/layout/item_dir_grid.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project +<!-- + Copyright (C) 2013 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. @@ -20,31 +21,49 @@ android:layout_margin="@dimen/grid_item_margin" android:background="@color/item_doc_background" android:elevation="5dp" - android:focusable="true"> + android:focusable="true" > <LinearLayout - android:layout_width="match_parent" - android:layout_height="match_parent" - android:orientation="horizontal" - android:paddingTop="16dp" - android:paddingBottom="16dp" - android:paddingLeft="12dp" - android:paddingRight="12dp"> - - <ImageView - android:src="@drawable/ic_doc_folder" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:orientation="horizontal" + android:paddingBottom="16dp" + android:paddingLeft="12dp" + android:paddingRight="12dp" + android:paddingTop="16dp" + android:gravity="center_vertical"> + + <FrameLayout android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_marginEnd="8dp" - android:scaleType="centerInside" - android:contentDescription="@null"/> + android:layout_height="wrap_content" + android:layout_marginEnd="8dp" > + + <ImageView + android:id="@+id/icon_mime_sm" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="centerInside" + android:src="@drawable/ic_doc_folder" /> + + <ImageView + android:id="@+id/icon_check" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:alpha="0" + android:contentDescription="@null" + android:scaleType="fitCenter" + android:src="@drawable/ic_check_circle" /> + + </FrameLayout> <TextView android:id="@android:id/title" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:singleLine="true" android:ellipsize="middle" + android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@android:style/TextAppearance.Material.Subhead" android:textColor="@*android:color/primary_text_default_material_light" /> @@ -52,11 +71,12 @@ </LinearLayout> <!-- An overlay that draws the item border when it is focused. --> + <View android:layout_width="match_parent" android:layout_height="match_parent" - android:contentDescription="@null" android:background="@drawable/item_doc_grid_border" + android:contentDescription="@null" android:duplicateParentState="true" /> </FrameLayout> diff --git a/packages/DocumentsUI/res/layout/item_doc_grid.xml b/packages/DocumentsUI/res/layout/item_doc_grid.xml index c0fc2c37ef3f..dd02d1ca0051 100644 --- a/packages/DocumentsUI/res/layout/item_doc_grid.xml +++ b/packages/DocumentsUI/res/layout/item_doc_grid.xml @@ -39,10 +39,11 @@ android:contentDescription="@null" /> <com.android.documentsui.GridItemThumbnail - android:id="@+id/icon_mime" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:scaleType="centerInside" + android:id="@+id/icon_mime_lg" + android:layout_width="@dimen/icon_size" + android:layout_height="@dimen/icon_size" + android:layout_gravity="center" + android:scaleType="fitCenter" android:contentDescription="@null" /> </FrameLayout> @@ -61,13 +62,25 @@ android:paddingRight="12dp"> <ImageView - android:id="@android:id/icon1" - android:layout_width="wrap_content" - android:layout_height="match_parent" + android:id="@+id/icon_mime_sm" + android:layout_width="@dimen/grid_item_icon_size" + android:layout_height="@dimen/grid_item_icon_size" + android:layout_marginEnd="8dp" + android:layout_alignParentStart="true" + android:layout_centerVertical="true" + android:scaleType="center" + android:contentDescription="@null"/> + + <ImageView + android:id="@+id/icon_check" + android:src="@drawable/ic_check_circle" + android:alpha="0" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" android:layout_marginEnd="8dp" android:layout_alignParentStart="true" android:layout_centerVertical="true" - android:scaleType="centerInside" + android:scaleType="fitCenter" android:contentDescription="@null"/> <TextView @@ -75,7 +88,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" - android:layout_toEndOf="@android:id/icon1" + android:layout_toEndOf="@id/icon_mime_sm" android:singleLine="true" android:ellipsize="middle" android:textAlignment="viewStart" @@ -86,7 +99,7 @@ android:id="@+id/size" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_toEndOf="@android:id/icon1" + android:layout_toEndOf="@id/icon_mime_sm" android:layout_below="@android:id/title" android:layout_marginEnd="4dp" android:singleLine="true" diff --git a/packages/DocumentsUI/res/layout/item_doc_list.xml b/packages/DocumentsUI/res/layout/item_doc_list.xml index e0684236846b..8d9837719fd7 100644 --- a/packages/DocumentsUI/res/layout/item_doc_list.xml +++ b/packages/DocumentsUI/res/layout/item_doc_list.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2013 The Android Open Source Project +<!-- + Copyright (C) 2013 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -18,8 +19,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/item_doc_background" - android:orientation="horizontal" - android:focusable="true"> + android:focusable="true" + android:orientation="horizontal" > <View android:id="@+id/focus_indicator" @@ -29,82 +30,76 @@ <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" - android:minHeight="@dimen/list_item_height" - android:paddingStart="@dimen/list_item_padding" - android:paddingEnd="@dimen/list_item_padding" + android:baselineAligned="false" android:gravity="center_vertical" + android:minHeight="@dimen/list_item_height" android:orientation="horizontal" - android:baselineAligned="false"> + android:paddingEnd="@dimen/list_item_padding" + android:paddingStart="@dimen/list_item_padding" > <FrameLayout android:id="@android:id/icon" - android:layout_width="@dimen/icon_size" - android:layout_height="@dimen/icon_size" - android:layout_marginEnd="16dp"> + android:layout_width="@dimen/list_item_thumbnail_size" + android:layout_height="@dimen/list_item_thumbnail_size" + android:layout_marginEnd="16dp" > <ImageView android:id="@+id/icon_mime" android:layout_width="wrap_content" - android:layout_height="match_parent" - android:scaleType="centerInside" - android:contentDescription="@null" /> + android:layout_height="wrap_content" + android:layout_gravity="center" + android:contentDescription="@null" + android:scaleType="centerInside" /> <ImageView android:id="@+id/icon_thumb" android:layout_width="match_parent" android:layout_height="match_parent" - android:scaleType="centerCrop" - android:contentDescription="@null" /> + android:contentDescription="@null" + android:scaleType="centerCrop" /> + <ImageView + android:id="@+id/icon_check" + android:layout_width="@dimen/check_icon_size" + android:layout_height="@dimen/check_icon_size" + android:layout_gravity="center" + android:alpha="0" + android:contentDescription="@null" + android:scaleType="fitCenter" + android:src="@drawable/ic_check_circle" /> </FrameLayout> <LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" - android:orientation="vertical"> + android:orientation="vertical" > - <LinearLayout - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:baselineAligned="false"> - - <TextView - android:id="@android:id/title" - android:layout_width="0dp" - android:layout_height="wrap_content" - android:layout_weight="1" - android:singleLine="true" - android:ellipsize="middle" - android:textAlignment="viewStart" - android:textAppearance="@android:style/TextAppearance.Material.Subhead" - android:textColor="?android:attr/textColorPrimary" /> - - <ImageView - android:id="@android:id/icon1" - android:layout_width="@dimen/root_icon_size" - android:layout_height="@dimen/root_icon_size" - android:layout_marginStart="8dp" - android:scaleType="centerInside" - android:contentDescription="@null" /> - - </LinearLayout> + <TextView + android:id="@android:id/title" + android:layout_width="wrap_content" + android:layout_height="0dp" + android:layout_weight="1" + android:ellipsize="middle" + android:singleLine="true" + android:textAlignment="viewStart" + android:textAppearance="@android:style/TextAppearance.Material.Subhead" + android:textColor="?android:attr/textColorPrimary" /> <LinearLayout android:id="@+id/line2" android:layout_width="match_parent" android:layout_height="wrap_content" + android:baselineAligned="false" android:gravity="center_vertical" - android:orientation="horizontal" - android:baselineAligned="false"> + android:orientation="horizontal" > <TextView android:id="@+id/date" android:layout_width="90dp" android:layout_height="wrap_content" - android:singleLine="true" android:ellipsize="end" + android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@android:style/TextAppearance.Material.Body1" android:textColor="?android:attr/textColorSecondary" /> @@ -114,8 +109,8 @@ android:layout_width="90dp" android:layout_height="wrap_content" android:layout_marginStart="8dp" - android:singleLine="true" android:ellipsize="end" + android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@android:style/TextAppearance.Material.Body1" android:textColor="?android:attr/textColorSecondary" /> @@ -124,18 +119,15 @@ android:id="@android:id/summary" android:layout_width="0dp" android:layout_height="wrap_content" - android:layout_weight="1" android:layout_marginStart="8dp" - android:singleLine="true" + android:layout_weight="1" android:ellipsize="end" + android:singleLine="true" android:textAlignment="viewStart" android:textAppearance="@android:style/TextAppearance.Material.Body1" android:textColor="?android:attr/textColorSecondary" /> - </LinearLayout> - </LinearLayout> - </LinearLayout> </com.android.documentsui.ListItem> diff --git a/packages/DocumentsUI/res/values/dimens.xml b/packages/DocumentsUI/res/values/dimens.xml index 060871d526d0..cacdf4d2f99d 100644 --- a/packages/DocumentsUI/res/values/dimens.xml +++ b/packages/DocumentsUI/res/values/dimens.xml @@ -18,6 +18,10 @@ <dimen name="icon_size">40dp</dimen> <dimen name="root_icon_size">24dp</dimen> <dimen name="root_icon_margin">0dp</dimen> + <dimen name="check_icon_size">30dp</dimen> + + <dimen name="list_item_thumbnail_size">40dp</dimen> + <dimen name="grid_item_icon_size">30dp</dimen> <dimen name="grid_width">152dp</dimen> <dimen name="grid_height">176dp</dimen> diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java index 9c0a04ca751c..7f710fc58181 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java @@ -39,7 +39,6 @@ import android.provider.DocumentsContract.Root; import android.support.annotation.LayoutRes; import android.support.annotation.Nullable; import android.util.Log; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; @@ -60,6 +59,7 @@ import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; +import com.android.internal.util.Preconditions; import libcore.io.IoUtils; @@ -111,6 +111,13 @@ public abstract class BaseActivity extends Activity { setContentView(mLayoutId); mRoots = DocumentsApplication.getRootsCache(this); + mRoots.setOnCacheUpdateListener( + new RootsCache.OnCacheUpdateListener() { + @Override + public void onCacheUpdate() { + new HandleRootsChangedTask().execute(getCurrentRoot()); + } + }); mDirectoryContainer = (DirectoryContainerView) findViewById(R.id.container_directory); mSearchManager = new SearchManager(); @@ -191,10 +198,7 @@ public abstract class BaseActivity extends Activity { void onRootPicked(RootInfo root) { // Clear entire backstack and start in new root - mState.stack.root = root; - mState.stack.clear(); - mState.stackTouched = true; - + mState.onRootChanged(root); mSearchManager.update(root); // Recents is always in memory, so we just load it directly. @@ -203,7 +207,7 @@ public abstract class BaseActivity extends Activity { if (mRoots.isRecentsRoot(root)) { onCurrentDirectoryChanged(ANIM_SIDE); } else { - new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory()); + new PickRootTask(root, true).executeOnExecutor(getExecutorForCurrentDirectory()); } } @@ -305,8 +309,7 @@ public abstract class BaseActivity extends Activity { void openContainerDocument(DocumentInfo doc) { checkArgument(doc.isContainer()); - mState.stack.push(doc); - mState.stackTouched = true; + mState.pushDocument(doc); onCurrentDirectoryChanged(ANIM_DOWN); } @@ -450,7 +453,7 @@ public abstract class BaseActivity extends Activity { return; } - if (!mState.stackTouched) { + if (!mState.hasLocationChanged()) { super.onBackPressed(); return; } @@ -471,9 +474,7 @@ public abstract class BaseActivity extends Activity { try { // Update the restored stack to ensure we have freshest data stack.updateDocuments(getContentResolver()); - - mState.stack = stack; - mState.stackTouched = true; + mState.setStack(stack); onCurrentDirectoryChanged(ANIM_SIDE); } catch (FileNotFoundException e) { @@ -481,31 +482,35 @@ public abstract class BaseActivity extends Activity { } } + private DocumentInfo getRootDocumentBlocking(RootInfo root) { + try { + final Uri uri = DocumentsContract.buildDocumentUri( + root.authority, root.documentId); + return DocumentInfo.fromUri(getContentResolver(), uri); + } catch (FileNotFoundException e) { + Log.w(mTag, "Failed to find root", e); + return null; + } + } + final class PickRootTask extends AsyncTask<Void, Void, DocumentInfo> { private RootInfo mRoot; + private boolean mTouched; - public PickRootTask(RootInfo root) { + public PickRootTask(RootInfo root, boolean touched) { mRoot = root; + mTouched = touched; } @Override protected DocumentInfo doInBackground(Void... params) { - try { - final Uri uri = DocumentsContract.buildDocumentUri( - mRoot.authority, mRoot.documentId); - return DocumentInfo.fromUri(getContentResolver(), uri); - } catch (FileNotFoundException e) { - Log.w(mTag, "Failed to find root", e); - return null; - } + return getRootDocumentBlocking(mRoot); } @Override protected void onPostExecute(DocumentInfo result) { if (result != null) { - mState.stack.push(result); - mState.stackTouched = true; - onCurrentDirectoryChanged(ANIM_SIDE); + openContainerDocument(result); } } } @@ -591,6 +596,40 @@ public abstract class BaseActivity extends Activity { } } + final class HandleRootsChangedTask extends AsyncTask<RootInfo, Void, RootInfo> { + DocumentInfo mHome; + + @Override + protected RootInfo doInBackground(RootInfo... roots) { + checkArgument(roots.length == 1); + final RootInfo currentRoot = roots[0]; + final Collection<RootInfo> cachedRoots = mRoots.getRootsBlocking(); + RootInfo homeRoot = null; + for (final RootInfo root : cachedRoots) { + if (root.isHome()) { + homeRoot = root; + } + if (root.getUri().equals(currentRoot.getUri())) { + // We don't need to change the current root as the current root was not removed. + return null; + } + } + Preconditions.checkNotNull(homeRoot); + mHome = getRootDocumentBlocking(homeRoot); + return homeRoot; + } + + @Override + protected void onPostExecute(RootInfo homeRoot) { + if (homeRoot != null && mHome != null) { + // Clear entire backstack and start in new root + mState.onRootChanged(homeRoot); + mSearchManager.update(homeRoot); + openContainerDocument(mHome); + } + } + } + final class ItemSelectedListener implements OnItemSelectedListener { boolean mIgnoreNextNavigation; @@ -603,8 +642,7 @@ public abstract class BaseActivity extends Activity { } while (mState.stack.size() > position + 1) { - mState.stackTouched = true; - mState.stack.pop(); + mState.popDocument(); } onCurrentDirectoryChanged(ANIM_UP); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java deleted file mode 100644 index 6a5911bb1bfd..000000000000 --- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java +++ /dev/null @@ -1,714 +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.documentsui; - -import static com.android.documentsui.Shared.DEBUG; -import static com.android.documentsui.model.DocumentInfo.getCursorLong; -import static com.android.documentsui.model.DocumentInfo.getCursorString; - -import android.app.Activity; -import android.app.IntentService; -import android.app.Notification; -import android.app.NotificationManager; -import android.app.PendingIntent; -import android.content.ContentProviderClient; -import android.content.Context; -import android.content.Intent; -import android.content.res.AssetFileDescriptor; -import android.content.res.Resources; -import android.database.Cursor; -import android.net.Uri; -import android.os.CancellationSignal; -import android.os.ParcelFileDescriptor; -import android.os.Parcelable; -import android.os.PowerManager; -import android.os.RemoteException; -import android.os.SystemClock; -import android.provider.DocumentsContract; -import android.provider.DocumentsContract.Document; -import android.support.annotation.Nullable; -import android.support.annotation.VisibleForTesting; -import android.support.design.widget.Snackbar; -import android.text.format.DateUtils; -import android.util.Log; -import android.webkit.MimeTypeMap; - -import com.android.documentsui.model.DocumentInfo; -import com.android.documentsui.model.DocumentStack; -import com.android.documentsui.model.RootInfo; - -import libcore.io.IoUtils; - -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.NumberFormat; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; - -public class CopyService extends IntentService { - public static final String TAG = "CopyService"; - - private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL"; - public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST"; - public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE"; - public static final String EXTRA_TRANSFER_MODE = "com.android.documentsui.TRANSFER_MODE"; - - public static final int TRANSFER_MODE_COPY = 1; - public static final int TRANSFER_MODE_MOVE = 2; - - // TODO: Move it to a shared file when more operations are implemented. - public static final int FAILURE_COPY = 1; - - // Parameters of the copy job. Requests to an IntentService are serialized so this code only - // needs to deal with one job at a time. - // NOTE: This must be declared by concrete type as the concrete type - // is required by putParcelableArrayListExtra. - private final ArrayList<DocumentInfo> mFailedFiles = new ArrayList<>(); - - private PowerManager mPowerManager; - - private NotificationManager mNotificationManager; - private Notification.Builder mProgressBuilder; - - // Jobs are serialized but a job ID is used, to avoid mixing up cancellation requests. - private String mJobId; - private volatile boolean mIsCancelled; - private long mBatchSize; - private long mBytesCopied; - private long mStartTime; - private long mLastNotificationTime; - // Speed estimation - private long mBytesCopiedSample; - private long mSampleTime; - private long mSpeed; - private long mRemainingTime; - // Provider clients are acquired for the duration of each copy job. Note that there is an - // implicit assumption that all srcs come from the same authority. - private ContentProviderClient mSrcClient; - private ContentProviderClient mDstClient; - - // For testing only. - @Nullable private TestOnlyListener mJobFinishedListener; - - public CopyService() { - super("CopyService"); - } - - /** - * Starts the service for a copy operation. - * - * @param context Context for the intent. - * @param srcDocs A list of src files to copy. - * @param dstStack The copy destination stack. - */ - public static void start(Activity activity, List<DocumentInfo> srcDocs, DocumentStack dstStack, - int mode) { - final Resources res = activity.getResources(); - final Intent copyIntent = new Intent(activity, CopyService.class); - copyIntent.putParcelableArrayListExtra( - EXTRA_SRC_LIST, - // Don't create a copy unless absolutely necessary :) - srcDocs instanceof ArrayList - ? (ArrayList<DocumentInfo>) srcDocs - : new ArrayList<DocumentInfo>(srcDocs)); - copyIntent.putExtra(Shared.EXTRA_STACK, (Parcelable) dstStack); - copyIntent.putExtra(EXTRA_TRANSFER_MODE, mode); - - int toastMessage = (mode == TRANSFER_MODE_COPY) ? R.plurals.copy_begin - : R.plurals.move_begin; - Snackbars.makeSnackbar(activity, - res.getQuantityString(toastMessage, srcDocs.size(), srcDocs.size()), - Snackbar.LENGTH_SHORT).show(); - activity.startService(copyIntent); - } - - @Override - public int onStartCommand(Intent intent, int flags, int startId) { - if (intent.hasExtra(EXTRA_CANCEL)) { - handleCancel(intent); - } - return super.onStartCommand(intent, flags, startId); - } - - @Override - protected void onHandleIntent(Intent intent) { - if (intent.hasExtra(EXTRA_CANCEL)) { - handleCancel(intent); - return; - } - - final PowerManager.WakeLock wakeLock = mPowerManager - .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - final ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST); - final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK); - // Copy by default. - final int transferMode = intent.getIntExtra(EXTRA_TRANSFER_MODE, TRANSFER_MODE_COPY); - - try { - wakeLock.acquire(); - - // Acquire content providers. - mSrcClient = DocumentsApplication.acquireUnstableProviderOrThrow(getContentResolver(), - srcs.get(0).authority); - mDstClient = DocumentsApplication.acquireUnstableProviderOrThrow(getContentResolver(), - stack.peek().authority); - - setupCopyJob(srcs, stack, transferMode); - - final String opDesc = transferMode == TRANSFER_MODE_COPY ? "copy" : "move"; - DocumentInfo srcInfo; - DocumentInfo dstInfo; - for (int i = 0; i < srcs.size() && !mIsCancelled; ++i) { - srcInfo = srcs.get(i); - dstInfo = stack.peek(); - - // Guard unsupported recursive operation. - if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) { - if (DEBUG) Log.d(TAG, - "Skipping recursive " + opDesc + " of directory " + dstInfo.derivedUri); - mFailedFiles.add(srcInfo); - continue; - } - - if (DEBUG) Log.d(TAG, - "Performing " + opDesc + " of " + srcInfo.displayName - + " (" + srcInfo.derivedUri + ")" + " to " + dstInfo.displayName - + " (" + dstInfo.derivedUri + ")"); - - copy(srcInfo, dstInfo, transferMode); - } - } catch (Exception e) { - // Catch-all to prevent any copy errors from wedging the app. - Log.e(TAG, "Exceptions occurred during copying", e); - } finally { - if (DEBUG) Log.d(TAG, "Cleaning up after copy"); - ContentProviderClient.releaseQuietly(mSrcClient); - ContentProviderClient.releaseQuietly(mDstClient); - - wakeLock.release(); - - // Dismiss the ongoing copy notification when the copy is done. - mNotificationManager.cancel(mJobId, 0); - - if (mFailedFiles.size() > 0) { - Log.e(TAG, mFailedFiles.size() + " files failed to copy"); - final Context context = getApplicationContext(); - final Intent navigateIntent = buildNavigateIntent(context, stack); - navigateIntent.putExtra(EXTRA_FAILURE, FAILURE_COPY); - navigateIntent.putExtra(EXTRA_TRANSFER_MODE, transferMode); - navigateIntent.putParcelableArrayListExtra(EXTRA_SRC_LIST, mFailedFiles); - - final int titleResourceId = (transferMode == TRANSFER_MODE_COPY ? - R.plurals.copy_error_notification_title : - R.plurals.move_error_notification_title); - final Notification.Builder errorBuilder = new Notification.Builder(this) - .setContentTitle(context.getResources().getQuantityString(titleResourceId, - mFailedFiles.size(), mFailedFiles.size())) - .setContentText(getString(R.string.notification_touch_for_details)) - .setContentIntent(PendingIntent.getActivity(context, 0, navigateIntent, - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT)) - .setCategory(Notification.CATEGORY_ERROR) - .setSmallIcon(R.drawable.ic_menu_copy) - .setAutoCancel(true); - mNotificationManager.notify(mJobId, 0, errorBuilder.build()); - } - - if (mJobFinishedListener != null) { - mJobFinishedListener.onFinished(mFailedFiles); - } - - if (DEBUG) Log.d(TAG, "Done cleaning up"); - } - } - - @Override - public void onCreate() { - super.onCreate(); - mPowerManager = getSystemService(PowerManager.class); - mNotificationManager = getSystemService(NotificationManager.class); - } - - /** - * Sets up the CopyService to start tracking and sending notifications for the given batch of - * files. - * - * @param srcs A list of src files to copy. - * @param stack The copy destination stack. - * @param transferMode The mode (i.e. copy, or move) - * @throws RemoteException - */ - private void setupCopyJob(ArrayList<DocumentInfo> srcs, DocumentStack stack, int transferMode) - throws RemoteException { - final boolean copying = (transferMode == TRANSFER_MODE_COPY); - // Create an ID for this copy job. Use the timestamp. - mJobId = String.valueOf(SystemClock.elapsedRealtime()); - // Reset the cancellation flag. - mIsCancelled = false; - - final Context context = getApplicationContext(); - final Intent navigateIntent = buildNavigateIntent(context, stack); - - final String contentTitle = getString(copying ? R.string.copy_notification_title - : R.string.move_notification_title); - mProgressBuilder = new Notification.Builder(this) - .setContentTitle(contentTitle) - .setContentIntent(PendingIntent.getActivity(context, 0, navigateIntent, 0)) - .setCategory(Notification.CATEGORY_PROGRESS) - .setSmallIcon(R.drawable.ic_menu_copy) - .setOngoing(true); - - final Intent cancelIntent = new Intent(this, CopyService.class); - cancelIntent.putExtra(EXTRA_CANCEL, mJobId); - mProgressBuilder.addAction(R.drawable.ic_cab_cancel, - getString(android.R.string.cancel), PendingIntent.getService(this, 0, - cancelIntent, - PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT)); - - // Send an initial progress notification. - final String contentText = getString(copying ? R.string.copy_preparing - : R.string.move_preparing); - mProgressBuilder.setProgress(0, 0, true); // Indeterminate progress while setting up. - mProgressBuilder.setContentText(contentText); - mNotificationManager.notify(mJobId, 0, mProgressBuilder.build()); - - // Reset batch parameters. - mFailedFiles.clear(); - mBatchSize = calculateFileSizes(srcs); - mBytesCopied = 0; - mStartTime = SystemClock.elapsedRealtime(); - mLastNotificationTime = 0; - mBytesCopiedSample = 0; - mSampleTime = 0; - mSpeed = 0; - mRemainingTime = 0; - - // TODO: Check preconditions for copy. - // - check that the destination has enough space and is writeable? - // - check MIME types? - } - - /** - * Sets a callback to be run when the next run job is finished. - * This is test ONLY instrumentation. The alternative is for us to add - * broadcast intents SOLELY for the purpose of testing. - * @param listener - */ - @VisibleForTesting - void addFinishedListener(TestOnlyListener listener) { - this.mJobFinishedListener = listener; - - } - - /** - * Only used for testing. Is that obvious enough? - */ - @VisibleForTesting - interface TestOnlyListener { - void onFinished(List<DocumentInfo> failed); - } - - /** - * Calculates the cumulative size of all the documents in the list. Directories are recursed - * into and totaled up. - * - * @param srcs - * @return Size in bytes. - * @throws RemoteException - */ - private long calculateFileSizes(List<DocumentInfo> srcs) throws RemoteException { - long result = 0; - for (DocumentInfo src : srcs) { - if (src.isDirectory()) { - // Directories need to be recursed into. - result += calculateFileSizesHelper(src.derivedUri); - } else { - result += src.size; - } - } - return result; - } - - /** - * Calculates (recursively) the cumulative size of all the files under the given directory. - * - * @throws RemoteException - */ - private long calculateFileSizesHelper(Uri uri) throws RemoteException { - final String authority = uri.getAuthority(); - final Uri queryUri = DocumentsContract.buildChildDocumentsUri(authority, - DocumentsContract.getDocumentId(uri)); - final String queryColumns[] = new String[] { - Document.COLUMN_DOCUMENT_ID, - Document.COLUMN_MIME_TYPE, - Document.COLUMN_SIZE - }; - - long result = 0; - Cursor cursor = null; - try { - cursor = mSrcClient.query(queryUri, queryColumns, null, null, null); - while (cursor.moveToNext()) { - if (Document.MIME_TYPE_DIR.equals( - getCursorString(cursor, Document.COLUMN_MIME_TYPE))) { - // Recurse into directories. - final Uri subdirUri = DocumentsContract.buildDocumentUri(authority, - getCursorString(cursor, Document.COLUMN_DOCUMENT_ID)); - result += calculateFileSizesHelper(subdirUri); - } else { - // This may return -1 if the size isn't defined. Ignore those cases. - long size = getCursorLong(cursor, Document.COLUMN_SIZE); - result += size > 0 ? size : 0; - } - } - } finally { - IoUtils.closeQuietly(cursor); - } - - return result; - } - - /** - * Cancels the current copy job, if its ID matches the given ID. - * - * @param intent The cancellation intent. - */ - private void handleCancel(Intent intent) { - final String cancelledId = intent.getStringExtra(EXTRA_CANCEL); - // Do nothing if the cancelled ID doesn't match the current job ID. This prevents racey - // cancellation requests from affecting unrelated copy jobs. However, if the current job ID - // is null, the service most likely crashed and was revived by the incoming cancel intent. - // In that case, always allow the cancellation to proceed. - if (Objects.equals(mJobId, cancelledId) || mJobId == null) { - // Set the cancel flag. This causes the copy loops to exit. - mIsCancelled = true; - // Dismiss the progress notification here rather than in the copy loop. This preserves - // interactivity for the user in case the copy loop is stalled. - mNotificationManager.cancel(cancelledId, 0); - } - } - - /** - * Logs progress on the current copy operation. Displays/Updates the progress notification. - * - * @param bytesCopied - */ - private void makeProgress(long bytesCopied) { - mBytesCopied += bytesCopied; - double done = (double) mBytesCopied / mBatchSize; - String percent = NumberFormat.getPercentInstance().format(done); - - // Update time estimate - long currentTime = SystemClock.elapsedRealtime(); - long elapsedTime = currentTime - mStartTime; - - // Send out progress notifications once a second. - if (currentTime - mLastNotificationTime > 1000) { - updateRemainingTimeEstimate(elapsedTime); - mProgressBuilder.setProgress(100, (int) (done * 100), false); - mProgressBuilder.setContentInfo(percent); - if (mRemainingTime > 0) { - mProgressBuilder.setContentText(getString(R.string.copy_remaining, - DateUtils.formatDuration(mRemainingTime))); - } else { - mProgressBuilder.setContentText(null); - } - mNotificationManager.notify(mJobId, 0, mProgressBuilder.build()); - mLastNotificationTime = currentTime; - } - } - - /** - * Generates an estimate of the remaining time in the copy. - * - * @param elapsedTime The time elapsed so far. - */ - private void updateRemainingTimeEstimate(long elapsedTime) { - final long sampleDuration = elapsedTime - mSampleTime; - final long sampleSpeed = ((mBytesCopied - mBytesCopiedSample) * 1000) / sampleDuration; - if (mSpeed == 0) { - mSpeed = sampleSpeed; - } else { - mSpeed = ((3 * mSpeed) + sampleSpeed) / 4; - } - - if (mSampleTime > 0 && mSpeed > 0) { - mRemainingTime = ((mBatchSize - mBytesCopied) * 1000) / mSpeed; - } else { - mRemainingTime = 0; - } - - mSampleTime = elapsedTime; - mBytesCopiedSample = mBytesCopied; - } - - /** - * Copies a the given documents to the given location. - * - * @param srcInfo DocumentInfos for the documents to copy. - * @param dstDirInfo The destination directory. - * @param mode The transfer mode (copy or move). - * @return True on success, false on failure. - * @throws RemoteException - */ - private boolean copy(DocumentInfo srcInfo, DocumentInfo dstDirInfo, int mode) - throws RemoteException { - // When copying within the same provider, try to use optimized copying and moving. - // If not supported, then fallback to byte-by-byte copy/move. - if (srcInfo.authority.equals(dstDirInfo.authority)) { - switch (mode) { - case TRANSFER_MODE_COPY: - if ((srcInfo.flags & Document.FLAG_SUPPORTS_COPY) != 0) { - if (DocumentsContract.copyDocument(mSrcClient, srcInfo.derivedUri, - dstDirInfo.derivedUri) == null) { - mFailedFiles.add(srcInfo); - } - return false; - } - break; - case TRANSFER_MODE_MOVE: - if ((srcInfo.flags & Document.FLAG_SUPPORTS_MOVE) != 0) { - if (DocumentsContract.moveDocument(mSrcClient, srcInfo.derivedUri, - dstDirInfo.derivedUri) == null) { - mFailedFiles.add(srcInfo); - } - return false; - } - break; - default: - throw new IllegalArgumentException("Unknown transfer mode."); - } - } - - final String dstMimeType; - final String dstDisplayName; - - // If the file is virtual, but can be converted to another format, then try to copy it - // as such format. Also, append an extension for the target mime type (if known). - if (srcInfo.isVirtualDocument()) { - if (!srcInfo.isTypedDocument()) { - // Impossible to copy a file which is virtual, but not typed. - mFailedFiles.add(srcInfo); - return false; - } - final String[] streamTypes = getContentResolver().getStreamTypes( - srcInfo.derivedUri, "*/*"); - if (streamTypes != null && streamTypes.length > 0) { - dstMimeType = streamTypes[0]; - final String extension = MimeTypeMap.getSingleton(). - getExtensionFromMimeType(dstMimeType); - dstDisplayName = srcInfo.displayName + - (extension != null ? "." + extension : srcInfo.displayName); - } else { - // The provider says that it supports typed documents, but doesn't say - // anything about available formats. - // TODO: Log failures. b/26192412 - mFailedFiles.add(srcInfo); - return false; - } - } else { - dstMimeType = srcInfo.mimeType; - dstDisplayName = srcInfo.displayName; - } - - // Create the target document (either a file or a directory), then copy recursively the - // contents (bytes or children). - final Uri dstUri = DocumentsContract.createDocument(mDstClient, - dstDirInfo.derivedUri, dstMimeType, dstDisplayName); - if (dstUri == null) { - // If this is a directory, the entire subdir will not be copied over. - mFailedFiles.add(srcInfo); - return false; - } - - DocumentInfo dstInfo = null; - try { - dstInfo = DocumentInfo.fromUri(getContentResolver(), dstUri); - } catch (FileNotFoundException e) { - mFailedFiles.add(srcInfo); - return false; - } - - final boolean success; - if (Document.MIME_TYPE_DIR.equals(srcInfo.mimeType)) { - success = copyDirectoryHelper(srcInfo, dstInfo, mode); - } else { - success = copyFileHelper(srcInfo, dstInfo, dstMimeType, mode); - } - - if (mode == TRANSFER_MODE_MOVE && success) { - // This is racey. We should make sure that we never delete a directory after - // it changed, so we don't remove a file which had not been copied earlier - // to the target location. - try { - DocumentsContract.deleteDocument(mSrcClient, srcInfo.derivedUri); - } catch (RemoteException e) { - Log.w(TAG, "Failed to delete source after moving: " + srcInfo.derivedUri, e); - throw e; - } - } - - return success; - } - - /** - * Returns true if {@code doc} is a descendant of {@code parentDoc}. - * @throws RemoteException - */ - boolean isDescendentOf(DocumentInfo doc, DocumentInfo parentDoc) - throws RemoteException { - if (parentDoc.isDirectory() && doc.authority.equals(parentDoc.authority)) { - return DocumentsContract.isChildDocument( - mDstClient, doc.derivedUri, parentDoc.derivedUri); - } - return false; - } - - /** - * Handles recursion into a directory and copying its contents. Note that in linux terms, this - * does the equivalent of "cp src/* dst", not "cp -r src dst". - * - * @param srcDirInfo Info of the directory to copy from. The routine will copy the directory's - * contents, not the directory itself. - * @param dstDirInfo Info of the directory to copy to. Must be created beforehand. - * @return True on success, false if some of the children failed to copy. - * @throws RemoteException - */ - private boolean copyDirectoryHelper( - DocumentInfo srcDirInfo, DocumentInfo dstDirInfo, int mode) - throws RemoteException { - // Recurse into directories. Copy children into the new subdirectory. - final String queryColumns[] = new String[] { - Document.COLUMN_DISPLAY_NAME, - Document.COLUMN_DOCUMENT_ID, - Document.COLUMN_MIME_TYPE, - Document.COLUMN_SIZE, - Document.COLUMN_FLAGS - }; - Cursor cursor = null; - boolean success = true; - try { - // Iterate over srcs in the directory; copy to the destination directory. - final Uri queryUri = DocumentsContract.buildChildDocumentsUri(srcDirInfo.authority, - srcDirInfo.documentId); - cursor = mSrcClient.query(queryUri, queryColumns, null, null, null); - DocumentInfo srcInfo; - while (cursor.moveToNext()) { - srcInfo = DocumentInfo.fromCursor(cursor, srcDirInfo.authority); - success &= copy(srcInfo, dstDirInfo, mode); - } - } finally { - IoUtils.closeQuietly(cursor); - } - - return success; - } - - /** - * Handles copying a single file. - * - * @param srcUriInfo Info of the file to copy from. - * @param dstUriInfo Info of the *file* to copy to. Must be created beforehand. - * @param mimeType Mime type for the target. Can be different than source for virtual files. - * @return True on success, false on error. - * @throws RemoteException - */ - private boolean copyFileHelper(DocumentInfo srcInfo, DocumentInfo dstInfo, String mimeType, - int mode) throws RemoteException { - // Copy an individual file. - CancellationSignal canceller = new CancellationSignal(); - ParcelFileDescriptor srcFile = null; - ParcelFileDescriptor dstFile = null; - InputStream src = null; - OutputStream dst = null; - - boolean success = true; - try { - // If the file is virtual, but can be converted to another format, then try to copy it - // as such format. - if (srcInfo.isVirtualDocument() && srcInfo.isTypedDocument()) { - final AssetFileDescriptor srcFileAsAsset = - mSrcClient.openTypedAssetFileDescriptor( - srcInfo.derivedUri, mimeType, null, canceller); - srcFile = srcFileAsAsset.getParcelFileDescriptor(); - src = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset); - } else { - srcFile = mSrcClient.openFile(srcInfo.derivedUri, "r", canceller); - src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile); - } - - dstFile = mDstClient.openFile(dstInfo.derivedUri, "w", canceller); - dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile); - - byte[] buffer = new byte[8192]; - int len; - while ((len = src.read(buffer)) != -1) { - if (mIsCancelled) { - success = false; - break; - } - dst.write(buffer, 0, len); - makeProgress(len); - } - - srcFile.checkError(); - } catch (IOException e) { - success = false; - mFailedFiles.add(srcInfo); - - if (dstFile != null) { - try { - dstFile.closeWithError(e.getMessage()); - } catch (IOException closeError) { - Log.e(TAG, "Error closing destination", closeError); - } - } - } finally { - // This also ensures the file descriptors are closed. - IoUtils.closeQuietly(src); - IoUtils.closeQuietly(dst); - } - - if (!success) { - // Clean up half-copied files. - canceller.cancel(); - try { - DocumentsContract.deleteDocument(mDstClient, dstInfo.derivedUri); - } catch (RemoteException e) { - // RemoteExceptions usually signal that the connection is dead, so there's no - // point attempting to continue. Propagate the exception up so the copy job is - // cancelled. - Log.w(TAG, "Failed to cleanup after copy error: " + srcInfo.derivedUri, e); - throw e; - } - } - - return success; - } - - /** - * Creates an intent for navigating back to the destination directory. - */ - private Intent buildNavigateIntent(Context context, DocumentStack stack) { - Intent intent = new Intent(context, FilesActivity.class); - intent.setAction(DocumentsContract.ACTION_BROWSE); - intent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack); - return intent; - } -} diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 8ca2cfb93bac..ca8ef2e65bcb 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -54,6 +54,7 @@ import com.android.documentsui.dirlist.DirectoryFragment; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; +import com.android.documentsui.services.FileOperationService; import java.util.Arrays; import java.util.List; @@ -154,8 +155,8 @@ public class DocumentsActivity extends BaseActivity { if (state.action == ACTION_PICK_COPY_DESTINATION) { state.directoryCopy = intent.getBooleanExtra( Shared.EXTRA_DIRECTORY_COPY, false); - state.transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, - CopyService.TRANSFER_MODE_COPY); + state.transferMode = intent.getIntExtra(FileOperationService.EXTRA_OPERATION, + FileOperationService.OPERATION_COPY); } return state; @@ -481,7 +482,7 @@ public class DocumentsActivity extends BaseActivity { // Picking a copy destination is only used internally by us, so we // don't need to extend permissions to the caller. intent.putExtra(Shared.EXTRA_STACK, (Parcelable) mState.stack); - intent.putExtra(CopyService.EXTRA_TRANSFER_MODE, mState.transferMode); + intent.putExtra(FileOperationService.EXTRA_OPERATION, mState.transferMode); } else { intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION diff --git a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java b/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java index 23074f072c99..7f6f1c6bef14 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FailureDialogFragment.java @@ -16,6 +16,8 @@ package com.android.documentsui; +import static com.android.internal.util.Preconditions.checkArgument; + import android.app.AlertDialog; import android.app.Dialog; import android.app.DialogFragment; @@ -27,6 +29,8 @@ import android.text.Html; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; +import com.android.documentsui.services.FileOperationService; +import com.android.documentsui.services.FileOperations; import java.util.ArrayList; @@ -37,20 +41,20 @@ public class FailureDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { private static final String TAG = "FailureDialogFragment"; - private int mTransferMode; + private int mOperationType; private ArrayList<DocumentInfo> mFailedSrcList; public static void show(FragmentManager fm, int failure, - ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack, int transferMode) { + ArrayList<DocumentInfo> failedSrcList, DocumentStack dstStack, int operationType) { // TODO: Add support for other failures than copy. - if (failure != CopyService.FAILURE_COPY) { + if (failure != FileOperationService.FAILURE_COPY) { return; } final Bundle args = new Bundle(); - args.putInt(CopyService.EXTRA_FAILURE, failure); - args.putInt(CopyService.EXTRA_TRANSFER_MODE, transferMode); - args.putParcelableArrayList(CopyService.EXTRA_SRC_LIST, failedSrcList); + args.putInt(FileOperationService.EXTRA_FAILURE, failure); + args.putInt(FileOperationService.EXTRA_OPERATION, operationType); + args.putParcelableArrayList(FileOperationService.EXTRA_SRC_LIST, failedSrcList); final FragmentTransaction ft = fm.beginTransaction(); final FailureDialogFragment fragment = new FailureDialogFragment(); @@ -63,10 +67,12 @@ public class FailureDialogFragment extends DialogFragment @Override public void onClick(DialogInterface dialog, int whichButton) { if (whichButton == DialogInterface.BUTTON_POSITIVE) { - CopyService.start(getActivity(), mFailedSrcList, + FileOperations.start( + getActivity(), + mFailedSrcList, (DocumentStack) getActivity().getIntent().getParcelableExtra( Shared.EXTRA_STACK), - mTransferMode); + mOperationType); } } @@ -74,16 +80,27 @@ public class FailureDialogFragment extends DialogFragment public Dialog onCreateDialog(Bundle inState) { super.onCreate(inState); - mTransferMode = getArguments().getInt(CopyService.EXTRA_TRANSFER_MODE); - mFailedSrcList = getArguments().getParcelableArrayList(CopyService.EXTRA_SRC_LIST); + mOperationType = getArguments().getInt(FileOperationService.EXTRA_OPERATION); + mFailedSrcList = getArguments().getParcelableArrayList(FileOperationService.EXTRA_SRC_LIST); final StringBuilder list = new StringBuilder("<p>"); for (DocumentInfo documentInfo : mFailedSrcList) { list.append(String.format("• %s<br>", documentInfo.displayName)); } list.append("</p>"); - final String messageFormat = getString(mTransferMode == CopyService.TRANSFER_MODE_COPY ? - R.string.copy_failure_alert_content : R.string.move_failure_alert_content); + + // TODO: Add support for other file operations. + checkArgument( + mOperationType == FileOperationService.OPERATION_COPY + || mOperationType == FileOperationService.OPERATION_MOVE); + + int messageId = mOperationType == FileOperationService.OPERATION_COPY + ? R.string.copy_failure_alert_content + : R.string.move_failure_alert_content; + + final String messageFormat = getString( + messageId); + final String message = String.format(messageFormat, list.toString()); return new AlertDialog.Builder(getActivity()) diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java index e308f3f35651..0bd09f68ee19 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java @@ -49,6 +49,7 @@ import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; import com.android.documentsui.model.RootInfo; +import com.android.documentsui.services.FileOperationService; import java.util.ArrayList; import java.util.Arrays; @@ -120,20 +121,22 @@ public class FilesActivity extends BaseActivity { ProviderExecutor.forAuthority(homeUri.getAuthority())); } - final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0); - final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, - CopyService.TRANSFER_MODE_COPY); + final int failure = intent.getIntExtra(FileOperationService.EXTRA_FAILURE, 0); + final int opType = intent.getIntExtra( + FileOperationService.EXTRA_OPERATION, + FileOperationService.OPERATION_COPY); + // DialogFragment takes care of restoring the dialog on configuration change. // Only show it manually for the first time (icicle is null). if (icicle == null && failure != 0) { final ArrayList<DocumentInfo> failedSrcList = - intent.getParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST); + intent.getParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST); FailureDialogFragment.show( getFragmentManager(), failure, failedSrcList, mState.stack, - transferMode); + opType); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java index a1213d210b50..c28fae85cb8b 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java +++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java @@ -159,8 +159,8 @@ public class IconUtils { add("application/vnd.sun.xml.calc.template", icon); add("application/x-kspread", icon); - // Text - icon = R.drawable.ic_doc_text; + // Document + icon = R.drawable.ic_doc_document; add("application/vnd.oasis.opendocument.text", icon); add("application/vnd.oasis.opendocument.text-master", icon); add("application/vnd.oasis.opendocument.text-template", icon); diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java index bb6c3b5ecc33..7dac0c10e077 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java @@ -107,7 +107,7 @@ public class RecentsCreateFragment extends Fragment { mAdapter.update(data); // When launched into empty recents, show drawer - if (mAdapter.isEmpty() && !state.stackTouched && + if (mAdapter.isEmpty() && !state.hasLocationChanged() && context instanceof DocumentsActivity) { ((DocumentsActivity) context).setRootsDrawerOpen(true); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java index 72ee6cbab5fd..21e756623bdd 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java +++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java @@ -63,6 +63,7 @@ public class RootsCache { private final Context mContext; private final ContentObserver mObserver; + private OnCacheUpdateListener mCacheUpdateListener; private final RootInfo mRecentsRoot = new RootInfo(); @@ -94,6 +95,10 @@ public class RootsCache { } } + static interface OnCacheUpdateListener { + void onCacheUpdate(); + } + /** * Gather roots from all known storage providers. */ @@ -209,6 +214,13 @@ public class RootsCache { return null; } + @Override + protected void onPostExecute(Void result) { + if (mCacheUpdateListener != null) { + mCacheUpdateListener.onCacheUpdate(); + } + } + private void handleDocumentsProvider(ProviderInfo info) { // Ignore stopped packages for now; we might query them // later during UI interaction. @@ -348,6 +360,10 @@ public class RootsCache { } } + public void setOnCacheUpdateListener(OnCacheUpdateListener cacheUpdateListener) { + mCacheUpdateListener = cacheUpdateListener; + } + @VisibleForTesting static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) { final List<RootInfo> matching = new ArrayList<>(); diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java index c3366c36a886..22cb25a26a5c 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java +++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java @@ -20,6 +20,9 @@ import android.content.Context; import android.text.format.DateUtils; import android.text.format.Time; +import java.util.ArrayList; +import java.util.List; + /** @hide */ public final class Shared { /** Intent action name to pick a copy destination. */ @@ -64,4 +67,13 @@ public final class Shared { return DateUtils.formatDateTime(context, when, flags); } + /** + * A convenient way to transform any list into a (parcelable) ArrayList. + * Uses cast if possible, else creates a new list with entries from {@code list}. + */ + public static <T> ArrayList<T> asArrayList(List<T> list) { + return list instanceof ArrayList + ? (ArrayList<T>) list + : new ArrayList<T>(list); + } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java index 46372c00f872..2f0224ff4565 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/State.java +++ b/packages/DocumentsUI/src/com/android/documentsui/State.java @@ -24,6 +24,7 @@ import android.util.SparseArray; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.DurableUtils; +import com.android.documentsui.model.RootInfo; import java.util.ArrayList; import java.util.HashMap; @@ -49,7 +50,6 @@ public class State implements android.os.Parcelable { public boolean localOnly; public boolean forceAdvanced; public boolean showAdvanced; - public boolean stackTouched; public boolean restored; public boolean directoryCopy; public boolean openableOnly; @@ -87,6 +87,8 @@ public class State implements android.os.Parcelable { public static final int SORT_ORDER_LAST_MODIFIED = 2; public static final int SORT_ORDER_SIZE = 3; + private boolean mStackTouched; + public void initAcceptMimes(Intent intent) { if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) { acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES); @@ -96,6 +98,31 @@ public class State implements android.os.Parcelable { } } + public void onRootChanged(RootInfo root) { + stack.root = root; + stack.clear(); + mStackTouched = true; + } + + public void pushDocument(DocumentInfo info) { + stack.push(info); + mStackTouched = true; + } + + public void popDocument() { + stack.pop(); + mStackTouched = true; + } + + public void setStack(DocumentStack stack) { + this.stack = stack; + mStackTouched = true; + } + + public boolean hasLocationChanged() { + return mStackTouched; + } + @Override public int describeContents() { return 0; @@ -113,7 +140,6 @@ public class State implements android.os.Parcelable { out.writeInt(localOnly ? 1 : 0); out.writeInt(forceAdvanced ? 1 : 0); out.writeInt(showAdvanced ? 1 : 0); - out.writeInt(stackTouched ? 1 : 0); out.writeInt(restored ? 1 : 0); DurableUtils.writeToParcel(out, stack); out.writeString(currentSearch); @@ -121,6 +147,7 @@ public class State implements android.os.Parcelable { out.writeList(selectedDocumentsForCopy); out.writeList(excludedAuthorities); out.writeInt(openableOnly ? 1 : 0); + out.writeInt(mStackTouched ? 1 : 0); } public static final Creator<State> CREATOR = new Creator<State>() { @@ -137,7 +164,6 @@ public class State implements android.os.Parcelable { state.localOnly = in.readInt() != 0; state.forceAdvanced = in.readInt() != 0; state.showAdvanced = in.readInt() != 0; - state.stackTouched = in.readInt() != 0; state.restored = in.readInt() != 0; DurableUtils.readFromParcel(in, state.stack); state.currentSearch = in.readString(); @@ -145,6 +171,7 @@ public class State implements android.os.Parcelable { in.readList(state.selectedDocumentsForCopy, null); in.readList(state.excludedAuthorities, null); state.openableOnly = in.readInt() != 0; + state.mStackTouched = in.readInt() != 0; return state; } diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java index 9617582a1f3b..84ab85e35dc0 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java @@ -78,7 +78,6 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.documentsui.BaseActivity; -import com.android.documentsui.CopyService; import com.android.documentsui.DirectoryLoader; import com.android.documentsui.DirectoryResult; import com.android.documentsui.DocumentClipper; @@ -100,6 +99,8 @@ import com.android.documentsui.dirlist.MultiSelectManager.Selection; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.RootInfo; +import com.android.documentsui.services.FileOperationService; +import com.android.documentsui.services.FileOperations; import com.google.common.collect.Lists; @@ -411,7 +412,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi updateDisplayState(); // When launched into empty recents, show drawer - if (mType == TYPE_RECENT_OPEN && mModel.isEmpty() && !state.stackTouched && + if (mType == TYPE_RECENT_OPEN && mModel.isEmpty() && !state.hasLocationChanged() && context instanceof DocumentsActivity) { ((DocumentsActivity) context).setRootsDrawerOpen(true); } @@ -455,9 +456,15 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi return; } - CopyService.start(getActivity(), getDisplayState().selectedDocumentsForCopy, + int operationType = data.getIntExtra( + FileOperationService.EXTRA_OPERATION, + FileOperationService.OPERATION_COPY); + + FileOperations.start( + getActivity(), + getDisplayState().selectedDocumentsForCopy, (DocumentStack) data.getParcelableExtra(Shared.EXTRA_STACK), - data.getIntExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_COPY)); + operationType); } private boolean onSingleTapUp(MotionEvent e) { @@ -739,14 +746,14 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi return true; case R.id.menu_copy_to: - transferDocuments(selection, CopyService.TRANSFER_MODE_COPY); + transferDocuments(selection, FileOperationService.OPERATION_COPY); mode.finish(); return true; case R.id.menu_move_to: // Exit selection mode first, so we avoid deselecting deleted documents. mode.finish(); - transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE); + transferDocuments(selection, FileOperationService.OPERATION_MOVE); return true; case R.id.menu_copy_to_clipboard: @@ -898,7 +905,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi } } intent.putExtra(Shared.EXTRA_DIRECTORY_COPY, directoryCopy); - intent.putExtra(CopyService.EXTRA_TRANSFER_MODE, mode); + intent.putExtra(FileOperationService.EXTRA_OPERATION, mode); startActivityForResult(intent, REQUEST_COPY_DESTINATION); } }.execute(selected); @@ -1035,7 +1042,7 @@ public class DirectoryFragment extends Fragment implements DocumentsAdapter.Envi tmpStack = curStack; } - CopyService.start(getActivity(), docs, tmpStack, CopyService.TRANSFER_MODE_COPY); + FileOperations.copy(getActivity(), docs, tmpStack); } private ClipData getClipDataFromDocuments(List<DocumentInfo> docs) { diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java index ab67a5b6cec9..d1f8ff787833 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/EmptyDocumentHolder.java @@ -18,22 +18,33 @@ package com.android.documentsui.dirlist; import android.content.Context; import android.database.Cursor; +import android.view.View; import android.widget.Space; import com.android.documentsui.R; import com.android.documentsui.State; final class EmptyDocumentHolder extends DocumentHolder { + final int mVisibleHeight; + public EmptyDocumentHolder(Context context) { super(context, new Space(context)); // Per UX spec, this puts a bigger gap between the folders and documents in the grid. - final int gridMargin = context.getResources().getDimensionPixelSize(R.dimen.grid_item_margin); - itemView.setMinimumHeight(gridMargin * 2); + mVisibleHeight = context.getResources().getDimensionPixelSize(R.dimen.grid_item_margin) * 2; + } + + public void bind(State state) { + bind(null, null, state); } + @Override public void bind(Cursor cursor, String modelId, State state) { - // Nothing to bind. + if (state.derivedMode == State.MODE_GRID) { + itemView.setMinimumHeight(mVisibleHeight); + } else { + itemView.setMinimumHeight(0); + } return; } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java index 11ff263cabd8..e672327dfdae 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java @@ -23,6 +23,7 @@ import android.content.Context; import android.database.Cursor; import android.provider.DocumentsContract.Document; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; import com.android.documentsui.R; @@ -30,10 +31,24 @@ import com.android.documentsui.State; final class GridDirectoryHolder extends DocumentHolder { final TextView mTitle; + private ImageView mIconCheck; + private ImageView mIconMime; + public GridDirectoryHolder(Context context, ViewGroup parent) { super(context, parent, R.layout.item_dir_grid); mTitle = (TextView) itemView.findViewById(android.R.id.title); + mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime_sm); + mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check); + } + + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + float checkAlpha = selected ? 1f : 0f; + + mIconCheck.animate().alpha(checkAlpha).start(); + mIconMime.animate().alpha(1f - checkAlpha).start(); } /** diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java index 63c667be0be3..c4ac0f515e0f 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java @@ -32,6 +32,7 @@ import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; +import com.android.documentsui.IconUtils; import com.android.documentsui.R; import com.android.documentsui.RootCursorWrapper; import com.android.documentsui.Shared; @@ -43,8 +44,10 @@ final class GridDocumentHolder extends DocumentHolder { final TextView mTitle; final TextView mDate; final TextView mSize; - final ImageView mIconMime; + final ImageView mIconMimeLg; + final ImageView mIconMimeSm; final ImageView mIconThumb; + final ImageView mIconCheck; final IconHelper mIconHelper; public GridDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) { @@ -53,11 +56,23 @@ final class GridDocumentHolder extends DocumentHolder { mTitle = (TextView) itemView.findViewById(android.R.id.title); mDate = (TextView) itemView.findViewById(R.id.date); mSize = (TextView) itemView.findViewById(R.id.size); - mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime); + mIconMimeLg = (ImageView) itemView.findViewById(R.id.icon_mime_lg); + mIconMimeSm = (ImageView) itemView.findViewById(R.id.icon_mime_sm); mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb); + mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check); + mIconHelper = iconHelper; } + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + float checkAlpha = selected ? 1f : 0f; + + mIconCheck.animate().alpha(checkAlpha).start(); + mIconMimeSm.animate().alpha(1f - checkAlpha).start(); + } + /** * Bind this view to the given document for display. * @param cursor Pointing to the item to be bound. @@ -80,13 +95,15 @@ final class GridDocumentHolder extends DocumentHolder { mIconHelper.stopLoading(mIconThumb); - mIconMime.animate().cancel(); - mIconMime.setAlpha(1f); + mIconMimeLg.animate().cancel(); + mIconMimeLg.setAlpha(1f); mIconThumb.animate().cancel(); mIconThumb.setAlpha(0f); + mIconMimeSm.setImageDrawable(IconUtils.loadMimeIcon(mContext, docMimeType)); + final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId); - mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime); + mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMimeLg); if (mHideTitles) { mTitle.setVisibility(View.GONE); diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java index ff70eafc2a4d..0314077aae0b 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/IconHelper.java @@ -91,7 +91,8 @@ public class IconHelper { thumbSize = mContext.getResources().getDimensionPixelSize(R.dimen.grid_width); break; case MODE_LIST: - thumbSize = mContext.getResources().getDimensionPixelSize(R.dimen.icon_size); + thumbSize = mContext.getResources().getDimensionPixelSize( + R.dimen.list_item_thumbnail_size); break; case MODE_UNKNOWN: default: diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java index c22e91d58c32..00ea27b8b304 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java @@ -44,7 +44,7 @@ final class ListDocumentHolder extends DocumentHolder { final TextView mSize; final ImageView mIconMime; final ImageView mIconThumb; - final ImageView mIcon1; + final ImageView mIconCheck; final IconHelper mIconHelper; public ListDocumentHolder(Context context, ViewGroup parent, IconHelper iconHelper) { @@ -56,11 +56,21 @@ final class ListDocumentHolder extends DocumentHolder { mSize = (TextView) itemView.findViewById(R.id.size); mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime); mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb); - mIcon1 = (ImageView) itemView.findViewById(android.R.id.icon1); + mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check); mIconHelper = iconHelper; } + @Override + public void setSelected(boolean selected) { + super.setSelected(selected); + float checkAlpha = selected ? 1f : 0f; + + mIconCheck.animate().alpha(checkAlpha).start(); + mIconMime.animate().alpha(1f - checkAlpha).start(); + mIconThumb.animate().alpha(1f - checkAlpha).start(); + } + /** * Bind this view to the given document for display. * @param cursor Pointing to the item to be bound. @@ -86,7 +96,9 @@ final class ListDocumentHolder extends DocumentHolder { mIconHelper.stopLoading(mIconThumb); mIconMime.animate().cancel(); + mIconMime.setAlpha(1f); mIconThumb.animate().cancel(); + mIconThumb.setAlpha(0f); final Uri uri = DocumentsContract.buildDocumentUri(docAuthority, docId); mIconHelper.loadThumbnail(uri, docMimeType, docFlags, docIcon, mIconThumb, mIconMime); @@ -121,6 +133,5 @@ final class ListDocumentHolder extends DocumentHolder { final float iconAlpha = enabled ? 1f : 0.5f; mIconMime.setAlpha(iconAlpha); mIconThumb.setAlpha(iconAlpha); - mIcon1.setAlpha(iconAlpha); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java index 5994df952de9..d868fb46de98 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java @@ -945,16 +945,27 @@ public final class MultiSelectManager implements View.OnKeyListener { if (vh != null) { vh.itemView.requestFocus(); } else { - // Don't smooth scroll; that taxes the system unnecessarily and makes the scroll - // handling logic below more complicated. See b/24865658. - mView.scrollToPosition(pos); + mView.smoothScrollToPosition(pos); // Set a one-time listener to request focus when the scroll has completed. mView.addOnScrollListener( new RecyclerView.OnScrollListener() { @Override - public void onScrolled(RecyclerView view, int dx, int dy) { - view.findViewHolderForAdapterPosition(pos).itemView.requestFocus(); - view.removeOnScrollListener(this); + public void onScrollStateChanged (RecyclerView view, int newState) { + if (newState == RecyclerView.SCROLL_STATE_IDLE) { + // When scrolling stops, find the item and focus it. + RecyclerView.ViewHolder vh = + view.findViewHolderForAdapterPosition(pos); + if (vh != null) { + vh.itemView.requestFocus(); + } else { + // This might happen in weird corner cases, e.g. if the user is + // scrolling while a delete operation is in progress. In that + // case, just don't attempt to focus the missing item. + Log.w( + TAG, "Unable to focus position " + pos + " after a scroll"); + } + view.removeOnScrollListener(this); + } } }); } @@ -1913,37 +1924,41 @@ public final class MultiSelectManager implements View.OnKeyListener { // Here we unpack information from the event and pass it to an more // easily tested method....basically eliminating the need to synthesize // events and views and so on in our tests. - int position = findTargetPosition(view, keyCode); - if (position == RecyclerView.NO_POSITION) { + int endPos = findTargetPosition(view, keyCode); + if (endPos == RecyclerView.NO_POSITION) { // If there is no valid navigation target, don't handle the keypress. return false; } - return attemptChangeFocus(position, event.isShiftPressed()); + int startPos = mEnvironment.getAdapterPositionForChildView(view); + + return changeFocus(startPos, endPos, event.isShiftPressed()); } /** + * @param startPosition The current focus position. * @param targetPosition The adapter position to focus. * @param extendSelection */ @VisibleForTesting - boolean attemptChangeFocus(int targetPosition, boolean extendSelection) { + boolean changeFocus(int startPosition, int targetPosition, boolean extendSelection) { // Focus the new file. mEnvironment.focusItem(targetPosition); if (extendSelection) { - if (!hasSelection()) { - // If there is no selection, start a selection when the user presses shift-arrow. - toggleSelection(targetPosition); - setSelectionRangeBegin(targetPosition); - } else if (!mSingleSelect) { - mRanger.snapSelection(targetPosition); - notifySelectionChanged(); - } else { + if (mSingleSelect) { // We're in single select and have an existing selection. // Our best guess as to what the user would expect is to advance the selection. clearSelection(); toggleSelection(targetPosition); + } else { + if (!hasSelection()) { + // No selection - start a selection when the user presses shift-arrow. + toggleSelection(startPosition); + setSelectionRangeBegin(startPosition); + } + mRanger.snapSelection(targetPosition); + notifySelectionChanged(); } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java index b4782f035e11..3ee1d4229bbe 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java +++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java @@ -76,6 +76,8 @@ final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter { public void onBindViewHolder(DocumentHolder holder, int p, List<Object> payload) { if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) { mDelegate.onBindViewHolder(holder, toDelegatePosition(p), payload); + } else { + ((EmptyDocumentHolder)holder).bind(mEnv.getDisplayState()); } } @@ -83,6 +85,8 @@ final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter { public void onBindViewHolder(DocumentHolder holder, int p) { if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) { mDelegate.onBindViewHolder(holder, toDelegatePosition(p)); + } else { + ((EmptyDocumentHolder)holder).bind(mEnv.getDisplayState()); } } @@ -106,7 +110,11 @@ final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter { List<String> modelIds = mDelegate.getModelIds(); for (int i = 0; i < modelIds.size(); i++) { if (!isDirectory(model, i)) { - mBreakPosition = i; + // If the break is the first thing in the list, then there are actually no + // directories. In that case, don't insert a break at all. + if (i > 0) { + mBreakPosition = i; + } break; } } diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java index 215c6e696bb7..83df18cdca13 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java +++ b/packages/DocumentsUI/src/com/android/documentsui/model/DocumentInfo.java @@ -255,10 +255,6 @@ public class DocumentInfo implements Durable, Parcelable { return (flags & Document.FLAG_VIRTUAL_DOCUMENT) != 0; } - public boolean isTypedDocument() { - return (flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) != 0; - } - public int hashCode() { return derivedUri.hashCode() + mimeType.hashCode(); } diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java new file mode 100644 index 000000000000..8f89b4e6e55b --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java @@ -0,0 +1,505 @@ +/* + * 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. + */ + +package com.android.documentsui.services; + +import static android.os.SystemClock.elapsedRealtime; +import static com.android.documentsui.DocumentsApplication.acquireUnstableProviderOrThrow; +import static com.android.documentsui.Shared.DEBUG; +import static com.android.documentsui.model.DocumentInfo.getCursorLong; +import static com.android.documentsui.model.DocumentInfo.getCursorString; +import static com.android.documentsui.services.FileOperationService.OPERATION_COPY; +import static com.google.common.base.Preconditions.checkArgument; + +import android.annotation.StringRes; +import android.app.Notification; +import android.app.Notification.Builder; +import android.content.ContentProviderClient; +import android.content.Context; +import android.content.res.AssetFileDescriptor; +import android.database.Cursor; +import android.net.Uri; +import android.os.CancellationSignal; +import android.os.ParcelFileDescriptor; +import android.os.RemoteException; +import android.provider.DocumentsContract; +import android.provider.DocumentsContract.Document; +import android.text.format.DateUtils; +import android.util.Log; +import android.webkit.MimeTypeMap; + +import com.android.documentsui.R; +import com.android.documentsui.model.DocumentInfo; +import com.android.documentsui.model.DocumentStack; + +import libcore.io.IoUtils; + +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.text.NumberFormat; +import java.util.List; + +class CopyJob extends Job { + private static final String TAG = "CopyJob"; + private static final int PROGRESS_INTERVAL_MILLIS = 1000; + final List<DocumentInfo> mSrcFiles; + + // Provider clients are acquired for the duration of each copy job. Note that there is an + // implicit assumption that all srcs come from the same authority. + ContentProviderClient srcClient; + ContentProviderClient dstClient; + + private long mStartTime = -1; + private long mBatchSize; + private long mBytesCopied; + private long mLastNotificationTime; + // Speed estimation + private long mBytesCopiedSample; + private long mSampleTime; + private long mSpeed; + private long mRemainingTime; + + /** + * Copies files to a destination identified by {@code destination}. + * @see @link {@link Job} constructor for most param descriptions. + * + * @param srcs List of files to be copied. + */ + CopyJob(Context serviceContext, Context appContext, Listener listener, + String id, DocumentStack destination, List<DocumentInfo> srcs) { + super(OPERATION_COPY, serviceContext, appContext, listener, id, destination); + + checkArgument(!srcs.isEmpty()); + this.mSrcFiles = srcs; + } + + @Override + Builder createProgressBuilder() { + return super.createProgressBuilder( + serviceContext.getString(R.string.copy_notification_title), + R.drawable.ic_menu_copy, + serviceContext.getString(android.R.string.cancel), + R.drawable.ic_cab_cancel); + } + + @Override + public Notification getSetupNotification() { + return getSetupNotification(serviceContext.getString(R.string.copy_preparing)); + } + + public boolean shouldUpdateProgress() { + // Wait a while between updates :) + return elapsedRealtime() - mLastNotificationTime > PROGRESS_INTERVAL_MILLIS; + } + + Notification getProgressNotification(@StringRes int msgId) { + double completed = (double) this.mBytesCopied / mBatchSize; + mProgressBuilder.setProgress(100, (int) (completed * 100), false); + mProgressBuilder.setContentInfo( + NumberFormat.getPercentInstance().format(completed)); + if (mRemainingTime > 0) { + mProgressBuilder.setContentText(serviceContext.getString(msgId, + DateUtils.formatDuration(mRemainingTime))); + } else { + mProgressBuilder.setContentText(null); + } + + // Remember when we last returned progress so we can provide an answer + // in shouldUpdateProgress. + mLastNotificationTime = elapsedRealtime(); + return mProgressBuilder.build(); + } + + public Notification getProgressNotification() { + return getProgressNotification(R.string.copy_remaining); + } + + void onBytesCopied(long numBytes) { + this.mBytesCopied += numBytes; + } + + /** + * Generates an estimate of the remaining time in the copy. + */ + void updateRemainingTimeEstimate() { + long elapsedTime = elapsedRealtime() - mStartTime; + + final long sampleDuration = elapsedTime - mSampleTime; + final long sampleSpeed = ((mBytesCopied - mBytesCopiedSample) * 1000) / sampleDuration; + if (mSpeed == 0) { + mSpeed = sampleSpeed; + } else { + mSpeed = ((3 * mSpeed) + sampleSpeed) / 4; + } + + if (mSampleTime > 0 && mSpeed > 0) { + mRemainingTime = ((mBatchSize - mBytesCopied) * 1000) / mSpeed; + } else { + mRemainingTime = 0; + } + + mSampleTime = elapsedTime; + mBytesCopiedSample = mBytesCopied; + } + + @Override + Notification getFailureNotification() { + return getFailureNotification( + R.plurals.copy_error_notification_title, R.drawable.ic_menu_copy); + } + + @Override + void run(FileOperationService service) throws RemoteException { + mStartTime = elapsedRealtime(); + + // Acquire content providers. + srcClient = acquireUnstableProviderOrThrow( + getContentResolver(), + mSrcFiles.get(0).authority); + dstClient = acquireUnstableProviderOrThrow( + getContentResolver(), + stack.peek().authority); + + // client + mBatchSize = calculateSize(srcClient, mSrcFiles); + + DocumentInfo srcInfo; + DocumentInfo dstInfo; + for (int i = 0; i < mSrcFiles.size() && !isCanceled(); ++i) { + srcInfo = mSrcFiles.get(i); + dstInfo = stack.peek(); + + // Guard unsupported recursive operation. + if (dstInfo.equals(srcInfo) || isDescendentOf(srcInfo, dstInfo)) { + if (DEBUG) Log.d(TAG, "Skipping recursive operation on directory " + + dstInfo.derivedUri); + onFileFailed(srcInfo); + continue; + } + + if (DEBUG) Log.d(TAG, + "Performing op-type:" + type() + " of " + srcInfo.displayName + + " (" + srcInfo.derivedUri + ")" + " to " + dstInfo.displayName + + " (" + dstInfo.derivedUri + ")"); + + processDocument(srcInfo, dstInfo); + } + } + + /** + * Logs progress on the current copy operation. Displays/Updates the progress notification. + * + * @param bytesCopied + */ + private void makeCopyProgress(long bytesCopied) { + onBytesCopied(bytesCopied); + if (shouldUpdateProgress()) { + updateRemainingTimeEstimate(); + listener.onProgress(this); + } + } + + /** + * Copies a the given document to the given location. + * + * @param srcInfo DocumentInfos for the documents to copy. + * @param dstDirInfo The destination directory. + * @param mode The transfer mode (copy or move). + * @return True on success, false on failure. + * @throws RemoteException + */ + boolean processDocument(DocumentInfo srcInfo, DocumentInfo dstDirInfo) throws RemoteException { + + // TODO: When optimized copy kicks in, we'll not making any progress updates. + // For now. Local storage isn't using optimized copy. + + // When copying within the same provider, try to use optimized copying and moving. + // If not supported, then fallback to byte-by-byte copy/move. + if (srcInfo.authority.equals(dstDirInfo.authority)) { + if ((srcInfo.flags & Document.FLAG_SUPPORTS_COPY) != 0) { + if (DocumentsContract.copyDocument(srcClient, srcInfo.derivedUri, + dstDirInfo.derivedUri) == null) { + onFileFailed(srcInfo); + } + return false; + } + } + + // If we couldn't do an optimized copy...we fall back to vanilla byte copy. + return byteCopyDocument(srcInfo, dstDirInfo); + } + + boolean byteCopyDocument(DocumentInfo srcInfo, DocumentInfo dstDirInfo) + throws RemoteException { + final String dstMimeType; + final String dstDisplayName; + + // If the file is virtual, but can be converted to another format, then try to copy it + // as such format. Also, append an extension for the target mime type (if known). + if (srcInfo.isVirtualDocument()) { + final String[] streamTypes = getContentResolver().getStreamTypes( + srcInfo.derivedUri, "*/*"); + if (streamTypes != null && streamTypes.length > 0) { + dstMimeType = streamTypes[0]; + final String extension = MimeTypeMap.getSingleton(). + getExtensionFromMimeType(dstMimeType); + dstDisplayName = srcInfo.displayName + + (extension != null ? "." + extension : srcInfo.displayName); + } else { + // The virtual file is not available as any alternative streamable format. + // TODO: Log failures. + onFileFailed(srcInfo); + return false; + } + } else { + dstMimeType = srcInfo.mimeType; + dstDisplayName = srcInfo.displayName; + } + + // Create the target document (either a file or a directory), then copy recursively the + // contents (bytes or children). + final Uri dstUri = DocumentsContract.createDocument(dstClient, + dstDirInfo.derivedUri, dstMimeType, dstDisplayName); + if (dstUri == null) { + // If this is a directory, the entire subdir will not be copied over. + onFileFailed(srcInfo); + return false; + } + + DocumentInfo dstInfo = null; + try { + dstInfo = DocumentInfo.fromUri(getContentResolver(), dstUri); + } catch (FileNotFoundException e) { + onFileFailed(srcInfo); + return false; + } + + final boolean success; + if (Document.MIME_TYPE_DIR.equals(srcInfo.mimeType)) { + success = copyDirectoryHelper(srcInfo, dstInfo); + } else { + success = copyFileHelper(srcInfo, dstInfo, dstMimeType); + } + + return success; + } + + /** + * Handles recursion into a directory and copying its contents. Note that in linux terms, this + * does the equivalent of "cp src/* dst", not "cp -r src dst". + * + * @param srcDirInfo Info of the directory to copy from. The routine will copy the directory's + * contents, not the directory itself. + * @param dstDirInfo Info of the directory to copy to. Must be created beforehand. + * @return True on success, false if some of the children failed to copy. + * @throws RemoteException + */ + private boolean copyDirectoryHelper(DocumentInfo srcDirInfo, DocumentInfo dstDirInfo) + throws RemoteException { + // Recurse into directories. Copy children into the new subdirectory. + final String queryColumns[] = new String[] { + Document.COLUMN_DISPLAY_NAME, + Document.COLUMN_DOCUMENT_ID, + Document.COLUMN_MIME_TYPE, + Document.COLUMN_SIZE, + Document.COLUMN_FLAGS + }; + Cursor cursor = null; + boolean success = true; + try { + // Iterate over srcs in the directory; copy to the destination directory. + final Uri queryUri = DocumentsContract.buildChildDocumentsUri(srcDirInfo.authority, + srcDirInfo.documentId); + cursor = srcClient.query(queryUri, queryColumns, null, null, null); + DocumentInfo srcInfo; + while (cursor.moveToNext()) { + srcInfo = DocumentInfo.fromCursor(cursor, srcDirInfo.authority); + success &= processDocument(srcInfo, dstDirInfo); + } + } finally { + IoUtils.closeQuietly(cursor); + } + + return success; + } + + /** + * Handles copying a single file. + * + * @param srcUriInfo Info of the file to copy from. + * @param dstUriInfo Info of the *file* to copy to. Must be created beforehand. + * @param mimeType Mime type for the target. Can be different than source for virtual files. + * @return True on success, false on error. + * @throws RemoteException + */ + private boolean copyFileHelper(DocumentInfo srcInfo, DocumentInfo dstInfo, String mimeType) + throws RemoteException { + // Copy an individual file. + CancellationSignal canceller = new CancellationSignal(); + ParcelFileDescriptor srcFile = null; + ParcelFileDescriptor dstFile = null; + InputStream src = null; + OutputStream dst = null; + + boolean success = true; + try { + // If the file is virtual, but can be converted to another format, then try to copy it + // as such format. + if (srcInfo.isVirtualDocument()) { + final AssetFileDescriptor srcFileAsAsset = + srcClient.openTypedAssetFileDescriptor( + srcInfo.derivedUri, mimeType, null, canceller); + srcFile = srcFileAsAsset.getParcelFileDescriptor(); + src = new AssetFileDescriptor.AutoCloseInputStream(srcFileAsAsset); + } else { + srcFile = srcClient.openFile(srcInfo.derivedUri, "r", canceller); + src = new ParcelFileDescriptor.AutoCloseInputStream(srcFile); + } + + dstFile = dstClient.openFile(dstInfo.derivedUri, "w", canceller); + dst = new ParcelFileDescriptor.AutoCloseOutputStream(dstFile); + + byte[] buffer = new byte[8192]; + int len; + while ((len = src.read(buffer)) != -1) { + if (isCanceled()) { + if (DEBUG) Log.d(TAG, "Canceled copy mid-copy. Id:" + id); + success = false; + break; + } + dst.write(buffer, 0, len); + makeCopyProgress(len); + } + + srcFile.checkError(); + } catch (IOException e) { + success = false; + onFileFailed(srcInfo); + + if (dstFile != null) { + try { + dstFile.closeWithError(e.getMessage()); + } catch (IOException closeError) { + Log.e(TAG, "Error closing destination", closeError); + } + } + } finally { + // This also ensures the file descriptors are closed. + IoUtils.closeQuietly(src); + IoUtils.closeQuietly(dst); + } + + if (!success) { + // Clean up half-copied files. + canceller.cancel(); + try { + DocumentsContract.deleteDocument(dstClient, dstInfo.derivedUri); + } catch (RemoteException e) { + // RemoteExceptions usually signal that the connection is dead, so there's no + // point attempting to continue. Propagate the exception up so the copy job is + // cancelled. + Log.w(TAG, "Failed to cleanup after copy error: " + srcInfo.derivedUri, e); + throw e; + } + } + + return success; + } + + /** + * Calculates the cumulative size of all the documents in the list. Directories are recursed + * into and totaled up. + * + * @param srcs + * @return Size in bytes. + * @throws RemoteException + */ + private static long calculateSize(ContentProviderClient client, List<DocumentInfo> srcs) + throws RemoteException { + long result = 0; + + for (DocumentInfo src : srcs) { + if (src.isDirectory()) { + // Directories need to be recursed into. + result += calculateFileSizesRecursively(client, src.derivedUri); + } else { + result += src.size; + } + } + return result; + } + + /** + * Calculates (recursively) the cumulative size of all the files under the given directory. + * + * @throws RemoteException + */ + private static long calculateFileSizesRecursively( + ContentProviderClient client, Uri uri) throws RemoteException { + final String authority = uri.getAuthority(); + final Uri queryUri = DocumentsContract.buildChildDocumentsUri(authority, + DocumentsContract.getDocumentId(uri)); + final String queryColumns[] = new String[] { + Document.COLUMN_DOCUMENT_ID, + Document.COLUMN_MIME_TYPE, + Document.COLUMN_SIZE + }; + + long result = 0; + Cursor cursor = null; + try { + cursor = client.query(queryUri, queryColumns, null, null, null); + while (cursor.moveToNext()) { + if (Document.MIME_TYPE_DIR.equals( + getCursorString(cursor, Document.COLUMN_MIME_TYPE))) { + // Recurse into directories. + final Uri dirUri = DocumentsContract.buildDocumentUri(authority, + getCursorString(cursor, Document.COLUMN_DOCUMENT_ID)); + result += calculateFileSizesRecursively(client, dirUri); + } else { + // This may return -1 if the size isn't defined. Ignore those cases. + long size = getCursorLong(cursor, Document.COLUMN_SIZE); + result += size > 0 ? size : 0; + } + } + } finally { + IoUtils.closeQuietly(cursor); + } + + return result; + } + + @Override + void cleanup() { + ContentProviderClient.releaseQuietly(srcClient); + ContentProviderClient.releaseQuietly(dstClient); + } + + /** + * Returns true if {@code doc} is a descendant of {@code parentDoc}. + * @throws RemoteException + */ + boolean isDescendentOf(DocumentInfo doc, DocumentInfo parentDoc) + throws RemoteException { + if (parentDoc.isDirectory() && doc.authority.equals(parentDoc.authority)) { + return DocumentsContract.isChildDocument( + dstClient, doc.derivedUri, parentDoc.derivedUri); + } + return false; + } +}
\ No newline at end of file diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java new file mode 100644 index 000000000000..6d87ecf72cef --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java @@ -0,0 +1,245 @@ +/* + * 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.documentsui.services; + +import static android.os.SystemClock.elapsedRealtime; +import static com.android.documentsui.Shared.DEBUG; +import static com.android.internal.util.Preconditions.checkArgument; +import static com.android.internal.util.Preconditions.checkNotNull; +import static com.android.internal.util.Preconditions.checkState; + +import android.annotation.IntDef; +import android.app.IntentService; +import android.app.NotificationManager; +import android.content.Intent; +import android.os.PowerManager; +import android.support.annotation.Nullable; +import android.support.annotation.VisibleForTesting; +import android.util.Log; + +import com.android.documentsui.Shared; +import com.android.documentsui.model.DocumentInfo; +import com.android.documentsui.model.DocumentStack; + +import com.google.common.base.Objects; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.ArrayList; +import java.util.List; + +public class FileOperationService extends IntentService implements Job.Listener { + public static final String TAG = "FileOperationService"; + + public static final String EXTRA_JOB_ID = "com.android.documentsui.JOB_ID"; + public static final String EXTRA_OPERATION = "com.android.documentsui.OPERATION"; + public static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL"; + public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST"; + public static final String EXTRA_FAILURE = "com.android.documentsui.FAILURE"; + + public static final int OPERATION_UNKNOWN = -1; + public static final int OPERATION_COPY = 1; + public static final int OPERATION_MOVE = 2; + public static final int OPERATION_DELETE = 3; + + @IntDef(flag = true, value = { + OPERATION_UNKNOWN, + OPERATION_COPY, + OPERATION_MOVE, + OPERATION_DELETE + }) + @Retention(RetentionPolicy.SOURCE) + public @interface OpType {} + + // TODO: Move it to a shared file when more operations are implemented. + public static final int FAILURE_COPY = 1; + + private PowerManager mPowerManager; + + private NotificationManager mNotificationManager; + + // TODO: Rework service to support multiple concurrent jobs. + private volatile Job mJob; + + // For testing only. + @Nullable private TestOnlyListener mJobFinishedListener; + + public FileOperationService() { + super("FileOperationService"); + } + + @Override + public void onCreate() { + super.onCreate(); + + if (DEBUG) Log.d(TAG, "Created."); + mPowerManager = getSystemService(PowerManager.class); + mNotificationManager = getSystemService(NotificationManager.class); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (DEBUG) Log.d(TAG, "onStartCommand: " + intent); + if (intent.hasExtra(EXTRA_CANCEL)) { + handleCancel(intent); + return START_REDELIVER_INTENT; + } else { + return super.onStartCommand(intent, flags, startId); + } + } + + @Override + protected void onHandleIntent(Intent intent) { + if (DEBUG) Log.d(TAG, "onHandleIntent: " + intent); + + String jobId = intent.getStringExtra(EXTRA_JOB_ID); + @OpType int operationType = intent.getIntExtra(EXTRA_OPERATION, OPERATION_UNKNOWN); + checkArgument(jobId != null); + if (intent.hasExtra(EXTRA_CANCEL)) { + handleCancel(intent); + return; + } + + checkArgument(operationType != OPERATION_UNKNOWN); + + PowerManager.WakeLock wakeLock = mPowerManager.newWakeLock( + PowerManager.PARTIAL_WAKE_LOCK, TAG); + + ArrayList<DocumentInfo> srcs = intent.getParcelableArrayListExtra(EXTRA_SRC_LIST); + DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK); + + Job job = createJob(operationType, jobId, srcs, stack); + + try { + wakeLock.acquire(); + + mNotificationManager.notify(job.id, 0, job.getSetupNotification()); + job.run(this); + + } catch (Exception e) { + // Catch-all to prevent any copy errors from wedging the app. + Log.e(TAG, "Exceptions occurred during copying", e); + } finally { + if (DEBUG) Log.d(TAG, "Cleaning up after copy"); + + job.cleanup(); + wakeLock.release(); + + // Dismiss the ongoing copy notification when the copy is done. + mNotificationManager.cancel(job.id, 0); + + if (job.failed()) { + Log.e(TAG, job.failedFiles.size() + " files failed to copy"); + mNotificationManager.notify(job.id, 0, job.getFailureNotification()); + } + + // TEST ONLY CODE...<raised eyebrows> + if (mJobFinishedListener != null) { + mJobFinishedListener.onFinished(job.failedFiles); + } + + deleteJob(job); + if (DEBUG) Log.d(TAG, "Done cleaning up"); + } + } + + /** + * Cancels the operation corresponding to job id, identified in "EXTRA_JOB_ID". + * + * @param intent The cancellation intent. + */ + private void handleCancel(Intent intent) { + checkArgument(intent.hasExtra(EXTRA_CANCEL)); + String jobId = checkNotNull(intent.getStringExtra(EXTRA_JOB_ID)); + + // Do nothing if the cancelled ID doesn't match the current job ID. This prevents racey + // cancellation requests from affecting unrelated copy jobs. However, if the current job ID + // is null, the service most likely crashed and was revived by the incoming cancel intent. + // In that case, always allow the cancellation to proceed. + if (mJob != null && Objects.equal(jobId, mJob.id)) { + mJob.cancel(); + } + + // Dismiss the progress notification here rather than in the copy loop. This preserves + // interactivity for the user in case the copy loop is stalled. + // Try to cancel it even if we don't have a job id...in case there is some sad + // orphan notification. + mNotificationManager.cancel(jobId, 0); + } + + public static String createJobId() { + return String.valueOf(elapsedRealtime()); + } + + Job createJob( + @OpType int operationType, String id, ArrayList<DocumentInfo> srcs, + DocumentStack stack) { + + checkState(mJob == null); + + switch (operationType) { + case OPERATION_COPY: + mJob = new CopyJob(this, getApplicationContext(), this, id, stack, srcs); + break; + case OPERATION_MOVE: + mJob = new MoveJob(this, getApplicationContext(), this, id, stack, srcs); + break; + case OPERATION_DELETE: + throw new UnsupportedOperationException(); + default: + throw new UnsupportedOperationException(); + } + + return checkNotNull(mJob); + } + + void deleteJob(Job job) { + checkArgument(job == mJob); + mJob = null; + } + + @Override + public void onProgress(CopyJob job) { + if (DEBUG) Log.d(TAG, "On copy progress..."); + mNotificationManager.notify(job.id, 0, job.getProgressNotification()); + } + + @Override + public void onProgress(MoveJob job) { + if (DEBUG) Log.d(TAG, "On move progress..."); + mNotificationManager.notify(job.id, 0, job.getProgressNotification()); + } + + /** + * Sets a callback to be run when the next run job is finished. + * This is test ONLY instrumentation. The alternative is for us to add + * broadcast intents SOLELY for the purpose of testing. + * @param listener + */ + @VisibleForTesting + void addFinishedListener(TestOnlyListener listener) { + this.mJobFinishedListener = listener; + } + + /** + * Only used for testing. Is that obvious enough? + */ + @VisibleForTesting + interface TestOnlyListener { + void onFinished(List<DocumentInfo> failed); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java new file mode 100644 index 000000000000..88bf03b496e7 --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperations.java @@ -0,0 +1,190 @@ +/* + * 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. + */ + +package com.android.documentsui.services; + +import static com.android.documentsui.Shared.DEBUG; +import static com.android.documentsui.Shared.EXTRA_STACK; +import static com.android.documentsui.Shared.asArrayList; +import static com.android.documentsui.Shared.getQuantityString; +import static com.android.documentsui.services.FileOperationService.EXTRA_CANCEL; +import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID; +import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION; +import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST; +import static com.android.documentsui.services.FileOperationService.OPERATION_COPY; +import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE; +import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Resources; +import android.os.Parcelable; +import android.support.design.widget.Snackbar; +import android.util.Log; + +import com.android.documentsui.R; +import com.android.documentsui.Snackbars; +import com.android.documentsui.model.DocumentInfo; +import com.android.documentsui.model.DocumentStack; +import com.android.documentsui.services.FileOperationService.OpType; + +import java.util.List; + +/** + * Helper functions for starting various file operations. + */ +public final class FileOperations { + + private static final String TAG = "FileOperations"; + + private FileOperations() {} + + /** + * Tries to start the activity. Returns the job id. + */ + public static String start( + Activity activity, List<DocumentInfo> srcDocs, DocumentStack stack, + int operationType) { + + if (DEBUG) Log.d(TAG, "Handling generic 'start' call."); + + switch (operationType) { + case OPERATION_COPY: + return FileOperations.copy(activity, srcDocs, stack); + case OPERATION_MOVE: + return FileOperations.move(activity, srcDocs, stack); + case OPERATION_DELETE: + return FileOperations.delete(activity, srcDocs, stack); + default: + throw new UnsupportedOperationException("Unknown operation: " + operationType); + } + } + + /** + * Makes a best effort to cancel operation identified by jobId. + * + * @param context Context for the intent. + * @param jobId The id of the job to cancel. + * Use {@link FileOperationService#createJobId} if you don't have one handy. + * @param srcDocs A list of src files to copy. + * @param dstStack The copy destination stack. + */ + public static void cancel(Activity activity, String jobId) { + if (DEBUG) Log.d(TAG, "Attempting to canceling operation: " + jobId); + + Intent intent = new Intent(activity, FileOperationService.class); + intent.putExtra(EXTRA_CANCEL, true); + intent.putExtra(EXTRA_JOB_ID, jobId); + + activity.startService(intent); + } + + /** + * Starts the service for a copy operation. + * + * @param context Context for the intent. + * @param jobId A unique jobid for this job. + * Use {@link FileOperationService#createJobId} if you don't have one handy. + * @param srcDocs A list of src files to copy. + * @param destination The copy destination stack. + */ + public static String copy( + Activity activity, List<DocumentInfo> srcDocs, DocumentStack destination) { + String jobId = FileOperationService.createJobId(); + if (DEBUG) Log.d(TAG, "Initiating 'copy' operation id: " + jobId); + + Intent intent = createBaseIntent(OPERATION_COPY, activity, jobId, srcDocs, destination); + + createSharedSnackBar(activity, R.plurals.copy_begin, srcDocs.size()) + .show(); + + activity.startService(intent); + + return jobId; + } + + /** + * Starts the service for a move operation. + * + * @param jobId A unique jobid for this job. + * Use {@link FileOperationService#createJobId} if you don't have one handy. + * @param srcDocs A list of src files to copy. + * @param destination The move destination stack. + */ + public static String move( + Activity activity, List<DocumentInfo> srcDocs, DocumentStack destination) { + String jobId = FileOperationService.createJobId(); + if (DEBUG) Log.d(TAG, "Initiating 'move' operation id: " + jobId); + + Intent intent = createBaseIntent(OPERATION_MOVE, activity, jobId, srcDocs, destination); + + createSharedSnackBar(activity, R.plurals.move_begin, srcDocs.size()) + .show(); + + activity.startService(intent); + + return jobId; + } + + /** + * Starts the service for a move operation. + * + * @param jobId A unique jobid for this job. + * Use {@link FileOperationService#createJobId} if you don't have one handy. + * @param srcDocs A list of src files to copy. + * @return Id of the job. + */ + public static String delete( + Activity activity, List<DocumentInfo> srcDocs, DocumentStack location) { + String jobId = FileOperationService.createJobId(); + if (DEBUG) Log.d(TAG, "Initiating 'delete' operation id: " + jobId); + + Intent intent = createBaseIntent(OPERATION_DELETE, activity, jobId, srcDocs, location); + activity.startService(intent); + + return jobId; + } + + /** + * Starts the service for a move operation. + * + * @param jobId A unique jobid for this job. + * Use {@link FileOperationService#createJobId} if you don't have one handy. + * @param srcDocs A list of src files to copy. + * @return Id of the job. + */ + public static Intent createBaseIntent( + @OpType int operationType, Activity activity, String jobId, + List<DocumentInfo> srcDocs, DocumentStack localeStack) { + + Intent intent = new Intent(activity, FileOperationService.class); + intent.putExtra(EXTRA_JOB_ID, jobId); + intent.putParcelableArrayListExtra( + EXTRA_SRC_LIST, asArrayList(srcDocs)); + intent.putExtra(EXTRA_STACK, (Parcelable) localeStack); + intent.putExtra(EXTRA_OPERATION, operationType); + + return intent; + } + + private static Snackbar createSharedSnackBar(Activity activity, int contentId, int fileCount) { + Resources res = activity.getResources(); + return Snackbars.makeSnackbar( + activity, + getQuantityString(activity, contentId, fileCount), + Snackbar.LENGTH_SHORT); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java new file mode 100644 index 000000000000..5c37a87de90a --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java @@ -0,0 +1,193 @@ +/* + * 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. + */ + +package com.android.documentsui.services; + +import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN; +import static com.android.internal.util.Preconditions.checkArgument; + +import android.annotation.DrawableRes; +import android.annotation.PluralsRes; +import android.app.Notification; +import android.app.Notification.Builder; +import android.app.PendingIntent; +import android.content.ContentResolver; +import android.content.Context; +import android.content.Intent; +import android.os.Parcelable; +import android.os.RemoteException; +import android.provider.DocumentsContract; + +import com.android.documentsui.FilesActivity; +import com.android.documentsui.R; +import com.android.documentsui.Shared; +import com.android.documentsui.model.DocumentInfo; +import com.android.documentsui.model.DocumentStack; +import com.android.documentsui.services.FileOperationService.OpType; + +import java.util.ArrayList; + +abstract class Job { + + final Context serviceContext; + final Context appContext; + final Listener listener; + + final @OpType int mOpType; + final String id; + final DocumentStack stack; + + final ArrayList<DocumentInfo> failedFiles = new ArrayList<>(); + final Notification.Builder mProgressBuilder; + + private volatile boolean mCanceled; + + /** + * A simple progressable job, much like an AsyncTask, but with support + * for providing various related notification, progress and navigation information. + * @param opType + * + * @param serviceContext The context of the service in which this job is running. + * This is usually just "this". + * @param appContext The context of the invoking application. This is usually + * just {@code getApplicationContext()}. + * @param listener + * @param id Arbitrary string ID + * @param stack The documents stack context relating to this request. This is the + * destination in the Files app where the user will be take when the + * navigation intent is invoked (presumably from notification). + */ + Job(@OpType int opType, Context serviceContext, Context appContext, Listener listener, + String id, DocumentStack stack) { + + checkArgument(opType != OPERATION_UNKNOWN); + this.serviceContext = serviceContext; + this.appContext = appContext; + this.listener = listener; + mOpType = opType; + + this.id = id; + this.stack = stack; + + mProgressBuilder = createProgressBuilder(); + } + + abstract void run(FileOperationService service) throws RemoteException; + abstract void cleanup(); + + @OpType int type() { + return mOpType; + } + + abstract Notification getSetupNotification(); + // TODO: Progress notification for deletes. + // abstract Notification getProgressNotification(long bytesCopied); + abstract Notification getFailureNotification(); + + final void cancel() { + mCanceled = true; + } + + final boolean isCanceled() { + return mCanceled; + } + + final ContentResolver getContentResolver() { + return serviceContext.getContentResolver(); + } + + void onFileFailed(DocumentInfo file) { + failedFiles.add(file); + } + + final boolean failed() { + return !failedFiles.isEmpty(); + } + + Notification getSetupNotification(String content) { + mProgressBuilder.setProgress(0, 0, true); + mProgressBuilder.setContentText(content); + return mProgressBuilder.build(); + } + + Notification getFailureNotification(@PluralsRes int titleId, @DrawableRes int icon) { + final Intent navigateIntent = buildNavigateIntent(); + navigateIntent.putExtra(FileOperationService.EXTRA_FAILURE, FileOperationService.FAILURE_COPY); + navigateIntent.putExtra(FileOperationService.EXTRA_OPERATION, mOpType); + + navigateIntent.putParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST, failedFiles); + + final Notification.Builder errorBuilder = new Notification.Builder(serviceContext) + .setContentTitle(serviceContext.getResources().getQuantityString(titleId, + failedFiles.size(), failedFiles.size())) + .setContentText(serviceContext.getString(R.string.notification_touch_for_details)) + .setContentIntent(PendingIntent.getActivity(appContext, 0, navigateIntent, + PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_ONE_SHOT)) + .setCategory(Notification.CATEGORY_ERROR) + .setSmallIcon(icon) + .setAutoCancel(true); + return errorBuilder.build(); + } + + abstract Builder createProgressBuilder(); + + final Builder createProgressBuilder( + String title, @DrawableRes int icon, + String actionTitle, @DrawableRes int actionIcon) { + Notification.Builder progressBuilder = new Notification.Builder(serviceContext) + .setContentTitle(title) + .setContentIntent( + PendingIntent.getActivity(appContext, 0, buildNavigateIntent(), 0)) + .setCategory(Notification.CATEGORY_PROGRESS) + .setSmallIcon(icon) + .setOngoing(true); + + final Intent cancelIntent = createCancelIntent(); + + progressBuilder.addAction( + actionIcon, + actionTitle, + PendingIntent.getService( + serviceContext, + 0, + cancelIntent, + PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_CANCEL_CURRENT)); + + return progressBuilder; + } + + /** + * Creates an intent for navigating back to the destination directory. + */ + Intent buildNavigateIntent() { + Intent intent = new Intent(serviceContext, FilesActivity.class); + intent.setAction(DocumentsContract.ACTION_BROWSE); + intent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack); + return intent; + } + + Intent createCancelIntent() { + final Intent cancelIntent = new Intent(serviceContext, FileOperationService.class); + cancelIntent.putExtra(FileOperationService.EXTRA_CANCEL, true); + cancelIntent.putExtra(FileOperationService.EXTRA_JOB_ID, id); + return cancelIntent; + } + + interface Listener { + void onProgress(CopyJob job); + void onProgress(MoveJob job); + } +} diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java new file mode 100644 index 000000000000..4817f58d8d5a --- /dev/null +++ b/packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java @@ -0,0 +1,124 @@ +/* + * 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. + */ + +package com.android.documentsui.services; + +import android.app.Notification; +import android.app.Notification.Builder; +import android.content.Context; +import android.os.RemoteException; +import android.provider.DocumentsContract; +import android.provider.DocumentsContract.Document; +import android.util.Log; + +import com.android.documentsui.R; +import com.android.documentsui.model.DocumentInfo; +import com.android.documentsui.model.DocumentStack; + +import java.util.List; + +final class MoveJob extends CopyJob { + + private static final String TAG = "MoveJob"; + + /** + * Moves files to a destination identified by {@code destination}. + * Performs most work by delegating to CopyJob, then deleting + * a file after it has been copied. + * + * @see @link {@link Job} constructor for most param descriptions. + * + * @param srcs List of files to be moved. + */ + MoveJob(Context serviceContext, Context appContext, Listener listener, + String id, DocumentStack destination, List<DocumentInfo> srcs) { + super(serviceContext, appContext, listener, id, destination, srcs); + } + + @Override + int type() { + return FileOperationService.OPERATION_MOVE; + } + + @Override + Builder createProgressBuilder() { + return super.createProgressBuilder( + serviceContext.getString(R.string.move_notification_title), + R.drawable.ic_menu_copy, + serviceContext.getString(android.R.string.cancel), + R.drawable.ic_cab_cancel); + } + + @Override + public Notification getSetupNotification() { + return getSetupNotification(serviceContext.getString(R.string.move_preparing)); + } + + @Override + public Notification getProgressNotification() { + return getProgressNotification(R.string.copy_preparing); + } + + @Override + Notification getFailureNotification() { + return getFailureNotification( + R.plurals.move_error_notification_title, R.drawable.ic_menu_copy); + } + + /** + * Copies a the given document to the given location. + * + * @param srcInfo DocumentInfos for the documents to copy. + * @param dstDirInfo The destination directory. + * @param mode The transfer mode (copy or move). + * @return True on success, false on failure. + * @throws RemoteException + */ + @Override + boolean processDocument(DocumentInfo srcInfo, DocumentInfo dstDirInfo) throws RemoteException { + + // TODO: When optimized copy kicks in, we're not making any progress updates. FIX IT! + + // When copying within the same provider, try to use optimized copying and moving. + // If not supported, then fallback to byte-by-byte copy/move. + if (srcInfo.authority.equals(dstDirInfo.authority)) { + if ((srcInfo.flags & Document.FLAG_SUPPORTS_MOVE) != 0) { + if (DocumentsContract.moveDocument(srcClient, srcInfo.derivedUri, + dstDirInfo.derivedUri) == null) { + onFileFailed(srcInfo); + } + return false; + } + } + + // If we couldn't do an optimized copy...we fall back to vanilla byte copy. + boolean success = byteCopyDocument(srcInfo, dstDirInfo); + + if (success) { + // This is racey. We should make sure that we never delete a directory after + // it changed, so we don't remove a file which had not been copied earlier + // to the target location. + try { + DocumentsContract.deleteDocument(srcClient, srcInfo.derivedUri); + } catch (RemoteException e) { + Log.w(TAG, "Failed to delete source after copy: " + srcInfo.derivedUri, e); + return false; + } + } + + return success; + } +} diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java new file mode 100644 index 000000000000..b74b985a7d88 --- /dev/null +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StateTest.java @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package com.android.documentsui; + +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; + +import com.android.documentsui.model.DocumentInfo; + +@SmallTest +public class StateTest extends AndroidTestCase { + public void testPushDocument() { + final State state = new State(); + final DocumentInfo infoFirst = new DocumentInfo(); + infoFirst.displayName = "firstDirectory"; + final DocumentInfo infoSecond = new DocumentInfo(); + infoSecond.displayName = "secondDirectory"; + assertFalse(state.hasLocationChanged()); + state.pushDocument(infoFirst); + state.pushDocument(infoSecond); + assertTrue(state.hasLocationChanged()); + assertEquals("secondDirectory", state.stack.getFirst().displayName); + state.popDocument(); + assertEquals("firstDirectory", state.stack.getFirst().displayName); + } +} diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java index 2c311a7cc192..50f462807bfe 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/StubProvider.java @@ -316,12 +316,9 @@ public class StubProvider extends DocumentsProvider { String documentId, String mimeTypeFilter, Bundle opts, CancellationSignal signal) throws FileNotFoundException { final StubDocument document = mStorage.get(documentId); - if (document == null || !document.file.isFile()) { + if (document == null || !document.file.isFile() || document.streamTypes == null) { throw new FileNotFoundException(); } - if ((document.flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) == 0) { - throw new IllegalStateException("Tried to open a non-typed document as typed."); - } for (final String mimeType : document.streamTypes) { // Strict compare won't accept wildcards, but that's OK for tests, as DocumentsUI // doesn't use them for getStreamTypes nor openTypedDocument. @@ -349,13 +346,13 @@ public class StubProvider extends DocumentsProvider { throw new IllegalArgumentException( "The provided Uri is incorrect, or the file is gone."); } - if ((document.flags & Document.FLAG_SUPPORTS_TYPED_DOCUMENT) == 0) { - return null; - } if (!"*/*".equals(mimeTypeFilter)) { // Not used by DocumentsUI, so don't bother implementing it. throw new UnsupportedOperationException(); } + if (document.streamTypes == null) { + return null; + } return document.streamTypes.toArray(new String[document.streamTypes.size()]); } @@ -628,9 +625,6 @@ public class StubProvider extends DocumentsProvider { File file, String mimeType, List<String> streamTypes, StubDocument parent) { int flags = Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_WRITE | Document.FLAG_VIRTUAL_DOCUMENT; - if (streamTypes.size() > 0) { - flags |= Document.FLAG_SUPPORTS_TYPED_DOCUMENT; - } return new StubDocument(file, mimeType, streamTypes, flags, parent); } diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java index e06199efbc3b..7a3b6d430970 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java @@ -166,6 +166,12 @@ public class MultiSelectManagerTest extends AndroidTestCase { assertRangeSelection(0, 7); } + public void testKeyboardSelection() { + // This simulates shift-navigation. + keyToPosition(5, 10, true); + assertRangeSelection(5, 10); + } + public void testSingleSelectMode() { mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE); mManager.addCallback(mCallback); @@ -186,7 +192,7 @@ public class MultiSelectManagerTest extends AndroidTestCase { mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE); mManager.addCallback(mCallback); longPress(20); - keyToPosition(22, true); + keyToPosition(20, 22, true); assertSelection(items.get(22)); } @@ -250,8 +256,8 @@ public class MultiSelectManagerTest extends AndroidTestCase { mManager.onSingleTapUp(TestInputEvent.shiftClick(position)); } - private void keyToPosition(int position, boolean shift) { - mManager.attemptChangeFocus(position, shift); + private void keyToPosition(int startPos, int endPos, boolean shift) { + mManager.changeFocus(startPos, endPos, shift); } private void assertSelected(String... expected) { diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapperTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapperTest.java new file mode 100644 index 000000000000..398885cbdb84 --- /dev/null +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapperTest.java @@ -0,0 +1,170 @@ +/* + * 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. + */ + +package com.android.documentsui.dirlist; + +import android.content.Context; +import android.database.Cursor; +import android.database.MatrixCursor; +import android.provider.DocumentsContract.Document; +import android.support.v7.widget.RecyclerView; +import android.test.AndroidTestCase; +import android.test.suitebuilder.annotation.SmallTest; +import android.util.SparseArray; +import android.view.ViewGroup; + +import com.android.documentsui.DirectoryResult; +import com.android.documentsui.RootCursorWrapper; +import com.android.documentsui.State; + +import java.util.List; + +@SmallTest +public class SectionBreakDocumentsAdapterWrapperTest extends AndroidTestCase { + + private static final String AUTHORITY = "test_authority"; + private static final String[] NAMES = new String[] { + "4", + "foo", + "1", + "bar", + "*(Ljifl;a", + "0", + "baz", + "2", + "3", + "%$%VD" + }; + + private TestModel mModel; + private SectionBreakDocumentsAdapterWrapper mAdapter; + + public void setUp() { + + final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY); + DocumentsAdapter.Environment env = new TestEnvironment(testContext); + + mModel = new TestModel(testContext, AUTHORITY); + mAdapter = new SectionBreakDocumentsAdapterWrapper( + env, + new ModelBackedDocumentsAdapter( + env, new IconHelper(testContext, State.MODE_GRID))); + + mModel.addUpdateListener(mAdapter); + } + + // Tests that the item count is correct for a directory containing only subdirs. + public void testItemCount_allDirs() { + MatrixCursor c = new MatrixCursor(TestModel.COLUMNS); + + for (int i = 0; i < 5; ++i) { + MatrixCursor.RowBuilder row = c.newRow(); + row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY); + row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i)); + row.add(Document.COLUMN_SIZE, i); + row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR); + } + DirectoryResult r = new DirectoryResult(); + r.cursor = c; + r.sortOrder = State.SORT_ORDER_SIZE; + mModel.update(r); + + assertEquals(mModel.getItemCount(), mAdapter.getItemCount()); + } + + // Tests that the item count is correct for a directory containing only files. + public void testItemCount_allFiles() { + mModel.update(NAMES); + assertEquals(mModel.getItemCount(), mAdapter.getItemCount()); + } + + // Tests that the item count is correct for a directory containing files and subdirs. + public void testItemCount_mixed() { + MatrixCursor c = new MatrixCursor(TestModel.COLUMNS); + + for (int i = 0; i < 5; ++i) { + MatrixCursor.RowBuilder row = c.newRow(); + row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY); + row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i)); + row.add(Document.COLUMN_SIZE, i); + String mimeType =(i < 2) ? Document.MIME_TYPE_DIR : "text/*"; + row.add(Document.COLUMN_MIME_TYPE, mimeType); + } + DirectoryResult r = new DirectoryResult(); + r.cursor = c; + r.sortOrder = State.SORT_ORDER_SIZE; + mModel.update(r); + + assertEquals(mModel.getItemCount() + 1, mAdapter.getItemCount()); + } + + private final class TestEnvironment implements DocumentsAdapter.Environment { + private final Context testContext; + + private TestEnvironment(Context testContext) { + this.testContext = testContext; + } + + @Override + public boolean isSelected(String id) { + return false; + } + + @Override + public boolean isDocumentEnabled(String mimeType, int flags) { + return true; + } + + @Override + public void initDocumentHolder(DocumentHolder holder) {} + + @Override + public Model getModel() { + return mModel; + } + + @Override + public State getDisplayState() { + return null; + } + + @Override + public Context getContext() { + return testContext; + } + + @Override + public int getColumnCount() { + return 4; + } + + @Override + public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {} + } + + private static class DummyListener implements Model.UpdateListener { + public void onModelUpdate(Model model) {} + public void onModelUpdateFailed(Exception e) {} + } + + private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { + public int getItemCount() { return 0; } + public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {} + public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return null; + } + } +} diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java index 3a537a6f5ea3..f9cd3b2c0c25 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java @@ -29,7 +29,7 @@ import java.util.Set; public class TestModel extends Model { - private static final String[] COLUMNS = new String[]{ + static final String[] COLUMNS = new String[]{ RootCursorWrapper.COLUMN_AUTHORITY, Document.COLUMN_DOCUMENT_ID, Document.COLUMN_FLAGS, diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java index 24a811393b65..35aad60b274c 100644 --- a/packages/DocumentsUI/tests/src/com/android/documentsui/CopyServiceTest.java +++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.documentsui; +package com.android.documentsui.services; import android.content.ContentProviderClient; import android.content.ContentResolver; @@ -34,6 +34,9 @@ import android.test.mock.MockContentResolver; import android.test.suitebuilder.annotation.MediumTest; import android.util.Log; +import com.android.documentsui.DocumentsProviderHelper; +import com.android.documentsui.Shared; +import com.android.documentsui.StubProvider; import com.android.documentsui.model.DocumentInfo; import com.android.documentsui.model.DocumentStack; import com.android.documentsui.model.RootInfo; @@ -54,10 +57,10 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @MediumTest -public class CopyServiceTest extends ServiceTestCase<CopyService> { +public class FileOperationServiceTest extends ServiceTestCase<FileOperationService> { - public CopyServiceTest() { - super(CopyService.class); + public FileOperationServiceTest() { + super(FileOperationService.class); } private static String AUTHORITY = "com.android.documentsui.stubprovider"; @@ -139,7 +142,9 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { testContent.getBytes()); Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile)); - moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE); + moveIntent.putExtra( + FileOperationService.EXTRA_OPERATION, + FileOperationService.OPERATION_MOVE); startService(moveIntent); // 3 operations: file creation, writing data, deleting original. @@ -235,7 +240,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { Uri testDir = createTestDirectory(srcPath); Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir)); - moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE); + moveIntent.putExtra(FileOperationService.EXTRA_OPERATION, FileOperationService.OPERATION_MOVE); startService(moveIntent); // 2 operations: Directory creation, and removal of the original. @@ -270,7 +275,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { mStorage.createRegularFile(SRC_ROOT, srcFiles[2], "text/plain", testContent[2].getBytes()); Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir)); - moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE); + moveIntent.putExtra(FileOperationService.EXTRA_OPERATION, FileOperationService.OPERATION_MOVE); startService(moveIntent); // dir creation, then creation and writing of 3 files, then removal of src dir and 3 src @@ -311,10 +316,8 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { public void testCopyVirtualNonTypedFile() throws Exception { String srcPath = "/non-typed.sth"; - // Empty stream types causes the FLAG_SUPPORTS_TYPED_DOCUMENT to be not set. - ArrayList<String> streamTypes = new ArrayList<>(); Uri testFile = mStorage.createVirtualFile(SRC_ROOT, srcPath, "virtual/mime-type", - streamTypes, "I love Tokyo!".getBytes()); + null /* streamTypes */, "I love Tokyo!".getBytes()); Intent intent = createCopyIntent(Lists.newArrayList(testFile)); startService(intent); @@ -334,7 +337,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { mStorage.simulateReadErrorsForFile(testFile); Intent moveIntent = createCopyIntent(Lists.newArrayList(testFile)); - moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE); + moveIntent.putExtra(FileOperationService.EXTRA_OPERATION, FileOperationService.OPERATION_MOVE); startService(moveIntent); try { @@ -376,7 +379,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { mStorage.simulateReadErrorsForFile(errFile); Intent moveIntent = createCopyIntent(Lists.newArrayList(testDir)); - moveIntent.putExtra(CopyService.EXTRA_TRANSFER_MODE, CopyService.TRANSFER_MODE_MOVE); + moveIntent.putExtra(FileOperationService.EXTRA_OPERATION, FileOperationService.OPERATION_MOVE); startService(moveIntent); // - dst dir creation, @@ -424,8 +427,14 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { DocumentStack stack = new DocumentStack(); stack.push(DocumentInfo.fromUri(mResolver, dst)); - final Intent copyIntent = new Intent(mContext, CopyService.class); - copyIntent.putParcelableArrayListExtra(CopyService.EXTRA_SRC_LIST, srcDocs); + final Intent copyIntent = new Intent(mContext, FileOperationService.class); + copyIntent.putExtra( + FileOperationService.EXTRA_OPERATION, + FileOperationService.OPERATION_COPY); + copyIntent.putExtra( + FileOperationService.EXTRA_JOB_ID, + FileOperationService.createJobId()); + copyIntent.putParcelableArrayListExtra(FileOperationService.EXTRA_SRC_LIST, srcDocs); copyIntent.putExtra(Shared.EXTRA_STACK, (Parcelable) stack); return copyIntent; @@ -511,7 +520,7 @@ public class CopyServiceTest extends ServiceTestCase<CopyService> { mResolver.addProvider(AUTHORITY, mStorage); } - private final class CopyJobListener implements CopyService.TestOnlyListener { + private final class CopyJobListener implements FileOperationService.TestOnlyListener { final CountDownLatch latch = new CountDownLatch(1); final List<DocumentInfo> failedDocs = new ArrayList<>(); diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp index f592a1fb1ae1..f9fb85c446ad 100644 --- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp +++ b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp @@ -30,15 +30,13 @@ #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" +#include "nativehelper/ScopedPrimitiveArray.h" namespace { -constexpr int min(int a, int b) { - return a < b ? a : b; -} - // Maximum number of bytes to write in one request. constexpr size_t MAX_WRITE = 256 * 1024; +constexpr size_t NUM_MAX_HANDLES = 1024; // Largest possible request. // The request size is bounded by the maximum size of a FUSE_WRITE request @@ -47,6 +45,8 @@ constexpr size_t MAX_REQUEST_SIZE = sizeof(struct fuse_in_header) + sizeof(struct fuse_write_in) + MAX_WRITE; static jclass app_fuse_class; +static jmethodID app_fuse_get_file_size; +static jmethodID app_fuse_get_object_bytes; struct FuseRequest { char buffer[MAX_REQUEST_SIZE]; @@ -79,15 +79,25 @@ public: * The class is used to access AppFuse class in Java from fuse handlers. */ class AppFuse { + JNIEnv* env_; + jobject self_; + + // Map between file handle and inode. + std::map<uint32_t, uint64_t> handles_; + uint32_t handle_counter_; + public: - AppFuse(JNIEnv* /*env*/, jobject /*self*/) { - } + AppFuse(JNIEnv* env, jobject self) : + env_(env), self_(self), handle_counter_(0) {} bool handle_fuse_request(int fd, const FuseRequest& req) { ALOGV("Request op=%d", req.header().opcode); switch (req.header().opcode) { // TODO: Handle more operations that are enough to provide seekable // FD. + case FUSE_LOOKUP: + invoke_handler(fd, req, &AppFuse::handle_fuse_lookup); + return true; case FUSE_INIT: invoke_handler(fd, req, &AppFuse::handle_fuse_init); return true; @@ -96,6 +106,18 @@ public: return true; case FUSE_FORGET: return false; + case FUSE_OPEN: + invoke_handler(fd, req, &AppFuse::handle_fuse_open); + return true; + case FUSE_READ: + invoke_handler(fd, req, &AppFuse::handle_fuse_read, 8192); + return true; + case FUSE_RELEASE: + invoke_handler(fd, req, &AppFuse::handle_fuse_release, 0); + return true; + case FUSE_FLUSH: + invoke_handler(fd, req, &AppFuse::handle_fuse_flush, 0); + return true; default: { ALOGV("NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n", req.header().opcode, @@ -108,10 +130,37 @@ public: } private: + int handle_fuse_lookup(const fuse_in_header& header, + const char* name, + fuse_entry_out* out, + uint32_t* /*unused*/) { + if (header.nodeid != 1) { + return -ENOENT; + } + + const int n = atoi(name); + if (n == 0) { + return -ENOENT; + } + + int64_t size = get_file_size(n); + if (size < 0) { + return -ENOENT; + } + + out->nodeid = n; + out->attr_valid = 10; + out->entry_valid = 10; + out->attr.ino = n; + out->attr.mode = S_IFREG | 0777; + out->attr.size = size; + return 0; + } + int handle_fuse_init(const fuse_in_header&, const fuse_init_in* in, fuse_init_out* out, - size_t* reply_size) { + uint32_t* reply_size) { // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out // defined (fuse version 7.6). The structure is the same from 7.6 through // 7.22. Beginning with 7.23, the structure increased in size and added @@ -124,7 +173,7 @@ private: } // We limit ourselves to 15 because we don't handle BATCH_FORGET yet - out->minor = min(in->minor, 15); + out->minor = std::min(in->minor, 15u); #if defined(FUSE_COMPAT_22_INIT_OUT_SIZE) // FUSE_KERNEL_VERSION >= 23. @@ -152,7 +201,7 @@ private: int handle_fuse_getattr(const fuse_in_header& header, const fuse_getattr_in* /* in */, fuse_attr_out* out, - size_t* /*unused*/) { + uint32_t* /*unused*/) { if (header.nodeid != 1) { return -ENOENT; } @@ -163,14 +212,67 @@ private: return 0; } + int handle_fuse_open(const fuse_in_header& header, + const fuse_open_in* /* in */, + fuse_open_out* out, + uint32_t* /*unused*/) { + if (handles_.size() >= NUM_MAX_HANDLES) { + // Too many open files. + return -EMFILE; + } + uint32_t handle; + do { + handle = handle_counter_++; + } while (handles_.count(handle) != 0); + + handles_.insert(std::make_pair(handle, header.nodeid)); + out->fh = handle; + return 0; + } + + int handle_fuse_read(const fuse_in_header& /* header */, + const fuse_read_in* in, + void* out, + uint32_t* reply_size) { + const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh); + if (it == handles_.end()) { + return -EBADF; + } + const int64_t result = get_object_bytes( + it->second, + in->offset, + in->size, + out); + if (result < 0) { + return -EIO; + } + *reply_size = static_cast<size_t>(result); + return 0; + } + + int handle_fuse_release(const fuse_in_header& /* header */, + const fuse_release_in* in, + void* /* out */, + uint32_t* /* reply_size */) { + handles_.erase(in->fh); + return 0; + } + + int handle_fuse_flush(const fuse_in_header& /* header */, + const void* /* in */, + void* /* out */, + uint32_t* /* reply_size */) { + return 0; + } + template <typename T, typename S> void invoke_handler(int fd, const FuseRequest& request, int (AppFuse::*handler)(const fuse_in_header&, const T*, S*, - size_t*), - size_t reply_size = sizeof(S)) { + uint32_t*), + uint32_t reply_size = sizeof(S)) { char reply_data[reply_size]; memset(reply_data, 0, reply_size); const int reply_code = (this->*handler)( @@ -186,6 +288,39 @@ private: reply_size); } + int64_t get_file_size(int inode) { + return static_cast<int64_t>(env_->CallLongMethod( + self_, + app_fuse_get_file_size, + static_cast<int>(inode))); + } + + int64_t get_object_bytes( + int inode, + uint64_t offset, + uint32_t size, + void* buf) { + const uint32_t read_size = static_cast<uint32_t>(std::min( + static_cast<uint64_t>(size), + get_file_size(inode) - offset)); + const jbyteArray array = (jbyteArray) env_->CallObjectMethod( + self_, + app_fuse_get_object_bytes, + inode, + offset, + read_size); + if (array == nullptr) { + return -1; + } + ScopedByteArrayRO bytes(env_, array); + if (bytes.size() != read_size || bytes.get() == nullptr) { + return -1; + } + + memcpy(buf, bytes.get(), read_size); + return read_size; + } + static void fuse_reply(int fd, int unique, int reply_code, void* reply_data, size_t reply_size) { // Don't send any data for error case. @@ -219,6 +354,7 @@ jboolean com_android_mtp_AppFuse_start_app_fuse_loop( ALOGD("Start fuse loop."); while (true) { FuseRequest request; + const ssize_t result = TEMP_FAILURE_RETRY( read(fd, request.buffer, sizeof(request.buffer))); if (result < 0) { @@ -272,12 +408,27 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { ALOGE("Can't find com/android/mtp/AppFuse"); return -1; } + app_fuse_class = static_cast<jclass>(env->NewGlobalRef(clazz)); if (app_fuse_class == nullptr) { ALOGE("Can't obtain global reference for com/android/mtp/AppFuse"); return -1; } + app_fuse_get_file_size = env->GetMethodID( + app_fuse_class, "getFileSize", "(I)J"); + if (app_fuse_get_file_size == nullptr) { + ALOGE("Can't find getFileSize"); + return -1; + } + + app_fuse_get_object_bytes = env->GetMethodID( + app_fuse_class, "getObjectBytes", "(IJI)[B"); + if (app_fuse_get_object_bytes == nullptr) { + ALOGE("Can't find getObjectBytes"); + return -1; + } + const int result = android::AndroidRuntime::registerNativeMethods( env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods)); if (result < 0) { diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java index 2c09ad135266..5ffd7cf27b5f 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java @@ -17,16 +17,14 @@ package com.android.mtp; import android.os.ParcelFileDescriptor; +import android.os.Process; import android.os.storage.StorageManager; import android.util.Log; - import com.android.internal.annotations.VisibleForTesting; - import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; -import android.os.Process; - /** * TODO: Remove VisibleForTesting class. */ @@ -37,12 +35,14 @@ public class AppFuse { } private final String mName; + private final Callback mCallback; private final Thread mMessageThread; private ParcelFileDescriptor mDeviceFd; @VisibleForTesting - AppFuse(String name) { + AppFuse(String name, Callback callback) { mName = name; + mCallback = callback; mMessageThread = new Thread(new Runnable() { @Override public void run() { @@ -72,10 +72,45 @@ public class AppFuse { } } + /** + * @param i + * @throws FileNotFoundException + */ + @VisibleForTesting + public ParcelFileDescriptor openFile(int i) throws FileNotFoundException { + return ParcelFileDescriptor.open(new File( + getMountPoint(), + Integer.toString(i)), + ParcelFileDescriptor.MODE_READ_ONLY); + } + @VisibleForTesting File getMountPoint() { return new File("/mnt/appfuse/" + Process.myUid() + "_" + mName); } + static interface Callback { + long getFileSize(int inode) throws FileNotFoundException; + byte[] getObjectBytes(int inode, long offset, int size) throws IOException; + } + + @VisibleForTesting + private long getFileSize(int inode) { + try { + return mCallback.getFileSize(inode); + } catch (IOException e) { + return -1; + } + } + + @VisibleForTesting + private byte[] getObjectBytes(int inode, long offset, int size) { + try { + return mCallback.getObjectBytes(inode, offset, size); + } catch (IOException e) { + return null; + } + } + private native boolean native_start_app_fuse_loop(int fd); } diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java index 71df5c15bed4..02d07b9275fe 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDeviceRecord.java @@ -21,11 +21,14 @@ class MtpDeviceRecord { public final String name; public final boolean opened; public final MtpRoot[] roots; + public final int[] operationsSupported; - MtpDeviceRecord(int deviceId, String name, boolean opened, MtpRoot[] roots) { + MtpDeviceRecord( + int deviceId, String name, boolean opened, MtpRoot[] roots, int[] operationsSupported) { this.deviceId = deviceId; this.name = name; this.opened = opened; this.roots = roots; + this.operationsSupported = operationsSupported; } } diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java index 88cab8b30a80..9c726ba24ce6 100644 --- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java +++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java @@ -24,6 +24,7 @@ import android.hardware.usb.UsbInterface; import android.hardware.usb.UsbManager; import android.mtp.MtpConstants; import android.mtp.MtpDevice; +import android.mtp.MtpDeviceInfo; import android.mtp.MtpEvent; import android.mtp.MtpObjectInfo; import android.os.CancellationSignal; @@ -123,9 +124,11 @@ class MtpManager { if (!isMtpDevice(device)) { continue; } - final boolean opened = mDevices.get(device.getDeviceId()) != null; + final MtpDevice mtpDevice = mDevices.get(device.getDeviceId()); + final boolean opened = mtpDevice != null; final String name = device.getProductName(); MtpRoot[] roots; + int[] operationsSupported = null; if (opened) { try { roots = getRoots(device.getDeviceId()); @@ -136,10 +139,19 @@ class MtpManager { // the device is physically connected. roots = new MtpRoot[0]; } + final MtpDeviceInfo info = mtpDevice.getDeviceInfo(); + if (info != null) { + operationsSupported = mtpDevice.getDeviceInfo().getOperationsSupported(); + } + if (operationsSupported == null) { + operationsSupported = new int[0]; + } } else { roots = new MtpRoot[0]; + operationsSupported = new int[0]; } - devices.add(new MtpDeviceRecord(device.getDeviceId(), name, opened, roots)); + devices.add(new MtpDeviceRecord( + device.getDeviceId(), name, opened, roots, operationsSupported)); } return devices.toArray(new MtpDeviceRecord[devices.size()]); } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java index b66d8ebec212..76bd2b546472 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java @@ -16,24 +16,27 @@ package com.android.mtp; +import android.os.ParcelFileDescriptor; import android.os.storage.StorageManager; import android.system.ErrnoException; import android.system.Os; import android.test.AndroidTestCase; -import android.test.suitebuilder.annotation.SmallTest; +import android.test.suitebuilder.annotation.MediumTest; import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.Arrays; -@SmallTest +/** + * TODO: Enable this test after adding SELinux policies for appfuse. + */ +@MediumTest public class AppFuseTest extends AndroidTestCase { - /** - * TODO: Enable this test after adding SELinux policies for appfuse. - * @throws ErrnoException - * @throws InterruptedException - */ - public void disabled_testBasic() throws ErrnoException, InterruptedException { + + public void disabled_testMount() throws ErrnoException, InterruptedException { final StorageManager storageManager = getContext().getSystemService(StorageManager.class); - final AppFuse appFuse = new AppFuse("test"); + final AppFuse appFuse = new AppFuse("test", new TestCallback()); appFuse.mount(storageManager); final File file = appFuse.getMountPoint(); assertTrue(file.isDirectory()); @@ -41,4 +44,86 @@ public class AppFuseTest extends AndroidTestCase { appFuse.close(); assertTrue(1 != Os.stat(file.getPath()).st_ino); } + + public void disabled_testOpenFile() throws IOException { + final StorageManager storageManager = getContext().getSystemService(StorageManager.class); + final int INODE = 10; + final AppFuse appFuse = new AppFuse( + "test", + new TestCallback() { + @Override + public long getFileSize(int inode) throws FileNotFoundException { + if (INODE == inode) { + return 1024; + } + throw new FileNotFoundException(); + } + }); + appFuse.mount(storageManager); + final ParcelFileDescriptor fd = appFuse.openFile(INODE); + fd.close(); + appFuse.close(); + } + + public void disabled_testOpenFile_error() { + final StorageManager storageManager = getContext().getSystemService(StorageManager.class); + final int INODE = 10; + final AppFuse appFuse = new AppFuse("test", new TestCallback()); + appFuse.mount(storageManager); + try { + appFuse.openFile(INODE); + fail(); + } catch (Throwable t) { + assertTrue(t instanceof FileNotFoundException); + } + appFuse.close(); + } + + public void disabled_testReadFile() throws IOException { + final StorageManager storageManager = getContext().getSystemService(StorageManager.class); + final int INODE = 10; + final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' }; + final AppFuse appFuse = new AppFuse( + "test", + new TestCallback() { + @Override + public long getFileSize(int inode) throws FileNotFoundException { + if (inode == INODE) { + return BYTES.length; + } + return super.getFileSize(inode); + } + + @Override + public byte[] getObjectBytes(int inode, long offset, int size) + throws IOException { + if (inode == INODE) { + return Arrays.copyOfRange(BYTES, (int) offset, (int) offset + size); + } + return super.getObjectBytes(inode, offset, size); + } + }); + appFuse.mount(storageManager); + final ParcelFileDescriptor fd = appFuse.openFile(INODE); + try (final ParcelFileDescriptor.AutoCloseInputStream stream = + new ParcelFileDescriptor.AutoCloseInputStream(fd)) { + final byte[] buffer = new byte[1024]; + final int size = stream.read(buffer, 0, buffer.length); + assertEquals(5, size); + } + appFuse.close(); + } + + private static class TestCallback implements AppFuse.Callback { + @Override + public long getFileSize(int inode) throws FileNotFoundException { + throw new FileNotFoundException(); + } + + @Override + public byte[] getObjectBytes(int inode, long offset, int size) + throws IOException { + throw new IOException(); + } + } } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java index 1e1ea0a748a8..c39d5b39051d 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java @@ -77,7 +77,7 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testPutSingleStorageDocuments() throws Exception { mDatabase.getMapper().startAddingDocuments(null); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(0, "Device", true, new MtpRoot[0])); + new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], new int[0])); mDatabase.getMapper().stopAddingDocuments(null); mDatabase.getMapper().startAddingDocuments("1"); @@ -425,9 +425,9 @@ public class MtpDatabaseTest extends AndroidTestCase { }; mDatabase.getMapper().startAddingDocuments(null); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(0, "Device A", true, new MtpRoot[0])); + new MtpDeviceRecord(0, "Device A", true, new MtpRoot[0], new int[0])); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(1, "Device B", true, new MtpRoot[0])); + new MtpDeviceRecord(1, "Device B", true, new MtpRoot[0], new int[0])); mDatabase.getMapper().stopAddingDocuments(null); mDatabase.getMapper().startAddingDocuments("1"); @@ -562,7 +562,7 @@ public class MtpDatabaseTest extends AndroidTestCase { mDatabase.getMapper().startAddingDocuments(null); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(0, "Device", false, new MtpRoot[0])); + new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], new int[0])); mDatabase.getMapper().stopAddingDocuments(null); mDatabase.getMapper().startAddingDocuments("1"); @@ -640,7 +640,7 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testReplaceExistingRoots() { mDatabase.getMapper().startAddingDocuments(null); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(0, "Device", true, new MtpRoot[0])); + new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], new int[0])); mDatabase.getMapper().stopAddingDocuments(null); // The client code should be able to replace existing rows with new information. @@ -691,7 +691,7 @@ public class MtpDatabaseTest extends AndroidTestCase { // Add one. mDatabase.getMapper().startAddingDocuments(null); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(0, "Device", true, new MtpRoot[0])); + new MtpDeviceRecord(0, "Device", true, new MtpRoot[0], new int[0])); mDatabase.getMapper().stopAddingDocuments(null); mDatabase.getMapper().startAddingDocuments("1"); @@ -745,7 +745,7 @@ public class MtpDatabaseTest extends AndroidTestCase { // Add device document. mDatabase.getMapper().startAddingDocuments(null); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(0, "Device", false, new MtpRoot[0])); + new MtpDeviceRecord(0, "Device", false, new MtpRoot[0], new int[0])); mDatabase.getMapper().stopAddingDocuments(null); // It the device does not have storages, it shows a device root. @@ -895,7 +895,7 @@ public class MtpDatabaseTest extends AndroidTestCase { public void testGetDocumentIdForDevice() { mDatabase.getMapper().startAddingDocuments(null); mDatabase.getMapper().putDeviceDocument( - new MtpDeviceRecord(100, "Device", true, new MtpRoot[0])); + new MtpDeviceRecord(100, "Device", true, new MtpRoot[0], new int[0])); mDatabase.getMapper().stopAddingDocuments(null); assertEquals("1", mDatabase.getDocumentIdForDevice(100)); } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java index 71c48971ca32..44841af2eff6 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java @@ -68,7 +68,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { 1024 /* free space */, 2048 /* total space */, "" /* no volume identifier */) - })); + }, + new int[0])); mProvider.openDevice(0); mResolver.waitForNotification(ROOTS_URI, 1); @@ -107,7 +108,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { 1024 /* free space */, 2048 /* total space */, "" /* no volume identifier */) - })); + }, + new int[0])); mProvider.openDevice(0); mResolver.waitForNotification(ROOTS_URI, 1); } @@ -127,7 +129,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { 1024 /* free space */, 2048 /* total space */, "" /* no volume identifier */) - })); + }, + new int[0])); mMtpManager.addValidDevice(new MtpDeviceRecord( 1, "Device", @@ -141,7 +144,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { 2048 /* free space */, 4096 /* total space */, "Identifier B" /* no volume identifier */) - })); + }, + new int[0])); { mProvider.openDevice(0); @@ -175,8 +179,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { public void testQueryRoots_error() throws Exception { setupProvider(MtpDatabaseConstants.FLAG_DATABASE_IN_MEMORY); - mMtpManager.addValidDevice( - new MtpDeviceRecord(0, "Device A", false /* unopened */, new MtpRoot[0])); + mMtpManager.addValidDevice(new MtpDeviceRecord( + 0, "Device A", false /* unopened */, new MtpRoot[0], new int[0])); mMtpManager.addValidDevice(new MtpDeviceRecord( 1, "Device", @@ -190,7 +194,8 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { 2048 /* free space */, 4096 /* total space */, "Identifier B" /* no volume identifier */) - })); + }, + new int[0])); { mProvider.openDevice(0); mProvider.openDevice(1); @@ -433,7 +438,7 @@ public class MtpDocumentsProviderTest extends AndroidTestCase { throws InterruptedException, TimeoutException, IOException { final int changeCount = mResolver.getChangeCount(ROOTS_URI); mMtpManager.addValidDevice( - new MtpDeviceRecord(deviceId, "Device", false /* unopened */, roots)); + new MtpDeviceRecord(deviceId, "Device", false /* unopened */, roots, new int[0])); mProvider.openDevice(deviceId); mResolver.waitForNotification(ROOTS_URI, changeCount + 1); return getStrings(mProvider.queryRoots(strings(DocumentsContract.Root.COLUMN_ROOT_ID))); diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java index 5e95e4f88386..49b48c5bb66d 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java @@ -21,9 +21,11 @@ import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.os.CancellationSignal; import android.os.OperationCanceledException; +import android.os.SystemClock; import android.test.InstrumentationTestCase; import java.io.IOException; +import java.util.Arrays; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; import java.util.concurrent.TimeUnit; @@ -71,11 +73,18 @@ public class MtpManagerTest extends InstrumentationTestCase { }); final Thread thread = new Thread(future); thread.start(); - Thread.sleep(TIMEOUT_MS); + SystemClock.sleep(TIMEOUT_MS); signal.cancel(); assertTrue(future.get(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } + public void testOperationsSupported() { + final MtpDeviceRecord[] records = mManager.getDevices(); + assertEquals(1, records.length); + assertNotNull(records[0].operationsSupported); + getInstrumentation().show(Arrays.toString(records[0].operationsSupported)); + } + private Context getContext() { return getInstrumentation().getContext(); } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java index bbd0a300c6a1..3934b88140bb 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestMtpManager.java @@ -76,7 +76,7 @@ public class TestMtpManager extends MtpManager { result[i] = device; } else { result[i] = new MtpDeviceRecord( - device.deviceId, device.name, device.opened, new MtpRoot[0]); + device.deviceId, device.name, device.opened, new MtpRoot[0], new int[0]); } } return result; @@ -90,7 +90,7 @@ public class TestMtpManager extends MtpManager { } mDevices.put( deviceId, - new MtpDeviceRecord(device.deviceId, device.name, true, device.roots)); + new MtpDeviceRecord(device.deviceId, device.name, true, device.roots, new int[0])); } @Override @@ -101,7 +101,7 @@ public class TestMtpManager extends MtpManager { } mDevices.put( deviceId, - new MtpDeviceRecord(device.deviceId, device.name, false, device.roots)); + new MtpDeviceRecord(device.deviceId, device.name, false, device.roots, new int[0])); } @Override @@ -203,4 +203,9 @@ public class TestMtpManager extends MtpManager { } return Arrays.copyOf(result, count); } + + @Override + byte[] getObject(int deviceId, int objectHandle, int expectedSize) throws IOException { + return mImportFileBytes.get(pack(deviceId, objectHandle)); + } } diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java index 611e8317c4e4..2935267d9f07 100644 --- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java +++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestUtil.java @@ -16,27 +16,21 @@ package com.android.mtp; -import android.app.PendingIntent; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbDeviceConnection; import android.hardware.usb.UsbManager; +import android.os.SystemClock; import java.io.IOException; import java.util.HashMap; -import java.util.concurrent.CountDownLatch; +import java.util.Objects; + import junit.framework.Assert; /** * Static utility methods for testing. */ final class TestUtil { - private static final String ACTION_USB_PERMISSION = - "com.android.mtp.USB_PERMISSION"; - private TestUtil() {} /** @@ -46,81 +40,66 @@ final class TestUtil { static UsbDevice setupMtpDevice( TestResultInstrumentation instrumentation, UsbManager usbManager, - MtpManager manager) throws InterruptedException, IOException { - for (int i = 0; i < 2; i++) { - final UsbDevice device = findMtpDevice(instrumentation, usbManager); - manager.openDevice(device.getDeviceId()); + MtpManager manager) { + while (true) { + final UsbDevice device = findMtpDevice(instrumentation, usbManager, manager); try { + manager.openDevice(device.getDeviceId()); waitForStorages(instrumentation, manager, device.getDeviceId()); return device; } catch (IOException exp) { + instrumentation.show(Objects.toString(exp.getMessage())); + SystemClock.sleep(1000); // When the MTP device is Android, and it changes the USB device type from // "Charging" to "MTP", the device ID will be updated. We need to find a device // again. continue; } } - throw new IOException("Failed to obtain MTP devices"); } private static UsbDevice findMtpDevice( TestResultInstrumentation instrumentation, - UsbManager usbManager) throws InterruptedException { + UsbManager usbManager, + MtpManager manager) { while (true) { final HashMap<String,UsbDevice> devices = usbManager.getDeviceList(); if (devices.size() == 0) { instrumentation.show("Wait for devices."); - Thread.sleep(1000); + SystemClock.sleep(1000); continue; } final UsbDevice device = devices.values().iterator().next(); - requestPermission(instrumentation, usbManager, device); - final UsbDeviceConnection connection = usbManager.openDevice(device); - if (connection == null) { - Assert.fail("Cannot open USB connection."); - return null; - } - for (int i = 0; i < device.getInterfaceCount(); i++) { - // Since the test runs real environment, we need to call claim interface with - // force = true to rob interfaces from other applications. - connection.claimInterface(device.getInterface(i), true); - connection.releaseInterface(device.getInterface(i)); + try { + manager.openDevice(device.getDeviceId()); + } catch (IOException e) { + // Maybe other application is using the device. + // Force to obtain ownership of the device so that we can use the device next call + // of findMtpDevice. + instrumentation.show("Tries to get ownership of MTP device."); + final UsbDeviceConnection connection = usbManager.openDevice(device); + if (connection == null) { + Assert.fail("Cannot open USB connection."); + return null; + } + for (int i = 0; i < device.getInterfaceCount(); i++) { + // Since the test runs real environment, we need to call claim interface with + // force = true to rob interfaces from other applications. + connection.claimInterface(device.getInterface(i), true); + connection.releaseInterface(device.getInterface(i)); + } + connection.close(); + SystemClock.sleep(1000); + continue; } - connection.close(); return device; } } - private static void requestPermission( - final TestResultInstrumentation instrumentation, - UsbManager usbManager, - UsbDevice device) throws InterruptedException { - if (usbManager.hasPermission(device)) { - return; - } - final CountDownLatch latch = new CountDownLatch(1); - final BroadcastReceiver receiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - latch.countDown(); - instrumentation.getTargetContext().unregisterReceiver(this); - } - }; - instrumentation.getTargetContext().registerReceiver( - receiver, new IntentFilter(ACTION_USB_PERMISSION)); - usbManager.requestPermission(device, PendingIntent.getBroadcast( - instrumentation.getTargetContext(), - 0 /* requstCode */, - new Intent(ACTION_USB_PERMISSION), - 0 /* flags */)); - latch.await(); - Assert.assertTrue(usbManager.hasPermission(device)); - } - private static void waitForStorages( TestResultInstrumentation instrumentation, MtpManager manager, - int deviceId) throws InterruptedException, IOException { + int deviceId) throws IOException { while (true) { MtpDeviceRecord device = null; for (final MtpDeviceRecord deviceCandidate : manager.getDevices()) { @@ -134,7 +113,7 @@ final class TestUtil { } if (device.roots.length == 0) { instrumentation.show("Wait for storages."); - Thread.sleep(1000); + SystemClock.sleep(1000); continue; } return; diff --git a/packages/PrintSpooler/res/values/strings.xml b/packages/PrintSpooler/res/values/strings.xml index 97a7bffe9bf3..b662c58fa122 100644 --- a/packages/PrintSpooler/res/values/strings.xml +++ b/packages/PrintSpooler/res/values/strings.xml @@ -178,12 +178,6 @@ <!-- Template for the notification label for a blocked print job. [CHAR LIMIT=25] --> <string name="blocked_notification_title_template">Printer blocked <xliff:g id="print_job_name" example="foo.jpg">%1$s</xliff:g></string> - <!-- Template for the notification label for a composite (multiple items) print jobs notification. [CHAR LIMIT=25] --> - <plurals name="composite_notification_title_template"> - <item quantity="one"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print job</item> - <item quantity="other"><xliff:g id="print_job_name" example="foo.jpg">%1$d</xliff:g> print jobs</item> - </plurals> - <!-- Label for the notification button for cancelling a print job. [CHAR LIMIT=25] --> <string name="cancel">Cancel</string> diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java index 3dc5d7eccdf6..0210693c302c 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java @@ -40,6 +40,7 @@ import android.print.PrintJobId; import android.print.PrintJobInfo; import android.print.PrintManager; import android.provider.Settings; +import android.util.ArraySet; import android.util.Log; import com.android.printspooler.R; @@ -61,13 +62,22 @@ final class NotificationController { private static final String EXTRA_PRINT_JOB_ID = "EXTRA_PRINT_JOB_ID"; + private static final String PRINT_JOB_NOTIFICATION_GROUP_KEY = "PRINT_JOB_NOTIFICATIONS"; + private static final String PRINT_JOB_NOTIFICATION_SUMMARY = "PRINT_JOB_NOTIFICATIONS_SUMMARY"; + private final Context mContext; private final NotificationManager mNotificationManager; + /** + * Mapping from printJobIds to their notification Ids. + */ + private final ArraySet<PrintJobId> mNotifications; + public NotificationController(Context context) { mContext = context; mNotificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + mNotifications = new ArraySet<>(0); } public void onUpdateNotifications(List<PrintJobInfo> printJobs) { @@ -81,16 +91,44 @@ final class NotificationController { } } - updateNotification(notifyPrintJobs); + updateNotifications(notifyPrintJobs); } - private void updateNotification(List<PrintJobInfo> printJobs) { - if (printJobs.size() <= 0) { - removeNotification(); - } else if (printJobs.size() == 1) { - createSimpleNotification(printJobs.get(0)); - } else { + /** + * Update notifications for the given print jobs, remove all other notifications. + * + * @param printJobs The print job that we want to create notifications for. + */ + private void updateNotifications(List<PrintJobInfo> printJobs) { + ArraySet<PrintJobId> removedPrintJobs = new ArraySet<>(mNotifications); + + final int numPrintJobs = printJobs.size(); + + // Create summary notification + if (numPrintJobs > 1) { createStackedNotification(printJobs); + } else { + mNotificationManager.cancel(PRINT_JOB_NOTIFICATION_SUMMARY, 0); + } + + // Create per print job notification + for (int i = 0; i < numPrintJobs; i++) { + PrintJobInfo printJob = printJobs.get(i); + PrintJobId printJobId = printJob.getId(); + + removedPrintJobs.remove(printJobId); + mNotifications.add(printJobId); + + createSimpleNotification(printJob); + } + + // Remove notifications for print jobs that do not exist anymore + final int numRemovedPrintJobs = removedPrintJobs.size(); + for (int i = 0; i < numRemovedPrintJobs; i++) { + PrintJobId removedPrintJob = removedPrintJobs.valueAt(i); + + mNotificationManager.cancel(removedPrintJob.flattenToString(), 0); + mNotifications.remove(removedPrintJob); } } @@ -148,7 +186,8 @@ final class NotificationController { .setOngoing(true) .setShowWhen(true) .setColor(mContext.getColor( - com.android.internal.R.color.system_notification_accent_color)); + com.android.internal.R.color.system_notification_accent_color)) + .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY); if (firstAction != null) { builder.addAction(firstAction); @@ -176,7 +215,7 @@ final class NotificationController { builder.setContentText(printJob.getPrinterName()); } - mNotificationManager.notify(0, builder.build()); + mNotificationManager.notify(printJob.getId().flattenToString(), 0, builder.build()); } private void createPrintingNotification(PrintJobInfo printJob) { @@ -204,33 +243,36 @@ final class NotificationController { .setContentIntent(createContentIntent(null)) .setWhen(System.currentTimeMillis()) .setOngoing(true) - .setShowWhen(true); + .setShowWhen(true) + .setGroup(PRINT_JOB_NOTIFICATION_GROUP_KEY) + .setGroupSummary(true); final int printJobCount = printJobs.size(); InboxStyle inboxStyle = new InboxStyle(); - inboxStyle.setBigContentTitle(String.format(mContext.getResources().getQuantityText( - R.plurals.composite_notification_title_template, - printJobCount).toString(), printJobCount)); + int icon = com.android.internal.R.drawable.ic_print; for (int i = printJobCount - 1; i>= 0; i--) { PrintJobInfo printJob = printJobs.get(i); - if (i == printJobCount - 1) { - builder.setLargeIcon(((BitmapDrawable) mContext.getResources().getDrawable( - computeNotificationIcon(printJob), null)).getBitmap()); - builder.setSmallIcon(computeNotificationIcon(printJob)); - builder.setContentTitle(computeNotificationTitle(printJob)); - builder.setContentText(printJob.getPrinterName()); - } + inboxStyle.addLine(computeNotificationTitle(printJob)); + + // if any print job is in an error state show an error icon for the summary + if (printJob.getState() == PrintJobInfo.STATE_FAILED + || printJob.getState() == PrintJobInfo.STATE_BLOCKED) { + icon = com.android.internal.R.drawable.ic_print_error; + } } + builder.setSmallIcon(icon); + builder.setLargeIcon( + ((BitmapDrawable) mContext.getResources().getDrawable(icon, null)).getBitmap()); builder.setNumber(printJobCount); builder.setStyle(inboxStyle); builder.setColor(mContext.getColor( com.android.internal.R.color.system_notification_accent_color)); - mNotificationManager.notify(0, builder.build()); + mNotificationManager.notify(PRINT_JOB_NOTIFICATION_SUMMARY, 0, builder.build()); } private String computeNotificationTitle(PrintJobInfo printJob) { @@ -264,10 +306,6 @@ final class NotificationController { } } - private void removeNotification() { - mNotificationManager.cancel(0); - } - private PendingIntent createContentIntent(PrintJobId printJobId) { Intent intent = new Intent(Settings.ACTION_PRINT_SETTINGS); if (printJobId != null) { diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java index 496a0b09b905..18160ff56ce8 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java @@ -1416,9 +1416,9 @@ public final class PrintSpoolerService extends Service { } @Override - public void removeApprovedPrintService(ComponentName serviceToRemove) { + public void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) { (new ApprovedPrintServices(PrintSpoolerService.this)) - .removeApprovedService(serviceToRemove); + .pruneApprovedServices(servicesToKeep); } @Override diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java index cdfc7ee11b1e..81727ab4222a 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/SelectPrinterActivity.java @@ -66,6 +66,7 @@ import android.widget.ListView; import android.widget.SearchView; import android.widget.TextView; +import com.android.internal.content.PackageMonitor; import com.android.printspooler.R; import java.util.ArrayList; @@ -101,7 +102,8 @@ public final class SelectPrinterActivity extends Activity { private AnnounceFilterResult mAnnounceFilterResult; /** Monitor if new print services get enabled or disabled */ - private ContentObserver mPrintServicesObserver; + private ContentObserver mPrintServicesDisabledObserver; + private PackageMonitor mPackageObserver; @Override public void onCreate(Bundle savedInstanceState) { @@ -245,28 +247,45 @@ public final class SelectPrinterActivity extends Activity { * Register listener for changes to the enabled print services. */ private void registerServiceMonitor() { - mPrintServicesObserver = new ContentObserver(new Handler()) { + // Listen for services getting disabled + mPrintServicesDisabledObserver = new ContentObserver(new Handler()) { @Override public void onChange(boolean selfChange) { onPrintServicesUpdate(); } }; + // Listen for services getting installed or uninstalled + mPackageObserver = new PackageMonitor() { + @Override + public void onPackageModified(String packageName) { + onPrintServicesUpdate(); + } + + @Override + public void onPackageRemoved(String packageName, int uid) { + onPrintServicesUpdate(); + } + + @Override + public void onPackageAdded(String packageName, int uid) { + onPrintServicesUpdate(); + } + }; + getContentResolver().registerContentObserver( - Settings.Secure.getUriFor(Settings.Secure.ENABLED_PRINT_SERVICES), false, - mPrintServicesObserver); + Settings.Secure.getUriFor(Settings.Secure.DISABLED_PRINT_SERVICES), false, + mPrintServicesDisabledObserver); + + mPackageObserver.register(this, getMainLooper(), false); } /** - * Unregister {@link #mPrintServicesObserver listener for changes to the enabled print services} - * or nothing if the listener is not registered. + * Unregister the listeners for changes to the enabled print services. */ private void unregisterServiceMonitorIfNeeded() { - if (mPrintServicesObserver != null) { - getContentResolver().unregisterContentObserver(mPrintServicesObserver); - - mPrintServicesObserver = null; - } + getContentResolver().unregisterContentObserver(mPrintServicesDisabledObserver); + mPackageObserver.unregister(); } @Override diff --git a/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java b/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java index dd10567f00ab..a1e3ef430c9e 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java +++ b/packages/PrintSpooler/src/com/android/printspooler/util/ApprovedPrintServices.java @@ -23,6 +23,7 @@ import android.content.SharedPreferences.OnSharedPreferenceChangeListener; import android.printservice.PrintService; import android.util.ArraySet; +import java.util.List; import java.util.Set; /** @@ -126,29 +127,27 @@ public class ApprovedPrintServices { } /** - * If a {@link PrintService} is approved, remove it from the list of approved services. + * Remove all approved {@link PrintService print services} that are not in the given set. * - * @param serviceToRemove The {@link ComponentName} of the {@link PrintService} to be removed + * @param serviceNamesToKeep The {@link ComponentName names } of the services to keep */ - public void removeApprovedService(ComponentName serviceToRemove) { + public void pruneApprovedServices(List<ComponentName> serviceNamesToKeep) { synchronized (sLock) { - if (isApprovedService(serviceToRemove)) { - // Copy approved services. - ArraySet<String> approvedServices = new ArraySet<String>( - mPreferences.getStringSet(APPROVED_SERVICES_PREFERENCE, null)); + Set<String> approvedServices = getApprovedServices(); + Set<String> newApprovedServices = new ArraySet<>(approvedServices.size()); + + final int numServiceNamesToKeep = serviceNamesToKeep.size(); + for(int i = 0; i < numServiceNamesToKeep; i++) { + String serviceToKeep = serviceNamesToKeep.get(i).flattenToShortString(); + if (approvedServices.contains(serviceToKeep)) { + newApprovedServices.add(serviceToKeep); + } + } + if (approvedServices.size() != newApprovedServices.size()) { SharedPreferences.Editor editor = mPreferences.edit(); - final int numApprovedServices = approvedServices.size(); - for (int i = 0; i < numApprovedServices; i++) { - if (approvedServices.valueAt(i) - .equals(serviceToRemove.flattenToShortString())) { - approvedServices.removeAt(i); - break; - } - } - - editor.putStringSet(APPROVED_SERVICES_PREFERENCE, approvedServices); + editor.putStringSet(APPROVED_SERVICES_PREFERENCE, newApprovedServices); editor.apply(); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java new file mode 100644 index 000000000000..58a477efac09 --- /dev/null +++ b/packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java @@ -0,0 +1,177 @@ +/* + * 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 + */ +package com.android.settingslib; + +import android.content.Context; +import android.content.Intent; +import android.os.UserHandle; +import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.AttributeSet; +import android.util.Log; +import android.util.Pair; +import android.util.Xml; +import android.view.InflateException; +import com.android.settingslib.drawer.Tile; +import com.android.settingslib.drawer.TileUtils; +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class SuggestionParser { + + private static final String TAG = "SuggestionParser"; + + private final Context mContext; + private final List<SuggestionCategory> mSuggestionList; + private final ArrayMap<Pair<String, String>, Tile> addCache = new ArrayMap<>(); + + public SuggestionParser(Context context, int orderXml) { + mContext = context; + mSuggestionList = (List<SuggestionCategory>) new SuggestionOrderInflater(mContext) + .parse(orderXml); + } + + public List<Tile> getSuggestions() { + List<Tile> suggestions = new ArrayList<>(); + final int N = mSuggestionList.size(); + for (int i = 0; i < N; i++) { + readSuggestions(mSuggestionList.get(i), suggestions); + } + return suggestions; + } + + private void readSuggestions(SuggestionCategory category, List<Tile> suggestions) { + int countBefore = suggestions.size(); + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.addCategory(category.category); + if (category.pkg != null) { + intent.setPackage(category.pkg); + } + TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent, + addCache, null, suggestions, true, false); + if (!category.multiple && suggestions.size() > (countBefore + 1)) { + // If there are too many, remove them all and only re-add the one with the highest + // priority. + Tile item = suggestions.remove(suggestions.size() - 1); + while (suggestions.size() > countBefore) { + Tile last = suggestions.remove(suggestions.size() - 1); + if (last.priority > item.priority) { + item = last; + } + } + suggestions.add(item); + } + } + + private static class SuggestionCategory { + public String category; + public String pkg; + public boolean multiple; + } + + private static class SuggestionOrderInflater { + private static final String TAG_LIST = "optional-steps"; + private static final String TAG_ITEM = "step"; + + private static final String ATTR_CATEGORY = "category"; + private static final String ATTR_PACKAGE = "package"; + private static final String ATTR_MULTIPLE = "multiple"; + + private final Context mContext; + + public SuggestionOrderInflater(Context context) { + mContext = context; + } + + public Object parse(int resource) { + XmlPullParser parser = mContext.getResources().getXml(resource); + final AttributeSet attrs = Xml.asAttributeSet(parser); + try { + // Look for the root node. + int type; + do { + type = parser.next(); + } while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT); + + if (type != XmlPullParser.START_TAG) { + throw new InflateException(parser.getPositionDescription() + + ": No start tag found!"); + } + + // Temp is the root that was found in the xml + Object xmlRoot = onCreateItem(parser.getName(), attrs); + + // Inflate all children under temp + rParse(parser, xmlRoot, attrs); + return xmlRoot; + } catch (XmlPullParserException | IOException e) { + Log.w(TAG, "Problem parser resource " + resource, e); + return null; + } + } + + /** + * Recursive method used to descend down the xml hierarchy and instantiate + * items, instantiate their children. + */ + private void rParse(XmlPullParser parser, Object parent, final AttributeSet attrs) + throws XmlPullParserException, IOException { + final int depth = parser.getDepth(); + + int type; + while (((type = parser.next()) != XmlPullParser.END_TAG || + parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + final String name = parser.getName(); + + Object item = onCreateItem(name, attrs); + onAddChildItem(parent, item); + rParse(parser, item, attrs); + } + } + + protected void onAddChildItem(Object parent, Object child) { + if (parent instanceof List<?> && child instanceof SuggestionCategory) { + ((List<SuggestionCategory>) parent).add((SuggestionCategory) child); + } else { + throw new IllegalArgumentException("Parent was not a list"); + } + } + + protected Object onCreateItem(String name, AttributeSet attrs) { + if (name.equals(TAG_LIST)) { + return new ArrayList<SuggestionCategory>(); + } else if (name.equals(TAG_ITEM)) { + SuggestionCategory category = new SuggestionCategory(); + category.category = attrs.getAttributeValue(null, ATTR_CATEGORY); + category.pkg = attrs.getAttributeValue(null, ATTR_PACKAGE); + String multiple = attrs.getAttributeValue(null, ATTR_MULTIPLE); + category.multiple = !TextUtils.isEmpty(multiple) && Boolean.parseBoolean(multiple); + return category; + } else { + throw new IllegalArgumentException("Unknown item " + name); + } + } + } +} + diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java index 344bf6228bf2..f6d9134c5e2b 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java @@ -38,7 +38,7 @@ public class AppUtils { String packageName = appEntry.info.packageName; boolean hasPreferred = hasPreferredActivities(pm, packageName) || hasUsbDefaults(usbManager, packageName); - int status = pm.getIntentVerificationStatus(packageName, UserHandle.myUserId()); + int status = pm.getIntentVerificationStatusAsUser(packageName, UserHandle.myUserId()); // consider a visible current link-handling state to be any explicitly designated behavior boolean hasDomainURLsPreference = status != PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index e6fe447c8d98..d353f31e59b1 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -316,7 +316,7 @@ public class ApplicationsState { synchronized (mEntriesMap) { AppEntry entry = mEntriesMap.get(userId).get(packageName); if (entry != null) { - mPm.getPackageSizeInfo(packageName, userId, mBackgroundHandler.mStatsObserver); + mPm.getPackageSizeInfoAsUser(packageName, userId, mBackgroundHandler.mStatsObserver); } if (DEBUG_LOCKING) Log.v(TAG, "...requestSize releasing lock"); } @@ -906,7 +906,7 @@ public class ApplicationsState { entry.sizeLoadStart = now; mCurComputingSizePkg = entry.info.packageName; mCurComputingSizeUserId = UserHandle.getUserId(entry.info.uid); - mPm.getPackageSizeInfo(mCurComputingSizePkg, + mPm.getPackageSizeInfoAsUser(mCurComputingSizePkg, mCurComputingSizeUserId, mStatsObserver); } if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_SIZES releasing: now computing"); diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java index 9790e6408cc2..3b818c851626 100644 --- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java +++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java @@ -422,7 +422,7 @@ public class StorageMeasurement { ActivityManager.getCurrentUser(), currentProfiles, finished, count); for (UserInfo user : users) { for (ApplicationInfo app : volumeApps) { - packageManager.getPackageSizeInfo(app.packageName, user.id, observer); + packageManager.getPackageSizeInfoAsUser(app.packageName, user.id, observer); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java index 0f322cf6912d..53be0e6c116c 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardCategory.java @@ -43,22 +43,22 @@ public class DashboardCategory implements Parcelable { /** * List of the category's children */ - public List<DashboardTile> tiles = new ArrayList<DashboardTile>(); + public List<Tile> tiles = new ArrayList<Tile>(); public DashboardCategory() { // Empty } - public void addTile(DashboardTile tile) { + public void addTile(Tile tile) { tiles.add(tile); } - public void addTile(int n, DashboardTile tile) { + public void addTile(int n, Tile tile) { tiles.add(n, tile); } - public void removeTile(DashboardTile tile) { + public void removeTile(Tile tile) { tiles.remove(tile); } @@ -70,7 +70,7 @@ public class DashboardCategory implements Parcelable { return tiles.size(); } - public DashboardTile getTile(int n) { + public Tile getTile(int n) { return tiles.get(n); } @@ -89,7 +89,7 @@ public class DashboardCategory implements Parcelable { dest.writeInt(count); for (int n = 0; n < count; n++) { - DashboardTile tile = tiles.get(n); + Tile tile = tiles.get(n); tile.writeToParcel(dest, flags); } } @@ -102,7 +102,7 @@ public class DashboardCategory implements Parcelable { final int count = in.readInt(); for (int n = 0; n < count; n++) { - DashboardTile tile = DashboardTile.CREATOR.createFromParcel(in); + Tile tile = Tile.CREATOR.createFromParcel(in); tiles.add(tile); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java b/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java index 793e877dba24..2fd043f64208 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/ProfileSelectDialog.java @@ -30,9 +30,9 @@ public class ProfileSelectDialog extends DialogFragment implements OnClickListen private static final String ARG_SELECTED_TILE = "selectedTile"; - private DashboardTile mSelectedTile; + private Tile mSelectedTile; - public static void show(FragmentManager manager, DashboardTile tile) { + public static void show(FragmentManager manager, Tile tile) { ProfileSelectDialog dialog = new ProfileSelectDialog(); Bundle args = new Bundle(); args.putParcelable(ARG_SELECTED_TILE, tile); diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java index 102e47ab1870..3fc0c22a264e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java @@ -49,7 +49,7 @@ public class SettingsDrawerActivity extends Activity { private static final String TAG = "SettingsDrawerActivity"; private static List<DashboardCategory> sDashboardCategories; - private static HashMap<Pair<String, String>, DashboardTile> sTileCache; + private static HashMap<Pair<String, String>, Tile> sTileCache; private final PackageReceiver mPackageReceiver = new PackageReceiver(); private final List<CategoryListener> mCategoryListeners = new ArrayList<>(); @@ -194,7 +194,7 @@ public class SettingsDrawerActivity extends Activity { } } - public boolean openTile(DashboardTile tile) { + public boolean openTile(Tile tile) { closeDrawer(); if (tile == null) { return false; @@ -211,7 +211,7 @@ public class SettingsDrawerActivity extends Activity { return true; } - protected void onTileClicked(DashboardTile tile) { + protected void onTileClicked(Tile tile) { if (openTile(tile)) { finish(); } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java index 24c6ae8356ab..72f1c566e54e 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java @@ -48,7 +48,7 @@ public class SettingsDrawerAdapter extends BaseAdapter { mItems.add(category); for (int j = 0; j < dashboardCategory.tiles.size(); j++) { Item tile = new Item(); - DashboardTile dashboardTile = dashboardCategory.tiles.get(j); + Tile dashboardTile = dashboardCategory.tiles.get(j); tile.label = dashboardTile.title; tile.icon = dashboardTile.icon; tile.tile = dashboardTile; @@ -58,7 +58,7 @@ public class SettingsDrawerAdapter extends BaseAdapter { notifyDataSetChanged(); } - public DashboardTile getTile(int position) { + public Tile getTile(int position) { return mItems.get(position).tile; } @@ -101,6 +101,6 @@ public class SettingsDrawerAdapter extends BaseAdapter { private static class Item { public Icon icon; public CharSequence label; - public DashboardTile tile; + public Tile tile; } } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java index 347e9f742d29..b16cd0817f5f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/DashboardTile.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/Tile.java @@ -29,7 +29,7 @@ import java.util.ArrayList; /** * Description of a single dashboard tile that the user can select. */ -public class DashboardTile implements Parcelable { +public class Tile implements Parcelable { /** * Title of the tile that is shown to the user. @@ -79,7 +79,7 @@ public class DashboardTile implements Parcelable { */ public Bundle metaData; - public DashboardTile() { + public Tile() { // Empty } @@ -134,16 +134,16 @@ public class DashboardTile implements Parcelable { metaData = in.readBundle(); } - DashboardTile(Parcel in) { + Tile(Parcel in) { readFromParcel(in); } - public static final Creator<DashboardTile> CREATOR = new Creator<DashboardTile>() { - public DashboardTile createFromParcel(Parcel source) { - return new DashboardTile(source); + public static final Creator<Tile> CREATOR = new Creator<Tile>() { + public Tile createFromParcel(Parcel source) { + return new Tile(source); } - public DashboardTile[] newArray(int size) { - return new DashboardTile[size]; + public Tile[] newArray(int size) { + return new Tile[size]; } }; } diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java index 6b366801e76a..2dfdfda7eaa3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java @@ -1,13 +1,18 @@ /* * 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 + * 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. + * 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.settingslib.drawer; import android.app.ActivityManager; @@ -108,9 +113,9 @@ public class TileUtils { private static final String SETTING_PKG = "com.android.settings"; public static List<DashboardCategory> getCategories(Context context, - HashMap<Pair<String, String>, DashboardTile> cache) { + HashMap<Pair<String, String>, Tile> cache) { final long startTime = System.currentTimeMillis(); - ArrayList<DashboardTile> tiles = new ArrayList<>(); + ArrayList<Tile> tiles = new ArrayList<>(); UserManager userManager = UserManager.get(context); for (UserHandle user : userManager.getUserProfiles()) { // TODO: Needs much optimization, too many PM queries going on here. @@ -125,7 +130,7 @@ public class TileUtils { getTilesForAction(context, user, EXTRA_SETTINGS_ACTION, cache, null, tiles, false); } HashMap<String, DashboardCategory> categoryMap = new HashMap<>(); - for (DashboardTile tile : tiles) { + for (Tile tile : tiles) { DashboardCategory category = categoryMap.get(tile.category); if (category == null) { category = createCategory(context, tile.category); @@ -170,30 +175,34 @@ public class TileUtils { } private static void getTilesForAction(Context context, - UserHandle user, String action, Map<Pair<String, String>, DashboardTile> addedCache, - String defaultCategory, ArrayList<DashboardTile> outTiles, boolean requireSettings) { - PackageManager pm = context.getPackageManager(); + UserHandle user, String action, Map<Pair<String, String>, Tile> addedCache, + String defaultCategory, ArrayList<Tile> outTiles, boolean requireSettings) { Intent intent = new Intent(action); + if (requireSettings) { + intent.setPackage(SETTING_PKG); + } + getTilesForIntent(context, user, intent, addedCache, defaultCategory, outTiles, + requireSettings, true); + } + + public static void getTilesForIntent(Context context, UserHandle user, Intent intent, + Map<Pair<String, String>, Tile> addedCache, String defaultCategory, List<Tile> outTiles, + boolean usePriority, boolean checkCategory) { + PackageManager pm = context.getPackageManager(); List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent, PackageManager.GET_META_DATA, user.getIdentifier()); for (ResolveInfo resolved : results) { - if (requireSettings) { - if (!SETTING_PKG.equals(resolved.activityInfo.applicationInfo.packageName)) { - continue; - } - } else { - if (!resolved.system) { - // Do not allow any app to add to settings, only system ones. - continue; - } + if (!resolved.system) { + // Do not allow any app to add to settings, only system ones. + continue; } ActivityInfo activityInfo = resolved.activityInfo; Bundle metaData = activityInfo.metaData; String categoryKey = defaultCategory; - if (((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY)) + if (checkCategory && ((metaData == null) || !metaData.containsKey(EXTRA_CATEGORY_KEY)) && categoryKey == null) { - Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for action " - + action + " missing metadata " + Log.w(LOG_TAG, "Found " + resolved.activityInfo.name + " for intent " + + intent + " missing metadata " + (metaData == null ? "" : EXTRA_CATEGORY_KEY)); continue; } else { @@ -201,13 +210,13 @@ public class TileUtils { } Pair<String, String> key = new Pair<String, String>(activityInfo.packageName, activityInfo.name); - DashboardTile tile = addedCache.get(key); + Tile tile = addedCache.get(key); if (tile == null) { - tile = new DashboardTile(); + tile = new Tile(); tile.intent = new Intent().setClassName( activityInfo.packageName, activityInfo.name); tile.category = categoryKey; - tile.priority = requireSettings ? resolved.priority : 0; + tile.priority = usePriority ? resolved.priority : 0; tile.metaData = activityInfo.metaData; updateTileData(context, tile, activityInfo, activityInfo.applicationInfo, pm); @@ -234,7 +243,7 @@ public class TileUtils { return null; } - private static boolean updateTileData(Context context, DashboardTile tile, + private static boolean updateTileData(Context context, Tile tile, ActivityInfo activityInfo, ApplicationInfo applicationInfo, PackageManager pm) { if (applicationInfo.isSystemApp()) { int icon = 0; @@ -252,10 +261,18 @@ public class TileUtils { icon = metaData.getInt(META_DATA_PREFERENCE_ICON); } if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) { - title = metaData.getString(META_DATA_PREFERENCE_TITLE); + if (metaData.get(META_DATA_PREFERENCE_TITLE) instanceof Integer) { + title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE)); + } else { + title = metaData.getString(META_DATA_PREFERENCE_TITLE); + } } if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) { - summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY); + if (metaData.get(META_DATA_PREFERENCE_SUMMARY) instanceof Integer) { + summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); + } else { + summary = metaData.getString(META_DATA_PREFERENCE_SUMMARY); + } } } } catch (PackageManager.NameNotFoundException | Resources.NotFoundException e) { @@ -285,10 +302,10 @@ public class TileUtils { return false; } - private static final Comparator<DashboardTile> TILE_COMPARATOR = - new Comparator<DashboardTile>() { + private static final Comparator<Tile> TILE_COMPARATOR = + new Comparator<Tile>() { @Override - public int compare(DashboardTile lhs, DashboardTile rhs) { + public int compare(Tile lhs, Tile rhs) { return rhs.priority - lhs.priority; } }; diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java index e12e3a571880..e5aeb3c3c374 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsHelper.java @@ -229,18 +229,25 @@ public class SettingsHelper { } private boolean isAlreadyConfiguredCriticalAccessibilitySetting(String name) { - // These are the critical accessibility settings that are required for a - // blind user to be able to interact with the device. If these settings are + // These are the critical accessibility settings that are required for users with + // accessibility needs to be able to interact with the device. If these settings are // already configured, we will not overwrite them. If they are already set, - // it means that the user has performed a global gesture to enable accessibility - // and definitely needs these features working after the restore. + // it means that the user has performed a global gesture to enable accessibility or set + // these settings in the Accessibility portion of the Setup Wizard, and definitely needs + // these features working after the restore. if (Settings.Secure.ACCESSIBILITY_ENABLED.equals(name) || Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION.equals(name) || Settings.Secure.ACCESSIBILITY_SPEAK_PASSWORD.equals(name) - || Settings.Secure.TOUCH_EXPLORATION_ENABLED.equals(name)) { + || Settings.Secure.TOUCH_EXPLORATION_ENABLED.equals(name) + || Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER_ENABLED.equals(name) + || Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED.equals(name) + || Settings.Secure.UI_NIGHT_MODE.equals(name)) { return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0; } else if (Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES.equals(name) - || Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(name)) { + || Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES.equals(name) + || Settings.Secure.ACCESSIBILITY_DISPLAY_COLOR_MATRIX.equals(name) + || Settings.Secure.ACCESSIBILITY_DISPLAY_DALTONIZER.equals(name) + || Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE.equals(name)) { return !TextUtils.isEmpty(Settings.Secure.getString( mContext.getContentResolver(), name)); } diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java index bcb459a174a0..57d495f6f936 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java @@ -1010,6 +1010,11 @@ public class SettingsProvider extends ContentProvider { break; default: + if (setting != null && setting.startsWith(Settings.Global.DATA_ROAMING)) { + if ("0".equals(value)) return false; + restriction = UserManager.DISALLOW_DATA_ROAMING; + break; + } return false; } diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index c6d9e98774d0..7416fb564e27 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -151,6 +151,14 @@ </intent-filter> </receiver> + <receiver + android:name=".RemoteBugreportReceiver" + android:permission="android.permission.DUMP"> + <intent-filter> + <action android:name="android.intent.action.REMOTE_BUGREPORT_FINISHED" /> + </intent-filter> + </receiver> + <service android:name=".BugreportProgressService" android:exported="false"/> diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java index d31088ce308c..5c807e1bd652 100644 --- a/packages/Shell/src/com/android/shell/BugreportProgressService.java +++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java @@ -21,6 +21,7 @@ import static com.android.shell.BugreportPrefs.STATE_SHOW; import static com.android.shell.BugreportPrefs.getWarningState; import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileDescriptor; import java.io.FileInputStream; @@ -28,10 +29,13 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; +import java.nio.charset.StandardCharsets; import java.text.NumberFormat; import java.util.ArrayList; +import java.util.Enumeration; import java.util.List; import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import libcore.io.Streams; @@ -112,6 +116,10 @@ public class BugreportProgressService extends Service { // External intents sent by dumpstate. static final String INTENT_BUGREPORT_STARTED = "android.intent.action.BUGREPORT_STARTED"; static final String INTENT_BUGREPORT_FINISHED = "android.intent.action.BUGREPORT_FINISHED"; + static final String INTENT_REMOTE_BUGREPORT_FINISHED = + "android.intent.action.REMOTE_BUGREPORT_FINISHED"; + static final String INTENT_REMOTE_BUGREPORT_DISPATCH = + "android.intent.action.REMOTE_BUGREPORT_DISPATCH"; // Internal intents used on notification actions. static final String INTENT_BUGREPORT_CANCEL = "android.intent.action.BUGREPORT_CANCEL"; @@ -449,6 +457,11 @@ public class BugreportProgressService extends Service { .addAction(cancelAction) .build(); + if (info.finished) { + Log.w(TAG, "Not sending progress notification because bugreport has finished already (" + + info + ")"); + return; + } NotificationManager.from(mContext).notify(TAG, info.pid, notification); } @@ -628,7 +641,12 @@ public class BugreportProgressService extends Service { synchronized (BugreportProgressService.this) { mTakingScreenshot = flag; for (int i = 0; i < mProcesses.size(); i++) { - updateProgress(mProcesses.valueAt(i)); + final BugreportInfo info = mProcesses.valueAt(i); + if (info.finished) { + Log.d(TAG, "Not updating progress because share notification was already sent"); + continue; + } + updateProgress(info); } } } @@ -803,6 +821,9 @@ public class BugreportProgressService extends Service { Log.e(TAG, "INTERNAL ERROR: no info for PID " + pid + ": " + mProcesses); return; } + + addDetailsToZipFile(info); + final Intent sendIntent = buildSendIntent(mContext, info); final Intent notifIntent; @@ -858,7 +879,7 @@ public class BugreportProgressService extends Service { new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { - info.bugreportFile = zipBugreport(info.bugreportFile); + zipBugreport(info); sendBugreportNotification(context, info); return null; } @@ -869,35 +890,92 @@ public class BugreportProgressService extends Service { * Zips a bugreport file, returning the path to the new file (or to the * original in case of failure). */ - private static File zipBugreport(File bugreportFile) { - String bugreportPath = bugreportFile.getAbsolutePath(); - String zippedPath = bugreportPath.replace(".txt", ".zip"); + private static void zipBugreport(BugreportInfo info) { + final String bugreportPath = info.bugreportFile.getAbsolutePath(); + final String zippedPath = bugreportPath.replace(".txt", ".zip"); Log.v(TAG, "zipping " + bugreportPath + " as " + zippedPath); - File bugreportZippedFile = new File(zippedPath); - try (InputStream is = new FileInputStream(bugreportFile); + final File bugreportZippedFile = new File(zippedPath); + try (InputStream is = new FileInputStream(info.bugreportFile); ZipOutputStream zos = new ZipOutputStream( new BufferedOutputStream(new FileOutputStream(bugreportZippedFile)))) { - ZipEntry entry = new ZipEntry(bugreportFile.getName()); - entry.setTime(bugreportFile.lastModified()); - zos.putNextEntry(entry); - int totalBytes = Streams.copy(is, zos); - Log.v(TAG, "size of original bugreport: " + totalBytes + " bytes"); - zos.closeEntry(); - // Delete old file; - boolean deleted = bugreportFile.delete(); + addEntry(zos, info.bugreportFile.getName(), is); + // Delete old file + final boolean deleted = info.bugreportFile.delete(); if (deleted) { Log.v(TAG, "deleted original bugreport (" + bugreportPath + ")"); } else { Log.e(TAG, "could not delete original bugreport (" + bugreportPath + ")"); } - return bugreportZippedFile; + info.bugreportFile = bugreportZippedFile; } catch (IOException e) { Log.e(TAG, "exception zipping file " + zippedPath, e); - return bugreportFile; // Return original. } } /** + * Adds the user-provided info into the bugreport zip file. + * <p> + * If user provided a title, it will be saved into a {@code title.txt} entry; similarly, the + * description will be saved on {@code description.txt}. + */ + private void addDetailsToZipFile(BugreportInfo info) { + // It's not possible to add a new entry into an existing file, so we need to create a new + // zip, copy all entries, then rename it. + final File dir = info.bugreportFile.getParentFile(); + final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName()); + Log.d(TAG, "Writing temporary zip file (" + tmpZip + ")"); + try (ZipFile oldZip = new ZipFile(info.bugreportFile); + ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(tmpZip))) { + + // First copy contents from original zip. + Enumeration<? extends ZipEntry> entries = oldZip.entries(); + while (entries.hasMoreElements()) { + final ZipEntry entry = entries.nextElement(); + final String entryName = entry.getName(); + if (!entry.isDirectory()) { + addEntry(zos, entryName, entry.getTime(), oldZip.getInputStream(entry)); + } else { + Log.w(TAG, "skipping directory entry: " + entryName); + } + } + + // Then add the user-provided info. + addEntry(zos, "title.txt", info.title); + addEntry(zos, "description.txt", info.description); + } catch (IOException e) { + Log.e(TAG, "exception zipping file " + tmpZip, e); + return; + } + + if (!tmpZip.renameTo(info.bugreportFile)) { + Log.e(TAG, "Could not rename " + tmpZip + " to " + info.bugreportFile); + } + } + + private static void addEntry(ZipOutputStream zos, String entry, String text) + throws IOException { + if (DEBUG) Log.v(TAG, "adding entry '" + entry + "': " + text); + if (!TextUtils.isEmpty(text)) { + addEntry(zos, entry, new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8))); + } + } + + private static void addEntry(ZipOutputStream zos, String entryName, InputStream is) + throws IOException { + addEntry(zos, entryName, System.currentTimeMillis(), is); + } + + private static void addEntry(ZipOutputStream zos, String entryName, long timestamp, + InputStream is) throws IOException { + final ZipEntry entry = new ZipEntry(entryName); + entry.setTime(timestamp); + zos.putNextEntry(entry); + final int totalBytes = Streams.copy(is, zos); + if (DEBUG) Log.v(TAG, "size of '" + entryName + "' entry: " + totalBytes + " bytes"); + zos.closeEntry(); + } + + /** * Find the best matching {@link Account} based on build properties. */ private static Account findSendToAccount(Context context) { @@ -931,7 +1009,7 @@ public class BugreportProgressService extends Service { return foundAccount; } - private static Uri getUri(Context context, File file) { + static Uri getUri(Context context, File file) { return file != null ? FileProvider.getUriForFile(context, AUTHORITY, file) : null; } diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java index b818343b6ce0..c8898b97d878 100644 --- a/packages/Shell/src/com/android/shell/BugreportReceiver.java +++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java @@ -52,7 +52,7 @@ public class BugreportReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // Clean up older bugreports in background - cleanupOldFiles(intent); + cleanupOldFiles(this, intent, INTENT_BUGREPORT_FINISHED, MIN_KEEP_COUNT, MIN_KEEP_AGE); // Delegate intent handling to service. Intent serviceIntent = new Intent(context, BugreportProgressService.class); @@ -60,8 +60,9 @@ public class BugreportReceiver extends BroadcastReceiver { context.startService(serviceIntent); } - private void cleanupOldFiles(Intent intent) { - if (!INTENT_BUGREPORT_FINISHED.equals(intent.getAction())) { + static void cleanupOldFiles(BroadcastReceiver br, Intent intent, String expectedAction, + final int minCount, final long minAge) { + if (!expectedAction.equals(intent.getAction())) { return; } final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT); @@ -69,12 +70,11 @@ public class BugreportReceiver extends BroadcastReceiver { Log.e(TAG, "Not deleting old files because file " + bugreportFile + " doesn't exist"); return; } - final PendingResult result = goAsync(); + final PendingResult result = br.goAsync(); new AsyncTask<Void, Void, Void>() { @Override protected Void doInBackground(Void... params) { - FileUtils.deleteOlderFiles( - bugreportFile.getParentFile(), MIN_KEEP_COUNT, MIN_KEEP_AGE); + FileUtils.deleteOlderFiles(bugreportFile.getParentFile(), minCount, minAge); result.finish(); return null; } diff --git a/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java new file mode 100644 index 000000000000..6f783a1fbabf --- /dev/null +++ b/packages/Shell/src/com/android/shell/RemoteBugreportReceiver.java @@ -0,0 +1,63 @@ +/* + * 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.shell; + +import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT; +import static com.android.shell.BugreportProgressService.INTENT_REMOTE_BUGREPORT_FINISHED; +import static com.android.shell.BugreportProgressService.INTENT_REMOTE_BUGREPORT_DISPATCH; +import static com.android.shell.BugreportProgressService.getFileExtra; +import static com.android.shell.BugreportProgressService.getUri; +import static com.android.shell.BugreportReceiver.cleanupOldFiles; + +import java.io.File; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.os.UserHandle; + +/** + * Receiver that handles finished remote bugreports, by re-sending + * the intent with appended bugreport zip file URI. + * + * <p> Remote bugreport never contains a screenshot. + */ +public class RemoteBugreportReceiver extends BroadcastReceiver { + + private static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport"; + private static final String EXTRA_REMOTE_BUGREPORT_HASH = + "android.intent.extra.REMOTE_BUGREPORT_HASH"; + + /** Always keep just the last remote bugreport zip file */ + private static final int MIN_KEEP_COUNT = 1; + + @Override + public void onReceive(Context context, Intent intent) { + cleanupOldFiles(this, intent, INTENT_REMOTE_BUGREPORT_FINISHED, MIN_KEEP_COUNT, 0); + + final File bugreportFile = getFileExtra(intent, EXTRA_BUGREPORT); + final Uri bugreportUri = getUri(context, bugreportFile); + final String bugreportHash = intent.getStringExtra(EXTRA_REMOTE_BUGREPORT_HASH); + + final Intent newIntent = new Intent(INTENT_REMOTE_BUGREPORT_DISPATCH); + newIntent.setDataAndType(bugreportUri, BUGREPORT_MIMETYPE); + newIntent.putExtra(EXTRA_REMOTE_BUGREPORT_HASH, bugreportHash); + context.sendBroadcastAsUser(newIntent, UserHandle.SYSTEM, + android.Manifest.permission.DUMP); + } +} diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java index 6bee767e4706..d1a07ea21fc4 100644 --- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java +++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java @@ -60,6 +60,7 @@ import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.test.InstrumentationTestCase; import android.test.suitebuilder.annotation.LargeTest; +import android.text.TextUtils; import android.text.format.DateUtils; import android.util.Log; @@ -103,6 +104,12 @@ public class BugreportReceiverTest extends InstrumentationTestCase { private static final String NAME = "BUG, Y U NO REPORT?"; private static final String NEW_NAME = "Bug_Forrest_Bug"; private static final String TITLE = "Wimbugdom Champion 2015"; + + private static final String NO_DESCRIPTION = null; + private static final String NO_NAME = null; + private static final String NO_SCREENSHOT = null; + private static final String NO_TITLE = null; + private String mDescription; private String mPlainTextPath; @@ -142,6 +149,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { public void testProgress() throws Exception { resetProperties(); sendBugreportStarted(1000); + waitForScreenshotButtonEnabled(true); assertProgressNotification(NAME, "0.00%"); @@ -156,8 +164,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE, - null, 1); + assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, ZIP_FILE, + NAME, NO_TITLE, NO_DESCRIPTION, 1, true); assertServiceNotRunning(); } @@ -173,15 +181,17 @@ public class BugreportReceiverTest extends InstrumentationTestCase { Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE, - null, 2); + assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, ZIP_FILE, + NAME, NO_TITLE, NO_DESCRIPTION, 2, true); assertServiceNotRunning(); } - public void testProgress_changeDetails() throws Exception { + public void testProgress_changeDetailsInvalidInput() throws Exception { + resetProperties(); sendBugreportStarted(1000); + waitForScreenshotButtonEnabled(true); DetailsUi detailsUi = new DetailsUi(mUiBot); @@ -217,15 +227,73 @@ public class BugreportReceiverTest extends InstrumentationTestCase { Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath); - assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NEW_NAME, TITLE, - mDescription, 1); + assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE, + NEW_NAME, TITLE, mDescription, 1, true); assertServiceNotRunning(); } + public void testProgress_changeDetailsPlainBugreport() throws Exception { + changeDetailsTest(true); + } + + public void testProgress_changeDetailsZippedBugreport() throws Exception { + changeDetailsTest(false); + } + + public void changeDetailsTest(boolean plainText) throws Exception { + + resetProperties(); + sendBugreportStarted(1000); + waitForScreenshotButtonEnabled(true); + + DetailsUi detailsUi = new DetailsUi(mUiBot); + + // Check initial name. + String actualName = detailsUi.nameField.getText().toString(); + assertEquals("Wrong value on field 'name'", NAME, actualName); + + // Change fields. + detailsUi.reOpen(); + detailsUi.nameField.setText(NEW_NAME); + detailsUi.titleField.setText(TITLE); + detailsUi.descField.setText(mDescription); + + detailsUi.clickOk(); + + assertPropertyValue(NAME_PROPERTY, NEW_NAME); + assertProgressNotification(NEW_NAME, "0.00%"); + + Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, + plainText? mPlainTextPath : mZipPath, mScreenshotPath); + assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE, + NEW_NAME, TITLE, mDescription, 1, true); + + assertServiceNotRunning(); + } + + /** + * Tests the scenario where the initial screenshot and dumpstate are finished while the user + * is changing the info in the details screen. + */ + public void testProgress_bugreportAndScreenshotFinishedWhileChangingDetails() throws Exception { + bugreportFinishedWhileChangingDetailsTest(false); + } + + /** + * Tests the scenario where dumpstate is finished while the user is changing the info in the + * details screen, but the initial screenshot finishes afterwards. + */ public void testProgress_bugreportFinishedWhileChangingDetails() throws Exception { + bugreportFinishedWhileChangingDetailsTest(true); + } + + private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception { resetProperties(); sendBugreportStarted(1000); + if (waitScreenshot) { + waitForScreenshotButtonEnabled(true); + } DetailsUi detailsUi = new DetailsUi(mUiBot); @@ -233,7 +301,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { detailsUi.nameField.setText(NEW_NAME); sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath); - // Wait until the share notifcation is received... + // Wait until the share notification is received... mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title)); // ...then close notification bar. mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); @@ -249,8 +317,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { // Finally, share bugreport. Bundle extras = acceptBugreportAndGetSharedIntent(); - assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, TITLE, - mDescription, 1); + assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, TITLE, + NAME, TITLE, mDescription, 1, waitScreenshot); assertServiceNotRunning(); } @@ -275,7 +343,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { // Share the bugreport. mUiBot.chooseActivity(UI_NAME); Bundle extras = mListener.getExtras(); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, null); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT); // Make sure it's hidden now. int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN); @@ -293,13 +361,13 @@ public class BugreportReceiverTest extends InstrumentationTestCase { } public void testBugreportFinished_plainBugreportAndNoScreenshot() throws Exception { - Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, null); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, null); + Bundle extras = sendBugreportFinishedAndGetSharedIntent(mPlainTextPath, NO_SCREENSHOT); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT); } public void testBugreportFinished_zippedBugreportAndNoScreenshot() throws Exception { - Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, null); - assertActionSendMultiple(extras, BUGREPORT_CONTENT, null); + Bundle extras = sendBugreportFinishedAndGetSharedIntent(mZipPath, NO_SCREENSHOT); + assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT); } private void cancelExistingNotifications() { @@ -405,8 +473,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase { */ private void assertActionSendMultiple(Bundle extras, String bugreportContent, String screenshotContent) throws IOException { - assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, null, ZIP_FILE, - null, 0); + assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, ZIP_FILE, + NO_NAME, NO_TITLE, NO_DESCRIPTION, 0, false); } /** @@ -416,14 +484,17 @@ public class BugreportReceiverTest extends InstrumentationTestCase { * @param bugreportContent expected content in the bugreport file * @param screenshotContent expected content in the screenshot file (sent by dumpstate), if any * @param pid emulated dumpstate pid - * @param name bugreport name as provided by the user - * @param title bugreport name as provided by the user (or received by dumpstate) + * @param name expected subject + * @param name bugreport name as provided by the user (or received by dumpstate) + * @param title bugreport name as provided by the user * @param description bugreport description as provided by the user * @param numberScreenshots expected number of screenshots taken by Shell. + * @param renamedScreenshots whether the screenshots are expected to be renamed */ private void assertActionSendMultiple(Bundle extras, String bugreportContent, - String screenshotContent, int pid, String name, String title, String description, - int numberScreenshots) throws IOException { + String screenshotContent, int pid, String subject, + String name, String title, String description, + int numberScreenshots, boolean renamedScreenshots) throws IOException { String body = extras.getString(Intent.EXTRA_TEXT); assertContainsRegex("missing build info", SystemProperties.get("ro.build.description"), body); @@ -433,7 +504,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { assertContainsRegex("missing description", description, body); } - assertEquals("wrong subject", title, extras.getString(Intent.EXTRA_SUBJECT)); + assertEquals("wrong subject", subject, extras.getString(Intent.EXTRA_SUBJECT)); List<Uri> attachments = extras.getParcelableArrayList(Intent.EXTRA_STREAM); int expectedNumberScreenshots = numberScreenshots; @@ -456,6 +527,12 @@ public class BugreportReceiverTest extends InstrumentationTestCase { } assertNotNull("did not get .zip attachment", zipUri); assertZipContent(zipUri, BUGREPORT_FILE, BUGREPORT_CONTENT); + if (!TextUtils.isEmpty(title)) { + assertZipContent(zipUri, "title.txt", title); + } + if (!TextUtils.isEmpty(description)) { + assertZipContent(zipUri, "description.txt", description); + } // URI of the screenshot taken by dumpstate. Uri externalScreenshotUri = null; @@ -480,7 +557,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { // Check internal screenshots. SortedSet<String> expectedNames = new TreeSet<>(); for (int i = 1 ; i <= numberScreenshots; i++) { - String prefix = name != null ? name : Integer.toString(pid); + String prefix = renamedScreenshots ? name : Integer.toString(pid); String expectedName = "screenshot-" + prefix + "-" + i + ".png"; expectedNames.add(expectedName); } @@ -592,7 +669,7 @@ public class BugreportReceiverTest extends InstrumentationTestCase { private UiObject waitForScreenshotButtonEnabled(boolean expectedEnabled) throws Exception { UiObject screenshotButton = getScreenshotButton(); - int maxAttempts = SCREENSHOT_DELAY_SECONDS + 2; + int maxAttempts = SCREENSHOT_DELAY_SECONDS + 5; int i = 0; do { boolean enabled = screenshotButton.isEnabled(); diff --git a/packages/SystemUI/proguard.flags b/packages/SystemUI/proguard.flags index 6a10c2c62508..bc182215c0d4 100644 --- a/packages/SystemUI/proguard.flags +++ b/packages/SystemUI/proguard.flags @@ -10,6 +10,7 @@ public void setGlowScale(float); } +-keep class com.android.systemui.statusbar.car.CarStatusBar -keep class com.android.systemui.statusbar.phone.PhoneStatusBar -keep class com.android.systemui.statusbar.tv.TvStatusBar diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..6242084ea175 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png Binary files differnew file mode 100644 index 000000000000..1b37a47338aa --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_carmode.png diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png Binary files differnew file mode 100644 index 000000000000..9e0575883a06 --- /dev/null +++ b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_carmode.png diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..2fcfdde08164 --- /dev/null +++ b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..48708a5099a8 --- /dev/null +++ b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..3d731840a93f --- /dev/null +++ b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..786935d5d185 --- /dev/null +++ b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..e4bd4bc3e39d --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png Binary files differnew file mode 100644 index 000000000000..94ccf7912e8f --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_carmode.png diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png Binary files differnew file mode 100644 index 000000000000..980bbbcb4ceb --- /dev/null +++ b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_carmode.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..201be3b3c8b5 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png Binary files differnew file mode 100644 index 000000000000..2770d6264da0 --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_carmode.png diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png Binary files differnew file mode 100644 index 000000000000..8ac64937007b --- /dev/null +++ b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_carmode.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..8e3678b292b8 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png Binary files differnew file mode 100644 index 000000000000..6c7cb0582733 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_carmode.png diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png Binary files differnew file mode 100644 index 000000000000..ea2b108e1e4c --- /dev/null +++ b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_carmode.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png Binary files differnew file mode 100644 index 000000000000..3e11023ef7e1 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_carmode.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png Binary files differnew file mode 100644 index 000000000000..fe8213d6390e --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_carmode.png diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png Binary files differnew file mode 100644 index 000000000000..c117efd1e654 --- /dev/null +++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_carmode.png diff --git a/packages/SystemUI/res/layout/car_navigation_bar.xml b/packages/SystemUI/res/layout/car_navigation_bar.xml new file mode 100644 index 000000000000..f7f673db6197 --- /dev/null +++ b/packages/SystemUI/res/layout/car_navigation_bar.xml @@ -0,0 +1,51 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 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.systemui.statusbar.car.CarNavigationBarView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_height="match_parent" + android:layout_width="match_parent" + android:background="@drawable/system_bar_background"> + + <!-- phone.NavigationBarView has rot0 and rot90 but we expect the car head unit to have a fixed + rotation so skip this level of the heirarchy. + --> + <LinearLayout + android:layout_height="match_parent" + android:layout_width="match_parent" + android:orientation="horizontal" + android:clipChildren="false" + android:clipToPadding="false" + android:id="@+id/nav_buttons" + android:animateLayoutChanges="true"> + + <!-- Buttons get populated here from a car_arrays.xml. --> + </LinearLayout> + + <!-- lights out layout to match exactly --> + <LinearLayout + android:layout_height="match_parent" + android:layout_width="match_parent" + android:orientation="horizontal" + android:id="@+id/lights_out" + android:visibility="gone"> + <!-- Must match nav_buttons. --> + </LinearLayout> + +</com.android.systemui.statusbar.car.CarNavigationBarView> diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml new file mode 100644 index 000000000000..460433ea1c21 --- /dev/null +++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ 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 + --> +<RelativeLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/keyboard_shortcuts_wrapper" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout_marginTop="40dp" + android:focusable="true"> +</RelativeLayout> diff --git a/packages/SystemUI/res/values/arrays_car.xml b/packages/SystemUI/res/values/arrays_car.xml new file mode 100644 index 000000000000..230479d2c9db --- /dev/null +++ b/packages/SystemUI/res/values/arrays_car.xml @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +** +** Copyright 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. +*/ +--> +<resources> + <!-- These should be overriden in an overlay. The default implementation is empty. + There needs to be correspondence per index between these arrays, which means that if there + isn't a longpress action associated with a shortcut item, put in an empty item to make + sure everything lines up. + --> + <array name="car_shortcut_icons" /> + <array name="car_shortcut_intent_uris" /> + <array name="car_shortcut_longpress_intent_uris" /> +</resources> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index 40e8b5055591..955af823a44f 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -172,7 +172,7 @@ <integer name="recents_nav_bar_scrim_enter_duration">400</integer> <!-- The animation duration for animating the removal of a task view. --> - <integer name="recents_animate_task_view_remove_duration">250</integer> + <integer name="recents_animate_task_view_remove_duration">175</integer> <!-- The animation duration for scrolling the stack to a particular item. --> <integer name="recents_animate_task_stack_scroll_duration">200</integer> diff --git a/packages/SystemUI/res/values/internal.xml b/packages/SystemUI/res/values/internal.xml index 67685ee09c08..e0d3cd23565f 100644 --- a/packages/SystemUI/res/values/internal.xml +++ b/packages/SystemUI/res/values/internal.xml @@ -17,6 +17,7 @@ <resources> <dimen name="status_bar_height">@*android:dimen/status_bar_height</dimen> <dimen name="navigation_bar_height">@*android:dimen/navigation_bar_height</dimen> + <dimen name="navigation_bar_height_car_mode">@*android:dimen/navigation_bar_height_car_mode</dimen> <color name="screen_pinning_primary_text">@*android:color/primary_text_default_material_light</color> </resources> diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml index f02f763062c4..90cd3949bfcc 100644 --- a/packages/SystemUI/res/xml/tuner_prefs.xml +++ b/packages/SystemUI/res/xml/tuner_prefs.xml @@ -80,7 +80,7 @@ android:summary="@string/overview_initial_state_paging_desc" /> <com.android.systemui.tuner.TunerSwitch - android:key="overview_fast_toggle" + android:key="overview_fast_toggle_via_button" android:title="@string/overview_fast_toggle_via_button" android:summary="@string/overview_fast_toggle_via_button_desc" /> diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java index 1a36abd3f1c3..b6776bba0aff 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java @@ -28,6 +28,7 @@ import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import com.android.systemui.qs.QSTile.State; +import com.android.systemui.qs.external.TileServices; import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.BluetoothController; import com.android.systemui.statusbar.policy.CastController; @@ -349,8 +350,10 @@ public abstract class QSTile<TState extends State> implements Listenable { UserSwitcherController getUserSwitcherController(); UserInfoController getUserInfoController(); BatteryController getBatteryController(); + TileServices getTileServices(); void removeTile(String tileSpec); + public interface Callback { void onTilesChanged(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java index bda46756e1aa..5fa38c6e0304 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java @@ -49,6 +49,11 @@ public class QuickQSPanel extends QSPanel { mQsContainer.addView((View) mTileLayout, 1 /* Between brightness and footer */); } + @Override + protected void createCustomizePanel() { + // No customizing from the header. + } + public void setQSPanelAndHeader(QSPanel fullPanel, View header) { mFullPanel = fullPanel; mHeader = header; diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java index 5ac63bc6b189..7448493b4880 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java @@ -16,32 +16,28 @@ package com.android.systemui.qs.customize; import android.app.ActivityManager; -import android.app.Service; import android.content.ClipData; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.ServiceConnection; -import android.os.IBinder; +import android.os.Handler; import android.os.UserHandle; import android.provider.Settings.Secure; -import android.service.quicksettings.IQSTileService; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.view.LayoutInflater; import android.view.View; - import com.android.systemui.R; import com.android.systemui.qs.QSPanel; import com.android.systemui.qs.QSTile; -import com.android.systemui.qs.external.QSTileServiceWrapper; import com.android.systemui.qs.external.CustomTile; +import com.android.systemui.qs.external.TileLifecycleManager; import com.android.systemui.statusbar.phone.QSTileHost; import com.android.systemui.tuner.TunerService; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; /** @@ -52,8 +48,9 @@ import java.util.List; public class CustomQSPanel extends QSPanel { private static final String TAG = "CustomQSPanel"; + private static final boolean DEBUG = false; - private List<String> mSavedTiles; + private List<String> mSavedTiles = Collections.emptyList(); private ArrayList<String> mStash; private List<String> mTiles = new ArrayList<>(); @@ -67,17 +64,25 @@ public class CustomQSPanel extends QSPanel { ((NonPagedTileLayout) mTileLayout).setCustomQsPanel(this); removeView(mFooter.getView()); + if (DEBUG) Log.d(TAG, "new CustomQSPanel", new Throwable()); TunerService.get(mContext).addTunable(this, QSTileHost.TILES_SETTING); } @Override + protected void onDetachedFromWindow() { + // Don't allow the super to unregister the tunable. + } + + @Override public void onTuningChanged(String key, String newValue) { if (key.equals(QS_SHOW_BRIGHTNESS)) { // No Brightness for you. super.onTuningChanged(key, "0"); } if (QSTileHost.TILES_SETTING.equals(key)) { - mSavedTiles = QSTileHost.loadTileSpecs(mContext, newValue); + mSavedTiles = Collections.unmodifiableList( + QSTileHost.loadTileSpecs(mContext, newValue)); + if (DEBUG) Log.d(TAG, "New saved tiles " + TextUtils.join(",", mSavedTiles)); } } @@ -106,6 +111,7 @@ public class CustomQSPanel extends QSPanel { } public void setSavedTiles() { + if (DEBUG) Log.d(TAG, "setSavedTiles " + TextUtils.join(",", mSavedTiles)); setTiles(mSavedTiles); } @@ -114,47 +120,26 @@ public class CustomQSPanel extends QSPanel { String tileSpec = mSavedTiles.get(i); if (!tileSpec.startsWith(CustomTile.PREFIX)) continue; if (!mTiles.contains(tileSpec)) { - mContext.bindServiceAsUser( - new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)), - new ServiceConnection() { - @Override - public void onServiceDisconnected(ComponentName name) { - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - QSTileServiceWrapper wrapper = new QSTileServiceWrapper( - IQSTileService.Stub.asInterface(service)); - wrapper.onStopListening(); - wrapper.onTileRemoved(); - mContext.unbindService(this); - } - }, Service.BIND_AUTO_CREATE, - new UserHandle(ActivityManager.getCurrentUser())); + Intent intent = new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)); + TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(), + mContext, intent, new UserHandle(ActivityManager.getCurrentUser())); + lifecycleManager.onStopListening(); + lifecycleManager.onTileRemoved(); + lifecycleManager.flushMessagesAndUnbind(); } } for (int i = 0; i < mTiles.size(); i++) { String tileSpec = mTiles.get(i); if (!tileSpec.startsWith(CustomTile.PREFIX)) continue; if (!mSavedTiles.contains(tileSpec)) { - mContext.bindServiceAsUser( - new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)), - new ServiceConnection() { - @Override - public void onServiceDisconnected(ComponentName name) { - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - QSTileServiceWrapper wrapper = new QSTileServiceWrapper( - IQSTileService.Stub.asInterface(service)); - wrapper.onTileAdded(); - mContext.unbindService(this); - } - }, Service.BIND_AUTO_CREATE, - new UserHandle(ActivityManager.getCurrentUser())); + Intent intent = new Intent().setComponent(CustomTile.getComponentFromSpec(tileSpec)); + TileLifecycleManager lifecycleManager = new TileLifecycleManager(new Handler(), + mContext, intent, new UserHandle(ActivityManager.getCurrentUser())); + lifecycleManager.onTileAdded(); + lifecycleManager.flushMessagesAndUnbind(); } } + if (DEBUG) Log.d(TAG, "saveCurrentTiles " + mTiles); Secure.putStringForUser(getContext().getContentResolver(), QSTileHost.TILES_SETTING, TextUtils.join(",", mTiles), ActivityManager.getCurrentUser()); } @@ -173,30 +158,37 @@ public class CustomQSPanel extends QSPanel { } private void setTilesInternal() { + if (DEBUG) Log.d(TAG, "Set tiles internal"); for (int i = 0; i < mCurrentTiles.size(); i++) { mCurrentTiles.get(i).destroy(); } mCurrentTiles.clear(); for (int i = 0; i < mTiles.size(); i++) { if (mTiles.get(i).startsWith(CustomTile.PREFIX)) { - mCurrentTiles.add(BlankCustomTile.create(mHost, mTiles.get(i))); + QSTile<?> tile = BlankCustomTile.create(mHost, mTiles.get(i)); + tile.setTileSpec(mTiles.get(i)); + mCurrentTiles.add(tile); } else { QSTile<?> tile = mHost.createTile(mTiles.get(i)); if (tile != null) { + tile.setTileSpec(mTiles.get(i)); mCurrentTiles.add(tile); + } else { + if (DEBUG) Log.d(TAG, "Skipping " + mTiles.get(i)); } } - mCurrentTiles.get(mCurrentTiles.size() - 1).setTileSpec(mTiles.get(i)); } super.setTiles(mCurrentTiles); } public void addTile(String spec) { + if (DEBUG) Log.d(TAG, "addTile " + spec); mTiles.add(spec); setTilesInternal(); } public void moveTo(String from, String to) { + if (DEBUG) Log.d(TAG, "moveTo " + from + " " + to); int fromIndex = mTiles.indexOf(from); if (fromIndex < 0) { Log.e(TAG, "Unknown from tile " + from); @@ -220,6 +212,7 @@ public class CustomQSPanel extends QSPanel { } public void setTiles(List<String> tiles) { + if (DEBUG) Log.d(TAG, "Set tiles " + TextUtils.join(",", tiles)); mTiles = new ArrayList<>(tiles); setTilesInternal(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java index 2e5a0b277552..eefff30910a6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java @@ -132,6 +132,7 @@ public class CustomTile extends QSTile<QSTile.State> { } catch (RemoteException e) { } } + mHost.getTileServices().freeService(this, mServiceManager); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java index 41fce9f1fb98..8c5e87e1a0f6 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java @@ -76,6 +76,7 @@ public class TileLifecycleManager extends BroadcastReceiver implements @VisibleForTesting boolean mReceiverRegistered; private IQSService mService; + private boolean mUnbindImmediate; public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) { mContext = context; @@ -94,6 +95,14 @@ public class TileLifecycleManager extends BroadcastReceiver implements } } + /** + * Binds just long enough to send any queued messages, then unbinds. + */ + public void flushMessagesAndUnbind() { + mUnbindImmediate = true; + setBindService(true); + } + public void setBindService(boolean bind) { mBound = bind; if (bind) { @@ -173,6 +182,10 @@ public class TileLifecycleManager extends BroadcastReceiver implements } onTileRemoved(); } + if (mUnbindImmediate) { + mUnbindImmediate = false; + setBindService(false); + } } public void handleDestroy() { diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java index 00f76990c1e8..a831c87b9d86 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java +++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java @@ -20,17 +20,22 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.graphics.drawable.Icon; import android.os.Binder; import android.os.Handler; import android.os.Looper; import android.os.RemoteException; +import android.os.UserHandle; import android.service.quicksettings.IQSService; import android.service.quicksettings.Tile; import android.service.quicksettings.TileService; import android.util.ArrayMap; import android.util.Log; +import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.statusbar.phone.QSTileHost; +import com.android.systemui.statusbar.phone.StatusBarIconController; import java.util.ArrayList; import java.util.Collections; @@ -47,6 +52,7 @@ public class TileServices extends IQSService.Stub { private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>(); private final Context mContext; private final Handler mHandler; + private final Handler mMainHandler; private final QSTileHost mHost; private int mMaxBound = DEFAULT_MAX_BOUND; @@ -57,6 +63,7 @@ public class TileServices extends IQSService.Stub { mContext.registerReceiver(mRequestListeningReceiver, new IntentFilter(TileService.ACTION_REQUEST_LISTENING)); mHandler = new Handler(looper); + mMainHandler = new Handler(Looper.getMainLooper()); } public Context getContext() { @@ -82,6 +89,13 @@ public class TileServices extends IQSService.Stub { service.setBindAllowed(false); mServices.remove(tile); mTiles.remove(tile.getComponent()); + final String slot = tile.getComponent().getClassName(); + mMainHandler.post(new Runnable() { + @Override + public void run() { + mHost.getIconController().removeIcon(slot); + } + }); } } @@ -119,7 +133,7 @@ public class TileServices extends IQSService.Stub { private void verifyCaller(String packageName) { try { - int uid = mContext.getPackageManager().getPackageUid(packageName, + int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, Binder.getCallingUserHandle().getIdentifier()); if (Binder.getCallingUid() != uid) { throw new SecurityException("Component outside caller's uid"); @@ -161,8 +175,9 @@ public class TileServices extends IQSService.Stub { @Override public void updateQsTile(Tile tile) { - verifyCaller(tile.getComponentName().getPackageName()); - CustomTile customTile = getTileForComponent(tile.getComponentName()); + ComponentName componentName = tile.getComponentName(); + verifyCaller(componentName.getPackageName()); + CustomTile customTile = getTileForComponent(componentName); if (customTile != null) { synchronized (mServices) { mServices.get(customTile).setLastUpdate(System.currentTimeMillis()); @@ -174,14 +189,45 @@ public class TileServices extends IQSService.Stub { @Override public void onShowDialog(Tile tile) { - verifyCaller(tile.getComponentName().getPackageName()); - CustomTile customTile = getTileForComponent(tile.getComponentName()); + ComponentName componentName = tile.getComponentName(); + verifyCaller(componentName.getPackageName()); + CustomTile customTile = getTileForComponent(componentName); if (customTile != null) { customTile.onDialogShown(); mHost.collapsePanels(); } } + @Override + public void updateStatusIcon(Tile tile, Icon icon, String contentDescription) { + final ComponentName componentName = tile.getComponentName(); + String packageName = componentName.getPackageName(); + verifyCaller(packageName); + CustomTile customTile = getTileForComponent(componentName); + if (customTile != null) { + try { + UserHandle userHandle = getCallingUserHandle(); + PackageInfo info = mContext.getPackageManager().getPackageInfoAsUser(packageName, 0, + userHandle.getIdentifier()); + if (info.applicationInfo.isSystemApp()) { + final StatusBarIcon statusIcon = icon != null + ? new StatusBarIcon(userHandle, packageName, icon, 0, 0, + contentDescription) + : null; + mMainHandler.post(new Runnable() { + @Override + public void run() { + StatusBarIconController iconController = mHost.getIconController(); + iconController.setIcon(componentName.getClassName(), statusIcon); + iconController.setExternalIcon(componentName.getClassName()); + } + }); + } + } catch (PackageManager.NameNotFoundException e) { + } + } + } + private CustomTile getTileForComponent(ComponentName component) { synchronized (mServices) { return mTiles.get(component); diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 57074df392db..e4d80672d30d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -43,8 +43,10 @@ import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent; import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent; import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent; +import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent; import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent; +import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent; import com.android.systemui.recents.events.activity.HideHistoryEvent; import com.android.systemui.recents.events.activity.HideRecentsEvent; import com.android.systemui.recents.events.activity.IterateRecentsEvent; @@ -56,8 +58,7 @@ import com.android.systemui.recents.events.activity.ToggleRecentsEvent; import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent; -import com.android.systemui.recents.events.ui.DismissTaskEvent; -import com.android.systemui.recents.events.ui.DismissTaskViewEvent; +import com.android.systemui.recents.events.ui.DeleteTaskDataEvent; import com.android.systemui.recents.events.ui.ShowApplicationInfoEvent; import com.android.systemui.recents.events.ui.StackViewScrolledEvent; import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent; @@ -67,7 +68,6 @@ import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent; import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent; import com.android.systemui.recents.history.RecentsHistoryView; import com.android.systemui.recents.misc.DozeTrigger; -import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.model.RecentsPackageMonitor; import com.android.systemui.recents.model.RecentsTaskLoadPlan; @@ -76,7 +76,6 @@ import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import com.android.systemui.recents.views.RecentsView; import com.android.systemui.recents.views.SystemBarScrimViews; -import com.android.systemui.recents.views.ViewAnimation; import com.android.systemui.statusbar.BaseStatusBar; import java.util.ArrayList; @@ -274,7 +273,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD // If we have a focused Task, launch that Task now if (mRecentsView.launchPreviousTask()) return true; // If none of the other cases apply, then just go Home - dismissRecentsToHome(true); + dismissRecentsToHome(true /* animateTaskViews */); } return false; } @@ -288,7 +287,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD // If we have a focused Task, launch that Task now if (mRecentsView.launchFocusedTask()) return true; // If none of the other cases apply, then just go Home - dismissRecentsToHome(true); + dismissRecentsToHome(true /* animateTaskViews */); return true; } return false; @@ -297,32 +296,18 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD /** * Dismisses Recents directly to Home without checking whether it is currently visible. */ - void dismissRecentsToHome(boolean animated) { - if (animated) { - ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(); - exitTrigger.increment(); - exitTrigger.addLastDecrementRunnable(mFinishLaunchHomeRunnable); - exitTrigger.addLastDecrementRunnable(new Runnable() { - @Override - public void run() { - Recents.getSystemServices().sendCloseSystemWindows( - BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY); - } - }); - mRecentsView.startExitToHomeAnimation( - new ViewAnimation.TaskViewExitContext(exitTrigger)); - exitTrigger.decrement(); - } else { - mFinishLaunchHomeRunnable.run(); - Recents.getSystemServices().sendCloseSystemWindows( - BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY); - } - } - - /** Dismisses Recents directly to Home without transition animation. */ - void dismissRecentsToHomeWithoutTransitionAnimation() { - finish(); - overridePendingTransition(0, 0); + void dismissRecentsToHome(boolean animateTaskViews) { + DismissRecentsToHomeAnimationStarted dismissEvent = + new DismissRecentsToHomeAnimationStarted(animateTaskViews); + dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable); + dismissEvent.addPostAnimationCallback(new Runnable() { + @Override + public void run() { + Recents.getSystemServices().sendCloseSystemWindows( + BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY); + } + }); + EventBus.getDefault().send(dismissEvent); } /** Dismisses Recents directly to Home if we currently aren't transitioning. */ @@ -609,7 +594,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD if (!dismissHistory()) { RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); if (launchState.launchedFromHome) { - dismissRecentsToHome(true); + dismissRecentsToHome(true /* animateTaskViews */); } else { dismissRecentsToLaunchTargetTaskOrHome(); } @@ -650,13 +635,13 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD hideEvent.addPostAnimationCallback(new Runnable() { @Override public void run() { - dismissRecentsToHome(true /* animated */); + dismissRecentsToHome(true /* animateTaskViews */); } }); EventBus.getDefault().send(hideEvent); } else { - dismissRecentsToHome(true /* animated */); + dismissRecentsToHome(true /* animateTaskViews */); } } else { // Do nothing @@ -665,12 +650,9 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) { // Try and start the enter animation (or restart it on configuration changed) - ReferenceCountedTrigger t = new ReferenceCountedTrigger(); - ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t); - ctx.postAnimationTrigger.increment(); if (RecentsDebugFlags.Static.EnableSearchBar) { if (mSearchWidgetInfo != null) { - ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { + event.addPostAnimationCallback(new Runnable() { @Override public void run() { // Start listening for widget package changes if there is one bound @@ -681,8 +663,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD }); } } - mRecentsView.startEnterRecentsAnimation(ctx); - ctx.postAnimationTrigger.decrement(); } public final void onBusEvent(EnterRecentsWindowLastAnimationFrameEvent event) { @@ -727,7 +707,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD MetricsLogger.count(this, "overview_app_info", 1); } - public final void onBusEvent(DismissTaskEvent event) { + public final void onBusEvent(DeleteTaskDataEvent event) { // Remove any stored data from the loader RecentsTaskLoader loader = Recents.getTaskLoader(); loader.deleteTaskData(event.task, false); @@ -743,7 +723,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD mRecentsView.showEmptyView(); } else { // Just go straight home (no animation necessary because there are no more task views) - dismissRecentsToHome(false /* animated */); + dismissRecentsToHome(false /* animateTaskViews */); } // Keep track of all-deletions @@ -756,7 +736,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD public final void onBusEvent(LaunchTaskFailedEvent event) { // Return to Home - dismissRecentsToHome(true); + dismissRecentsToHome(true /* animateTaskViews */); MetricsLogger.count(this, "overview_task_launch_failed", 1); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index cfbd1cb13ab9..67135d5621b4 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -19,7 +19,6 @@ package com.android.systemui.recents; import android.content.Context; import android.content.res.Resources; import android.graphics.Rect; -import android.provider.Settings; import com.android.systemui.R; import com.android.systemui.recents.misc.SystemServicesProxy; diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index fd00289b0248..213018a50b2c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -338,7 +338,6 @@ public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) { RecentsConfiguration config = Recents.getConfiguration(); RecentsActivityLaunchState launchState = config.getLaunchState(); - RecentsDebugFlags flags = Recents.getDebugFlags(); if (!launchState.launchedWithAltTab) { // Notify recents to move onto the next task EventBus.getDefault().post(new IterateRecentsEvent()); diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java index 5c49ac380b9b..b0c8ff3c15b6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/EventBus.java @@ -27,7 +27,6 @@ import android.os.SystemClock; import android.os.UserHandle; import android.util.Log; import android.util.MutableBoolean; - import com.android.systemui.recents.misc.ReferenceCountedTrigger; import java.lang.ref.WeakReference; @@ -663,8 +662,6 @@ public class EventBus extends BroadcastReceiver { /** * Registers a new subscriber. - * - * @return return whether or not this */ private void registerSubscriber(Object subscriber, int priority, MutableBoolean hasInterprocessEventsChangedOut) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java index 5f3e830197ed..e7be85868da2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/DismissRecentsToHomeAnimationStarted.java @@ -21,6 +21,11 @@ import com.android.systemui.recents.events.EventBus; /** * This is sent when the task animation when dismissing Recents starts. */ -public class DismissRecentsToHomeAnimationStarted extends EventBus.Event { - // Simple event +public class DismissRecentsToHomeAnimationStarted extends EventBus.AnimatedEvent { + + public final boolean animated; + + public DismissRecentsToHomeAnimationStarted(boolean animated) { + this.animated = animated; + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java index b31f32090ac7..918875a2561b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/EnterRecentsWindowAnimationCompletedEvent.java @@ -23,6 +23,6 @@ import com.android.systemui.recents.events.EventBus; * we can start in-app animations so that they don't conflict with the window transition into * Recents. */ -public class EnterRecentsWindowAnimationCompletedEvent extends EventBus.Event { +public class EnterRecentsWindowAnimationCompletedEvent extends EventBus.AnimatedEvent { // Simple event } diff --git a/packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java index 8ae8c53a9197..fa806eb24ad1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ExitRecentsWindowFirstAnimationFrameEvent.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.systemui.recents; +package com.android.systemui.recents.events.activity; import com.android.systemui.recents.events.EventBus; diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java index e85dea31c837..af3eeb0c837d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/HideHistoryEvent.java @@ -17,7 +17,6 @@ package com.android.systemui.recents.events.activity; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.misc.ReferenceCountedTrigger; /** * This is sent when the history view will be closed. diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java index 457d81eecd7c..21b9301755ad 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskEvent.java @@ -22,7 +22,7 @@ import com.android.systemui.recents.model.Task; import com.android.systemui.recents.views.TaskView; /** - * This is sent to launch a task from Recents. + * This event is sent to request that a particular task is launched. */ public class LaunchTaskEvent extends EventBus.Event { diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java new file mode 100644 index 000000000000..3925ab1186dc --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTaskStartedEvent.java @@ -0,0 +1,36 @@ +/* + * 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.recents.events.activity; + +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.views.TaskView; + +/** + * This event is sent following {@link LaunchTaskEvent} after the call to the system is made to + * start the task. + */ +public class LaunchTaskStartedEvent extends EventBus.AnimatedEvent { + + public final TaskView taskView; + public final boolean screenPinningRequested; + + public LaunchTaskStartedEvent(TaskView taskView, boolean screenPinningRequested) { + this.taskView = taskView; + this.screenPinningRequested = screenPinningRequested; + } + +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java index 94e5a9725c49..b39d645b9326 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ShowHistoryEvent.java @@ -17,7 +17,6 @@ package com.android.systemui.recents.events.activity; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.misc.ReferenceCountedTrigger; /** * This is sent when the history view button is clicked. diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java index b94ed7b4104b..7579cd8b82a0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/TaskStackUpdatedEvent.java @@ -16,7 +16,6 @@ package com.android.systemui.recents.events.activity; -import com.android.systemui.recents.RecentsAppWidgetHost; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.model.TaskStack; diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java index bcbbde84a160..4ed027084def 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DeleteTaskDataEvent.java @@ -18,16 +18,16 @@ package com.android.systemui.recents.events.ui; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.model.Task; -import com.android.systemui.recents.views.TaskView; /** - * This is sent when a {@link Task} has been dismissed. + * This is sent when the data associated with a given {@link Task} should be deleted from the + * system. */ -public class DismissTaskEvent extends EventBus.Event { +public class DeleteTaskDataEvent extends EventBus.Event { public final Task task; - public DismissTaskEvent(Task task) { + public DeleteTaskDataEvent(Task task) { this.task = task; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java index 968890aea2f1..1165f4e76861 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/DismissTaskViewEvent.java @@ -21,15 +21,15 @@ import com.android.systemui.recents.model.Task; import com.android.systemui.recents.views.TaskView; /** - * This is sent when a {@link TaskView} has been dismissed. + * This event is sent to request that the given {@link TaskView} is dismissed. */ -public class DismissTaskViewEvent extends EventBus.Event { +public class DismissTaskViewEvent extends EventBus.AnimatedEvent { - public final Task task; public final TaskView taskView; + public final Task task; - public DismissTaskViewEvent(Task task, TaskView taskView) { - this.task = task; + public DismissTaskViewEvent(TaskView taskView, Task task) { this.taskView = taskView; + this.task = task; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java new file mode 100644 index 000000000000..7bd0958ebb24 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskViewDismissedEvent.java @@ -0,0 +1,35 @@ +/* + * 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.recents.events.ui; + +import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.model.Task; +import com.android.systemui.recents.views.TaskView; + +/** + * This event is sent when a {@link TaskView} has been dismissed and is no longer visible. + */ +public class TaskViewDismissedEvent extends EventBus.Event { + + public final Task task; + public final TaskView taskView; + + public TaskViewDismissedEvent(Task task, TaskView taskView) { + this.task = task; + this.taskView = taskView; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java index 8aa463179082..73c282fe8816 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragEndEvent.java @@ -17,7 +17,6 @@ package com.android.systemui.recents.events.ui.dragndrop; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.views.DropTarget; import com.android.systemui.recents.views.TaskView; diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java index 9f3e9d5e3362..df740185f1e8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/focus/DismissFocusedTaskViewEvent.java @@ -17,9 +17,10 @@ package com.android.systemui.recents.events.ui.focus; import com.android.systemui.recents.events.EventBus; +import com.android.systemui.recents.views.TaskView; /** - * Dismisses the currently focused task view. + * This event is sent to request that the currently focused {@link TaskView} is dismissed. */ public class DismissFocusedTaskViewEvent extends EventBus.Event { // Simple event diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java index 72ec7b76f1c9..f0fa1da7810f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java +++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java @@ -185,7 +185,6 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd * remove the task from the TaskStack since the TaskStackView will also receive this event. */ public void removeTasks(String packageName, int userId) { - boolean packagesRemoved = false; for (int i = mRows.size() - 1; i >= 0; i--) { Row row = mRows.get(i); if (row.getViewType() == TASK_ROW_VIEW_TYPE) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java index e0a27308dd1a..a91ea7e94f48 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java +++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryItemTouchCallbacks.java @@ -22,7 +22,7 @@ import android.support.v7.widget.helper.ItemTouchHelper; import com.android.internal.logging.MetricsLogger; import com.android.systemui.recents.Constants; import com.android.systemui.recents.events.EventBus; -import com.android.systemui.recents.events.ui.DismissTaskEvent; +import com.android.systemui.recents.events.ui.DeleteTaskDataEvent; /** @@ -65,7 +65,7 @@ public class RecentsHistoryItemTouchCallbacks extends ItemTouchHelper.SimpleCall RecentsHistoryAdapter.TaskRow taskRow = (RecentsHistoryAdapter.TaskRow) row; // Remove the task from the system - EventBus.getDefault().send(new DismissTaskEvent(taskRow.task)); + EventBus.getDefault().send(new DeleteTaskDataEvent(taskRow.task)); mAdapter.onTaskRemoved(taskRow.task, position); // Keep track of deletions by swiping within history diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java index 9524da5d08bb..a2f5159a7ec3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java @@ -35,7 +35,6 @@ import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.PackagesChangedEvent; import com.android.systemui.recents.misc.ReferenceCountedTrigger; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.model.TaskStack; /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java index 367f2e268af5..2637d8812357 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/ReferenceCountedTrigger.java @@ -18,8 +18,6 @@ package com.android.systemui.recents.misc; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.content.Context; -import android.util.Log; import java.util.ArrayList; @@ -30,8 +28,8 @@ import java.util.ArrayList; public class ReferenceCountedTrigger { int mCount; - ArrayList<Runnable> mFirstIncRunnables = new ArrayList<Runnable>(); - ArrayList<Runnable> mLastDecRunnables = new ArrayList<Runnable>(); + ArrayList<Runnable> mFirstIncRunnables = new ArrayList<>(); + ArrayList<Runnable> mLastDecRunnables = new ArrayList<>(); Runnable mErrorRunnable; // Convenience runnables @@ -107,16 +105,20 @@ public class ReferenceCountedTrigger { mLastDecRunnables.clear(); } - /** Convenience method to decrement this trigger as a runnable. */ - public Runnable decrementAsRunnable() { - return mDecrementRunnable; - } - /** Convenience method to decrement this trigger as a animator listener. */ + /** + * Convenience method to decrement this trigger as a animator listener. This listener is + * guarded to prevent being called back multiple times, and will trigger a decrement once and + * only once. + */ public Animator.AnimatorListener decrementOnAnimationEnd() { return new AnimatorListenerAdapter() { + private boolean hasEnded; + @Override public void onAnimationEnd(Animator animation) { + if (hasEnded) return; decrement(); + hasEnded = true; } }; } 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 108029d68805..dfcf41bcebbf 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -68,7 +68,6 @@ import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.RecentsImpl; -import com.android.systemui.statusbar.BaseStatusBar; import java.io.IOException; import java.util.ArrayList; @@ -79,7 +78,6 @@ import java.util.Random; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; /** @@ -470,7 +468,7 @@ public class SystemServicesProxy { try { mIam.positionTaskInStack(taskId, stackId, 0); - } catch (RemoteException e) { + } catch (RemoteException | IllegalArgumentException e) { e.printStackTrace(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index 2bf2ccba77c7..086fb5854fdb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -88,6 +88,15 @@ public class Utilities { } /** + * Cancels an animation. + */ + public static void cancelAnimation(Animator animator) { + if (animator != null) { + animator.cancel(); + } + } + + /** * Cancels an animation ensuring that if it has listeners, onCancel and onEnd * are not called. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index d6262ac3da44..d8dfce568629 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -25,7 +25,6 @@ import android.graphics.drawable.Drawable; import android.os.UserHandle; import android.os.UserManager; import android.util.ArraySet; -import android.util.Log; import com.android.systemui.Prefs; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsConfiguration; @@ -115,8 +114,6 @@ public class RecentsTaskLoadPlan { * - least-recent to most-recent freeform tasks */ public synchronized void preloadPlan(RecentsTaskLoader loader, boolean isTopTaskHome) { - RecentsConfiguration config = Recents.getConfiguration(); - SystemServicesProxy ssp = Recents.getSystemServices(); Resources res = mContext.getResources(); ArrayList<Task> allTasks = new ArrayList<>(); if (mRawTasks == null) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java index d030fc1a906e..f7e2b9db24af 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -230,8 +230,7 @@ public class Task { public void notifyTaskDataUnloaded(Bitmap defaultThumbnail, Drawable defaultApplicationIcon) { icon = defaultApplicationIcon; thumbnail = defaultThumbnail; - int callbackCount = mCallbacks.size(); - for (int i = 0; i < callbackCount; i++) { + for (int i = mCallbacks.size() - 1; i >= 0; i--) { mCallbacks.get(i).onTaskDataUnloaded(); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index 5e720cba36c7..856200df6529 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -495,9 +495,6 @@ public class TaskStack { // Sort all the tasks to ensure they are ordered correctly Collections.sort(newTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR); - // TODO: Update screen pinning for the new front-most task post refactoring lockToTask out - // of the Task - // Filter out the historical tasks from this new list ArrayList<Task> stackTasks = new ArrayList<>(); ArrayList<Task> historyTasks = new ArrayList<>(); @@ -564,6 +561,22 @@ public class TaskStack { } /** + * Returns the set of "freeform" tasks in the stack. + */ + public ArrayList<Task> getFreeformTasks() { + ArrayList<Task> freeformTasks = new ArrayList<>(); + ArrayList<Task> tasks = mStackTaskList.getTasks(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + Task task = tasks.get(i); + if (task.isFreeformTask()) { + freeformTasks.add(task); + } + } + return freeformTasks; + } + + /** * Computes a set of all the active and historical tasks ordered by their last active time. */ public ArrayList<Task> computeAllTasksList() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java index c0b8a9d23223..b8bbf5165248 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java @@ -18,8 +18,6 @@ package com.android.systemui.recents.views; import android.graphics.Outline; import android.graphics.Rect; -import android.util.IntProperty; -import android.util.Property; import android.view.View; import android.view.ViewOutlineProvider; @@ -29,23 +27,11 @@ public class AnimateableViewBounds extends ViewOutlineProvider { View mSourceView; Rect mClipRect = new Rect(); Rect mClipBounds = new Rect(); + Rect mLastClipBounds = new Rect(); int mCornerRadius; float mAlpha = 1f; final float mMinAlpha = 0.25f; - public static final Property<AnimateableViewBounds, Integer> CLIP_BOTTOM = - new IntProperty<AnimateableViewBounds>("clipBottom") { - @Override - public void setValue(AnimateableViewBounds object, int clip) { - object.setClipBottom(clip, false /* force */); - } - - @Override - public Integer get(AnimateableViewBounds object) { - return object.getClipBottom(); - } - }; - public AnimateableViewBounds(View source, int cornerRadius) { mSourceView = source; mCornerRadius = cornerRadius; @@ -77,11 +63,9 @@ public class AnimateableViewBounds extends ViewOutlineProvider { } /** Sets the bottom clip. */ - public void setClipBottom(int bottom, boolean force) { - if (bottom != mClipRect.bottom || force) { - mClipRect.bottom = bottom; - updateClipBounds(); - } + public void setClipBottom(int bottom) { + mClipRect.bottom = bottom; + updateClipBounds(); } /** Returns the bottom clip. */ @@ -93,7 +77,10 @@ public class AnimateableViewBounds extends ViewOutlineProvider { mClipBounds.set(Math.max(0, mClipRect.left), Math.max(0, mClipRect.top), mSourceView.getWidth() - Math.max(0, mClipRect.right), mSourceView.getHeight() - Math.max(0, mClipRect.bottom)); - mSourceView.setClipBounds(mClipBounds); - mSourceView.invalidateOutline(); + if (!mLastClipBounds.equals(mClipBounds)) { + mSourceView.setClipBounds(mClipBounds); + mSourceView.invalidateOutline(); + mLastClipBounds.set(mClipBounds); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java index 7f907ef86a2a..fce916b9d2d3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java @@ -19,8 +19,6 @@ package com.android.systemui.recents.views; import android.content.Context; import android.graphics.Rect; import android.graphics.RectF; -import android.util.Log; - import com.android.systemui.R; import com.android.systemui.recents.model.Task; @@ -33,9 +31,6 @@ import java.util.List; */ public class FreeformWorkspaceLayoutAlgorithm { - private static final String TAG = "FreeformWorkspaceLayoutAlgorithm"; - private static final boolean DEBUG = false; - // Optimization, allows for quick lookup of task -> rect private HashMap<Task.TaskKey, RectF> mTaskRectMap = new HashMap<>(); @@ -177,10 +172,6 @@ public class FreeformWorkspaceLayoutAlgorithm { transformOut.rect.offset(stackLayout.mFreeformRect.left, stackLayout.mFreeformRect.top); transformOut.visible = true; transformOut.p = 1f; - - if (DEBUG) { - Log.d(TAG, "getTransform: " + task.key + ", " + transformOut); - } return transformOut; } return null; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java index 0af7c1e9379e..51cae862cdcc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -32,15 +32,15 @@ import android.view.AppTransitionAnimationSpec; import android.view.IAppTransitionAnimationSpecsFuture; import android.view.WindowManagerGlobal; import com.android.internal.annotations.GuardedBy; -import com.android.systemui.recents.ExitRecentsWindowFirstAnimationFrameEvent; 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.ui.DismissTaskViewEvent; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -90,7 +90,7 @@ public class RecentsTransitionHelper { */ public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task, final TaskStackView stackView, final TaskView taskView, - final boolean lockToTask, final Rect bounds, int destinationStack) { + final boolean screenPinningRequested, final Rect bounds, int destinationStack) { final ActivityOptions opts = ActivityOptions.makeBasic(); if (bounds != null) { opts.setLaunchBounds(bounds.isEmpty() ? null : bounds); @@ -109,7 +109,7 @@ public class RecentsTransitionHelper { EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task)); EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent()); - if (lockToTask) { + if (screenPinningRequested) { // Request screen pinning after the animation runs mHandler.postDelayed(mStartScreenPinningRunnable, 350); } @@ -131,16 +131,19 @@ public class RecentsTransitionHelper { // task views, and we can launch immediately startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } else { + LaunchTaskStartedEvent launchStartedEvent = new LaunchTaskStartedEvent(taskView, + screenPinningRequested); if (task.group != null && !task.group.isFrontMostTask(task)) { - stackView.startLaunchTaskAnimation(taskView, new Runnable() { + launchStartedEvent.addPostAnimationCallback(new Runnable() { @Override public void run() { startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } - }, lockToTask); + }); + EventBus.getDefault().send(launchStartedEvent); } else { - stackView.startLaunchTaskAnimation(taskView, null, lockToTask); + EventBus.getDefault().send(launchStartedEvent); startTaskActivity(stack, task, taskView, opts, transitionFuture, animStartedListener); } @@ -167,7 +170,7 @@ public class RecentsTransitionHelper { EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront)); } else { // Dismiss the task if we fail to launch it - EventBus.getDefault().send(new DismissTaskViewEvent(task, taskView)); + taskView.dismissTask(); // Keep track of failed launches EventBus.getDefault().send(new LaunchTaskFailedEvent()); 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 c95c73bc4f89..e28e2b383aba 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,9 @@ package com.android.systemui.recents.views; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; import android.content.Context; -import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; @@ -32,8 +33,8 @@ import android.view.WindowInsets; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import android.widget.FrameLayout; -import com.android.internal.logging.MetricsLogger; import android.widget.TextView; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivity; @@ -43,7 +44,6 @@ import com.android.systemui.recents.RecentsConfiguration; 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.DebugFlagsChangedEvent; import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; import com.android.systemui.recents.events.activity.HideHistoryButtonEvent; import com.android.systemui.recents.events.activity.HideHistoryEvent; @@ -65,6 +65,7 @@ import com.android.systemui.stackdivider.WindowManagerProxy; import com.android.systemui.statusbar.FlingAnimationUtils; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; @@ -116,7 +117,6 @@ public class RecentsView extends FrameLayout { public RecentsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - Resources res = context.getResources(); setWillNotDraw(false); mHandler = new Handler(); mTransitionHelper = new RecentsTransitionHelper(getContext(), mHandler); @@ -145,14 +145,11 @@ public class RecentsView extends FrameLayout { RecentsConfiguration config = Recents.getConfiguration(); RecentsActivityLaunchState launchState = config.getLaunchState(); mStack = stack; - // Disable reusing task stack views until the visibility bug is fixed. b/25998134 - if (false && launchState.launchedReuseTaskStackViews) { + if (launchState.launchedReuseTaskStackViews) { if (mTaskStackView != null) { // If onRecentsHidden is not triggered, we need to the stack view again here mTaskStackView.reset(); mTaskStackView.setStack(stack); - removeView(mTaskStackView); - addView(mTaskStackView); } else { mTaskStackView = new TaskStackView(getContext(), stack); addView(mTaskStackView); @@ -216,7 +213,6 @@ public class RecentsView extends FrameLayout { /** Launches the focused task from the first stack if possible */ public boolean launchFocusedTask() { if (mTaskStackView != null) { - TaskStack stack = mTaskStackView.getStack(); Task task = mTaskStackView.getFocusedTask(); if (task != null) { TaskView taskView = mTaskStackView.getChildViewForTask(task); @@ -246,7 +242,6 @@ public class RecentsView extends FrameLayout { /** Launches a given task. */ public boolean launchTask(Task task, Rect taskBounds, int destinationStack) { if (mTaskStackView != null) { - TaskStack stack = mTaskStackView.getStack(); // Iterate the stack views and try and find the given task. List<TaskView> taskViews = mTaskStackView.getTaskViews(); int taskViewCount = taskViews.size(); @@ -262,39 +257,6 @@ public class RecentsView extends FrameLayout { return false; } - /** Requests all task stacks to start their enter-recents animation */ - public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) { - // We have to increment/decrement the post animation trigger in case there are no children - // to ensure that it runs - ctx.postAnimationTrigger.increment(); - if (mTaskStackView != null) { - mTaskStackView.startEnterRecentsAnimation(ctx); - } - ctx.postAnimationTrigger.decrement(); - } - - /** Requests all task stacks to start their exit-recents animation */ - public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { - // We have to increment/decrement the post animation trigger in case there are no children - // to ensure that it runs - ctx.postAnimationTrigger.increment(); - if (mTaskStackView != null) { - mTaskStackView.startExitToHomeAnimation(ctx); - } - ctx.postAnimationTrigger.decrement(); - - // Hide the history button - int taskViewExitToHomeDuration = getResources().getInteger( - R.integer.recents_task_exit_to_home_duration); - hideHistoryButton(taskViewExitToHomeDuration); - - // If we are going home, cancel the previous task's window transition - EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null)); - - // Notify sof the exit animation - EventBus.getDefault().send(new DismissRecentsToHomeAnimationStarted()); - } - /** Adds the search bar */ public void setSearchBar(RecentsAppWidgetHostView searchBar) { // Remove the previous search bar if one exists @@ -496,6 +458,16 @@ public class RecentsView extends FrameLayout { event.screenPinningRequested, event.targetTaskBounds, event.targetTaskStack); } + public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) { + // Hide the history button + int taskViewExitToHomeDuration = getResources().getInteger( + R.integer.recents_task_exit_to_home_duration); + hideHistoryButton(taskViewExitToHomeDuration); + + // If we are going home, cancel the previous task's window transition + EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null)); + } + public final void onBusEvent(DragStartEvent event) { updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(), TaskStack.DockState.NONE.viewState.dockAreaAlpha); @@ -517,23 +489,25 @@ public class RecentsView extends FrameLayout { // Handle the case where we drop onto a dock region if (event.dropTarget instanceof TaskStack.DockState) { - final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; - - // Remove the task after it is docked - event.taskView.animate() - .alpha(0f) - .setDuration(150) - .setInterpolator(mFastOutLinearInInterpolator) - .setUpdateListener(null) - .setListener(null) - .withEndAction(new Runnable() { - @Override - public void run() { - mTaskStackView.getStack().removeTask(event.task); - } - }) - .withLayer() - .start(); + TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; + TaskStackLayoutAlgorithm stackLayout = mTaskStackView.getStackAlgorithm(); + TaskStackViewScroller stackScroller = mTaskStackView.getScroller(); + TaskViewTransform tmpTransform = new TaskViewTransform(); + + // Remove the task view after it is docked + stackLayout.getStackTransform(event.task, stackScroller.getStackScroll(), tmpTransform, + null); + tmpTransform.scale = event.taskView.getScaleX(); + tmpTransform.rect.offset(event.taskView.getTranslationX(), + event.taskView.getTranslationY()); + mTaskStackView.updateTaskViewToTransform(event.taskView, tmpTransform, + new TaskViewAnimation(150, mFastOutLinearInInterpolator, + new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mTaskStackView.getStack().removeTask(event.task); + } + })); // Dock the task and launch it SystemServicesProxy ssp = Recents.getSystemServices(); @@ -613,21 +587,23 @@ public class RecentsView extends FrameLayout { private void showHistoryButton(final int duration, final ReferenceCountedTrigger postHideHistoryAnimationTrigger) { - mHistoryButton.setVisibility(View.VISIBLE); - mHistoryButton.setAlpha(0f); mHistoryButton.setText(getContext().getString(R.string.recents_history_label_format, mStack.getHistoricalTasks().size())); - postHideHistoryAnimationTrigger.addLastDecrementRunnable(new Runnable() { - @Override - public void run() { - mHistoryButton.animate() - .alpha(1f) - .setDuration(duration) - .setInterpolator(mFastOutSlowInInterpolator) - .withLayer() - .start(); - } - }); + if (mHistoryButton.getVisibility() == View.INVISIBLE) { + mHistoryButton.setVisibility(View.VISIBLE); + mHistoryButton.setAlpha(0f); + postHideHistoryAnimationTrigger.addLastDecrementRunnable(new Runnable() { + @Override + public void run() { + mHistoryButton.animate() + .alpha(1f) + .setDuration(duration) + .setInterpolator(mFastOutSlowInInterpolator) + .withLayer() + .start(); + } + }); + } } /** @@ -641,20 +617,22 @@ public class RecentsView extends FrameLayout { private void hideHistoryButton(int duration, final ReferenceCountedTrigger postHideStackAnimationTrigger) { - mHistoryButton.animate() - .alpha(0f) - .setDuration(duration) - .setInterpolator(mFastOutLinearInInterpolator) - .withEndAction(new Runnable() { - @Override - public void run() { - mHistoryButton.setVisibility(View.INVISIBLE); - postHideStackAnimationTrigger.decrement(); - } - }) - .withLayer() - .start(); - postHideStackAnimationTrigger.increment(); + if (mHistoryButton.getVisibility() == View.VISIBLE) { + mHistoryButton.animate() + .alpha(0f) + .setDuration(duration) + .setInterpolator(mFastOutLinearInInterpolator) + .withEndAction(new Runnable() { + @Override + public void run() { + mHistoryButton.setVisibility(View.INVISIBLE); + postHideStackAnimationTrigger.decrement(); + } + }) + .withLayer() + .start(); + postHideStackAnimationTrigger.increment(); + } } /** @@ -663,9 +641,7 @@ public class RecentsView extends FrameLayout { private void updateVisibleDockRegions(TaskStack.DockState[] newDockStates, int overrideAlpha) { ArraySet<TaskStack.DockState> newDockStatesSet = new ArraySet<>(); if (newDockStates != null) { - for (TaskStack.DockState dockState : newDockStates) { - newDockStatesSet.add(dockState); - } + Collections.addAll(newDockStatesSet, newDockStates); } for (TaskStack.DockState dockState : mVisibleDockStates) { TaskStack.DockState.ViewState viewState = dockState.viewState; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java index 318801dbcb9f..473334b40d8d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java @@ -26,7 +26,6 @@ import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEve import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartInitializeDropTargetsEvent; -import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; @@ -58,9 +57,6 @@ class DockRegion { */ public class RecentsViewTouchHandler { - private static final String TAG = "RecentsViewTouchHandler"; - private static final boolean DEBUG = false; - private RecentsView mRv; private Task mDragTask; @@ -128,7 +124,6 @@ public class RecentsViewTouchHandler { mTaskView.setTranslationX(x); mTaskView.setTranslationY(y); - RecentsConfiguration config = Recents.getConfiguration(); if (!ssp.hasDockedTask()) { // Add the dock state drop targets (these take priority) TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation(); @@ -150,7 +145,6 @@ public class RecentsViewTouchHandler { /** * Handles dragging touch events - * @param ev */ private void handleTouchEvent(MotionEvent ev) { int action = ev.getAction(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java index f84eb5367665..9618f212d983 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -22,9 +22,6 @@ import android.view.View; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import com.android.systemui.R; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsActivityLaunchState; -import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted; import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent; @@ -64,8 +61,6 @@ public class SystemBarScrimViews { */ public void prepareEnterRecentsAnimation(boolean hasStatusBarScrim, boolean animateStatusBarScrim, boolean hasNavBarScrim, boolean animateNavBarScrim) { - RecentsConfiguration config = Recents.getConfiguration(); - RecentsActivityLaunchState launchState = config.getLaunchState(); mHasNavBarScrim = hasStatusBarScrim; mShouldAnimateStatusBarScrim = animateStatusBarScrim; mHasStatusBarScrim = hasNavBarScrim; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java new file mode 100644 index 000000000000..80a35de9feb7 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java @@ -0,0 +1,397 @@ +/* + * 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.recents.views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.content.Context; +import android.content.res.Resources; +import android.graphics.RectF; +import android.view.View; +import android.view.animation.AnimationUtils; +import android.view.animation.Interpolator; +import com.android.systemui.R; +import com.android.systemui.recents.Recents; +import com.android.systemui.recents.RecentsActivityLaunchState; +import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.misc.ReferenceCountedTrigger; +import com.android.systemui.recents.model.Task; +import com.android.systemui.recents.model.TaskStack; +import com.android.systemui.statusbar.phone.PhoneStatusBar; + +import java.util.List; + +/** + * A helper class to create task view animations for {@link TaskView}s in a {@link TaskStackView}, + * but not the contents of the {@link TaskView}s. + */ +public class TaskStackAnimationHelper { + + /** + * Callbacks from the helper to coordinate view-content animations with view animations. + */ + public interface Callbacks { + /** + * Callback to prepare for the start animation for the launch target {@link TaskView}. + */ + void onPrepareLaunchTargetForEnterAnimation(); + + /** + * Callback to start the animation for the launch target {@link TaskView}. + */ + void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled, + ReferenceCountedTrigger postAnimationTrigger); + + /** + * Callback to start the animation for the launch target {@link TaskView} when it is + * launched from Recents. + */ + void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested, + ReferenceCountedTrigger postAnimationTrigger); + } + + private TaskStackView mStackView; + + private Interpolator mFastOutSlowInInterpolator; + private Interpolator mFastOutLinearInInterpolator; + private Interpolator mQuintOutInterpolator; + + private TaskViewTransform mTmpTransform = new TaskViewTransform(); + + public TaskStackAnimationHelper(Context context, TaskStackView stackView) { + mStackView = stackView; + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_slow_in); + mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_linear_in); + mQuintOutInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.decelerate_quint); + } + + /** + * Prepares the stack views and puts them in their initial animation state while visible, before + * the in-app enter animations start (after the window-transition completes). + */ + public void prepareForEnterAnimation() { + RecentsConfiguration config = Recents.getConfiguration(); + RecentsActivityLaunchState launchState = config.getLaunchState(); + Resources res = mStackView.getResources(); + + TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); + TaskStackViewScroller stackScroller = mStackView.getScroller(); + TaskStack stack = mStackView.getStack(); + Task launchTargetTask = stack.getLaunchTarget(); + + // Break early if there are no tasks + if (stack.getStackTaskCount() == 0) { + return; + } + + int offscreenY = stackLayout.mStackRect.bottom; + int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( + R.dimen.recents_task_view_affiliate_group_enter_offset); + + // Prepare each of the task views for their enter animation from front to back + List<TaskView> taskViews = mStackView.getTaskViews(); + for (int i = taskViews.size() - 1; i >= 0; i--) { + TaskView tv = taskViews.get(i); + Task task = tv.getTask(); + boolean currentTaskOccludesLaunchTarget = (launchTargetTask != null && + launchTargetTask.group.isTaskAboveTask(task, launchTargetTask)); + boolean hideTask = (launchTargetTask != null && + launchTargetTask.isFreeformTask() && task.isFreeformTask()); + + // Get the current transform for the task, which will be used to position it offscreen + stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, + null); + + if (hideTask) { + tv.setVisibility(View.INVISIBLE); + } else if (launchState.launchedHasConfigurationChanged) { + // Just load the views as-is + } else if (launchState.launchedFromAppWithThumbnail) { + if (task.isLaunchTarget) { + tv.onPrepareLaunchTargetForEnterAnimation(); + } else if (currentTaskOccludesLaunchTarget) { + // Move the task view slightly lower so we can animate it in + RectF bounds = new RectF(mTmpTransform.rect); + bounds.offset(0, taskViewAffiliateGroupEnterOffset); + tv.setAlpha(0f); + tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, + (int) bounds.right, (int) bounds.bottom); + } + } else if (launchState.launchedFromHome) { + // Move the task view off screen (below) so we can animate it in + RectF bounds = new RectF(mTmpTransform.rect); + bounds.offset(0, offscreenY); + tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right, + (int) bounds.bottom); + } + } + } + + /** + * Starts the in-app enter animation, which animates the {@link TaskView}s to their final places + * depending on how Recents was triggered. + */ + public void startEnterAnimation(final ReferenceCountedTrigger postAnimationTrigger) { + RecentsConfiguration config = Recents.getConfiguration(); + RecentsActivityLaunchState launchState = config.getLaunchState(); + Resources res = mStackView.getResources(); + + TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); + TaskStackViewScroller stackScroller = mStackView.getScroller(); + TaskStack stack = mStackView.getStack(); + Task launchTargetTask = stack.getLaunchTarget(); + + // Break early if there are no tasks + if (stack.getStackTaskCount() == 0) { + return; + } + + int taskViewEnterFromAppDuration = res.getInteger( + R.integer.recents_task_enter_from_app_duration); + int taskViewEnterFromHomeDuration = res.getInteger( + R.integer.recents_task_enter_from_home_duration); + int taskViewEnterFromHomeStaggerDelay = res.getInteger( + R.integer.recents_task_enter_from_home_stagger_delay); + + // Create enter animations for each of the views from front to back + List<TaskView> taskViews = mStackView.getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = taskViewCount - 1; i >= 0; i--) { + TaskView tv = taskViews.get(i); + Task task = tv.getTask(); + boolean currentTaskOccludesLaunchTarget = false; + if (launchTargetTask != null) { + currentTaskOccludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(task, + launchTargetTask); + } + + // Get the current transform for the task, which will be updated to the final transform + // to animate to depending on how recents was invoked + stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, + null); + + if (launchState.launchedFromAppWithThumbnail) { + if (task.isLaunchTarget) { + tv.onStartLaunchTargetEnterAnimation(taskViewEnterFromAppDuration, + mStackView.mScreenPinningEnabled, postAnimationTrigger); + } else { + // Animate the task up if it was occluding the launch target + if (currentTaskOccludesLaunchTarget) { + TaskViewAnimation taskAnimation = new TaskViewAnimation( + taskViewEnterFromAppDuration, PhoneStatusBar.ALPHA_IN, + postAnimationTrigger.decrementOnAnimationEnd()); + postAnimationTrigger.increment(); + mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); + } + } + + } else if (launchState.launchedFromHome) { + // Animate the tasks up + int frontIndex = (taskViewCount - i - 1); + int delay = frontIndex * taskViewEnterFromHomeStaggerDelay; + int duration = taskViewEnterFromHomeDuration + + frontIndex * taskViewEnterFromHomeStaggerDelay; + + TaskViewAnimation taskAnimation = new TaskViewAnimation(delay, + duration, mQuintOutInterpolator, + postAnimationTrigger.decrementOnAnimationEnd()); + postAnimationTrigger.increment(); + mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); + } + } + } + + /** + * Starts an in-app animation to hide all the task views so that we can transition back home. + */ + public void startExitToHomeAnimation(boolean animated, + ReferenceCountedTrigger postAnimationTrigger) { + Resources res = mStackView.getResources(); + TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); + TaskStackViewScroller stackScroller = mStackView.getScroller(); + TaskStack stack = mStackView.getStack(); + + // Break early if there are no tasks + if (stack.getStackTaskCount() == 0) { + return; + } + + int offscreenY = stackLayout.mStackRect.bottom; + int taskViewExitToHomeDuration = res.getInteger( + R.integer.recents_task_exit_to_home_duration); + + // Create the animations for each of the tasks + List<TaskView> taskViews = mStackView.getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = 0; i < taskViewCount; i++) { + TaskView tv = taskViews.get(i); + Task task = tv.getTask(); + TaskViewAnimation taskAnimation = new TaskViewAnimation( + animated ? taskViewExitToHomeDuration : 0, mFastOutLinearInInterpolator, + postAnimationTrigger.decrementOnAnimationEnd()); + postAnimationTrigger.increment(); + + stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, + null); + mTmpTransform.rect.offset(0, offscreenY); + mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); + } + } + + /** + * Starts the animation for the launching task view, hiding any tasks that might occlude the + * window transition for the launching task. + */ + public void startLaunchTaskAnimation(TaskView launchingTaskView, boolean screenPinningRequested, + final ReferenceCountedTrigger postAnimationTrigger) { + Resources res = mStackView.getResources(); + TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); + TaskStackViewScroller stackScroller = mStackView.getScroller(); + + int taskViewExitToAppDuration = res.getInteger( + R.integer.recents_task_exit_to_app_duration); + int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( + R.dimen.recents_task_view_affiliate_group_enter_offset); + + Task launchingTask = launchingTaskView.getTask(); + List<TaskView> taskViews = mStackView.getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = 0; i < taskViewCount; i++) { + TaskView tv = taskViews.get(i); + Task task = tv.getTask(); + boolean currentTaskOccludesLaunchTarget = (launchingTask != null && + launchingTask.group.isTaskAboveTask(task, launchingTask)); + + if (tv == launchingTaskView) { + tv.setClipViewInStack(false); + tv.onStartLaunchTargetLaunchAnimation(taskViewExitToAppDuration, + screenPinningRequested, postAnimationTrigger); + } else if (currentTaskOccludesLaunchTarget) { + // Animate this task out of view + TaskViewAnimation taskAnimation = new TaskViewAnimation( + taskViewExitToAppDuration, mFastOutLinearInInterpolator, + postAnimationTrigger.decrementOnAnimationEnd()); + postAnimationTrigger.increment(); + + stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, + null); + mTmpTransform.alpha = 0f; + mTmpTransform.rect.offset(0, taskViewAffiliateGroupEnterOffset); + mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); + } + } + } + + /** + * Starts the delete animation for the specified {@link TaskView}. + */ + public void startDeleteTaskAnimation(Task deleteTask, final TaskView deleteTaskView, + final ReferenceCountedTrigger postAnimationTrigger) { + Resources res = mStackView.getResources(); + TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); + TaskStackViewScroller stackScroller = mStackView.getScroller(); + + int taskViewRemoveAnimDuration = res.getInteger( + R.integer.recents_animate_task_view_remove_duration); + int taskViewRemoveAnimTranslationXPx = res.getDimensionPixelSize( + R.dimen.recents_task_view_remove_anim_translation_x); + + // Disabling clipping with the stack while the view is animating away + deleteTaskView.setClipViewInStack(false); + + // Compose the new animation and transform and star the animation + TaskViewAnimation taskAnimation = new TaskViewAnimation(taskViewRemoveAnimDuration, + PhoneStatusBar.ALPHA_OUT, new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + postAnimationTrigger.decrement(); + + // Re-enable clipping with the stack (we will reuse this view) + deleteTaskView.setClipViewInStack(true); + } + }); + postAnimationTrigger.increment(); + + stackLayout.getStackTransform(deleteTask, stackScroller.getStackScroll(), mTmpTransform, + null); + mTmpTransform.alpha = 0f; + mTmpTransform.rect.offset(taskViewRemoveAnimTranslationXPx, 0); + mStackView.updateTaskViewToTransform(deleteTaskView, mTmpTransform, taskAnimation); + } + + /** + * Starts the animation to hide the {@link TaskView}s when the history is shown. The history + * view's animation will be deferred until all the {@link TaskView}s are finished animating. + */ + public void startShowHistoryAnimation(ReferenceCountedTrigger postAnimationTrigger) { + Resources res = mStackView.getResources(); + TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); + TaskStackViewScroller stackScroller = mStackView.getScroller(); + + int historyTransitionDuration = res.getInteger( + R.integer.recents_history_transition_duration); + + List<TaskView> taskViews = mStackView.getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = taskViewCount - 1; i >= 0; i--) { + TaskView tv = taskViews.get(i); + Task task = tv.getTask(); + TaskViewAnimation taskAnimation = new TaskViewAnimation( + historyTransitionDuration, PhoneStatusBar.ALPHA_OUT, + postAnimationTrigger.decrementOnAnimationEnd()); + postAnimationTrigger.increment(); + + stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, + null); + mTmpTransform.alpha = 0f; + mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); + } + } + + /** + * Starts the animation to show the {@link TaskView}s when the history is hidden. The + * {@link TaskView} animations will be deferred until the history view has been animated away. + */ + public void startHideHistoryAnimation(final ReferenceCountedTrigger postAnimationTrigger) { + final Resources res = mStackView.getResources(); + final TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm(); + final TaskStackViewScroller stackScroller = mStackView.getScroller(); + + final int historyTransitionDuration = res.getInteger( + R.integer.recents_history_transition_duration); + + List<TaskView> taskViews = mStackView.getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = taskViewCount - 1; i >= 0; i--) { + final TaskView tv = taskViews.get(i); + postAnimationTrigger.addLastDecrementRunnable(new Runnable() { + @Override + public void run() { + TaskViewAnimation taskAnimation = new TaskViewAnimation( + historyTransitionDuration, PhoneStatusBar.ALPHA_IN); + stackLayout.getStackTransform(tv.getTask(), stackScroller.getStackScroll(), + mTmpTransform, null); + mTmpTransform.alpha = 1f; + mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); + } + }); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 9d391b0c8c86..726e4537a620 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -22,7 +22,6 @@ import android.content.res.Resources; import android.graphics.Path; import android.graphics.Rect; import android.util.FloatProperty; -import android.util.Log; import android.util.Property; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -103,9 +102,6 @@ class Range { */ public class TaskStackLayoutAlgorithm { - private static final String TAG = "TaskStackViewLayoutAlgorithm"; - private static final boolean DEBUG = false; - // The scale factor to apply to the user movement in the stack to unfocus it private static final float UNFOCUS_MULTIPLIER = 0.8f; @@ -130,7 +126,7 @@ public class TaskStackLayoutAlgorithm { * allocate to the freeform workspace * @param freeformBackgroundAlpha the background alpha for the freeform workspace */ - StackState(float freeformHeightPct, int freeformBackgroundAlpha) { + private StackState(float freeformHeightPct, int freeformBackgroundAlpha) { this.freeformHeightPct = freeformHeightPct; this.freeformBackgroundAlpha = freeformBackgroundAlpha; } @@ -212,7 +208,6 @@ public class TaskStackLayoutAlgorithm { } Context mContext; - private TaskStackView mStackView; private Interpolator mLinearOutSlowInInterpolator; private StackState mState = StackState.SPLIT; @@ -280,9 +275,12 @@ public class TaskStackLayoutAlgorithm { // The freeform workspace layout FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm; - public TaskStackLayoutAlgorithm(Context context, TaskStackView stackView) { + // The transform to place TaskViews at the front and back of the stack respectively + TaskViewTransform mBackOfStackTransform = new TaskViewTransform(); + TaskViewTransform mFrontOfStackTransform = new TaskViewTransform(); + + public TaskStackLayoutAlgorithm(Context context) { Resources res = context.getResources(); - mStackView = stackView; mFocusedRange = new Range(res.getFloat(R.integer.recents_layout_focused_range_min), res.getFloat(R.integer.recents_layout_focused_range_max)); @@ -318,7 +316,7 @@ public class TaskStackLayoutAlgorithm { */ public void setFocusState(float focusState) { mFocusState = focusState; - mStackView.requestSynchronizeStackViewsWithModel(); + updateFrontBackTransforms(); } /** @@ -368,14 +366,7 @@ public class TaskStackLayoutAlgorithm { mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve); mFocusedCurve = constructFocusedCurve(); mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve); - - if (DEBUG) { - Log.d(TAG, "initialize"); - Log.d(TAG, "\tmFreeformRect: " + mFreeformRect); - Log.d(TAG, "\tmStackRect: " + mStackRect); - Log.d(TAG, "\tmTaskRect: " + mTaskRect); - Log.d(TAG, "\tmSystemInsets: " + mSystemInsets); - } + updateFrontBackTransforms(); } /** @@ -455,13 +446,6 @@ public class TaskStackLayoutAlgorithm { mInitialScrollP = (mNumStackTasks - 1) - mUnfocusedRange.getAbsoluteX(normX); } } - - if (DEBUG) { - Log.d(TAG, "mNumStackTasks: " + mNumStackTasks); - Log.d(TAG, "mNumFreeformTasks: " + mNumFreeformTasks); - Log.d(TAG, "mMinScrollP: " + mMinScrollP); - Log.d(TAG, "mMaxScrollP: " + mMaxScrollP); - } } /** @@ -471,7 +455,7 @@ public class TaskStackLayoutAlgorithm { Utilities.cancelAnimationWithoutCallbacks(mFocusStateAnimator); if (mFocusState > STATE_UNFOCUSED) { float delta = (float) yMovement / (UNFOCUS_MULTIPLIER * mStackRect.height()); - mFocusState -= Math.min(mFocusState, Math.abs(delta)); + setFocusState(mFocusState - Math.min(mFocusState, Math.abs(delta))); } } @@ -497,27 +481,23 @@ public class TaskStackLayoutAlgorithm { RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState(); RecentsDebugFlags debugFlags = Recents.getDebugFlags(); if (launchState.launchedWithAltTab || debugFlags.isInitialStatePaging()) { - return 1f; + return STATE_FOCUSED; } - return 0f; + return STATE_UNFOCUSED; } /** - * Returns the task progress that would put the task just off the back of the stack. + * Returns the TaskViewTransform that would put the task just off the back of the stack. */ - public float getStackBackTaskProgress(float stackScroll) { - float min = mUnfocusedRange.relativeMin + - mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin); - return stackScroll + min; + public TaskViewTransform getBackOfStackTransform() { + return mBackOfStackTransform; } /** - * Returns the task progress that would put the task just off the front of the stack. + * Returns the TaskViewTransform that would put the task just off the front of the stack. */ - public float getStackFrontTaskProgress(float stackScroll) { - float max = mUnfocusedRange.relativeMax + - mFocusState * (mFocusedRange.relativeMax - mUnfocusedRange.relativeMax); - return stackScroll + max; + public TaskViewTransform getFrontOfStackTransform() { + return mFrontOfStackTransform; } /** @@ -617,9 +597,6 @@ public class TaskStackLayoutAlgorithm { if (task.thumbnail != null) { transformOut.thumbnailScale = (float) mTaskRect.width() / task.thumbnail.getWidth(); } - if (DEBUG) { - Log.d(TAG, "getTransform: " + task.key + ", " + transformOut); - } return transformOut; } } @@ -769,4 +746,23 @@ public class TaskStackLayoutAlgorithm { p.cubicTo(0.5f, 1f - peekHeightPct, cpoint2X, cpoint2Y, 1f, 0f); return p; } + + /** + * Updates the current transforms that would put a TaskView at the front and back of the stack. + */ + private void updateFrontBackTransforms() { + // Return early if we have not yet initialized + if (mStackRect.isEmpty()) { + return; + } + + float min = mUnfocusedRange.relativeMin + + mFocusState * (mFocusedRange.relativeMin - mUnfocusedRange.relativeMin); + float max = mUnfocusedRange.relativeMax + + mFocusState * (mFocusedRange.relativeMax - mUnfocusedRange.relativeMax); + getStackTransform(min, 0f, mBackOfStackTransform, null); + getStackTransform(max, 0f, mFrontOfStackTransform, null); + mBackOfStackTransform.visible = true; + mFrontOfStackTransform.visible = true; + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 94fae1381d85..9568facf87fb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -23,14 +23,12 @@ import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.os.Bundle; import android.os.Parcelable; import android.provider.Settings; import android.util.IntProperty; -import android.util.Log; import android.util.Property; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -47,19 +45,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.EnterRecentsWindowAnimationCompletedEvent; import com.android.systemui.recents.events.activity.HideHistoryButtonEvent; import com.android.systemui.recents.events.activity.HideHistoryEvent; import com.android.systemui.recents.events.activity.IterateRecentsEvent; import com.android.systemui.recents.events.activity.LaunchTaskEvent; +import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent; import com.android.systemui.recents.events.activity.PackagesChangedEvent; import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent; import com.android.systemui.recents.events.activity.ShowHistoryEvent; import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent; -import com.android.systemui.recents.events.ui.DismissTaskEvent; +import com.android.systemui.recents.events.ui.DeleteTaskDataEvent; import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.StackViewScrolledEvent; +import com.android.systemui.recents.events.ui.TaskViewDismissedEvent; import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent; import com.android.systemui.recents.events.ui.UserInteractionEvent; import com.android.systemui.recents.events.ui.dragndrop.DragDropTargetChangedEvent; @@ -76,7 +77,6 @@ import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -91,9 +91,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView.TaskViewCallbacks, TaskStackViewScroller.TaskStackViewScrollerCallbacks, ViewPool.ViewPoolConsumer<TaskView, Task> { - private final static String TAG = "TaskStackView"; - private final static boolean DEBUG = false; - private final static String KEY_SAVED_STATE_SUPER = "saved_instance_state_super"; private final static String KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE = "saved_instance_state_layout_focused_state"; @@ -105,6 +102,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal private static final float HIDE_HISTORY_BUTTON_SCROLL_THRESHOLD = 0.3f; private static final int DEFAULT_SYNC_STACK_DURATION = 200; + private static final int DRAG_SCALE_DURATION = 175; + private static final float DRAG_SCALE_FACTOR = 1.05f; public static final Property<Drawable, Integer> DRAWABLE_ALPHA = new IntProperty<Drawable>("drawableAlpha") { @@ -123,37 +122,34 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskStackLayoutAlgorithm mLayoutAlgorithm; TaskStackViewScroller mStackScroller; TaskStackViewTouchHandler mTouchHandler; + TaskStackAnimationHelper mAnimationHelper; GradientDrawable mFreeformWorkspaceBackground; ObjectAnimator mFreeformWorkspaceBackgroundAnimator; ViewPool<TaskView, Task> mViewPool; + + ArrayList<TaskView> mTaskViews = new ArrayList<>(); ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>(); + TaskViewAnimation mDeferredTaskViewUpdateAnimation = null; + DozeTrigger mUIDozeTrigger; Task mFocusedTask; - // Optimizations - int mStackViewsAnimationDuration; + int mTaskCornerRadiusPx; - boolean mStackViewsDirty = true; - boolean mStackViewsClipDirty = true; + + boolean mTaskViewsClipDirty = true; boolean mAwaitingFirstLayout = true; boolean mEnterAnimationComplete = false; - boolean mStartEnterAnimationRequestedAfterLayout; - ViewAnimation.TaskViewEnterContext mStartEnterAnimationContext; + boolean mTouchExplorationEnabled; + boolean mScreenPinningEnabled; Rect mTaskStackBounds = new Rect(); int[] mTmpVisibleRange = new int[2]; Rect mTmpRect = new Rect(); - RectF mTmpTaskRect = new RectF(); - TaskViewTransform mTmpStackBackTransform = new TaskViewTransform(); - TaskViewTransform mTmpStackFrontTransform = new TaskViewTransform(); HashMap<Task, TaskView> mTmpTaskViewMap = new HashMap<>(); - ArrayList<TaskView> mTaskViews = new ArrayList<>(); - List<TaskView> mImmutableTaskViews = new ArrayList<>(); List<TaskView> mTmpTaskViews = new ArrayList<>(); + TaskViewTransform mTmpTransform = new TaskViewTransform(); LayoutInflater mInflater; - boolean mTouchExplorationEnabled; - boolean mScreenPinningEnabled; - Interpolator mFastOutSlowInInterpolator; // A convenience update listener to request updating clipping of tasks @@ -161,7 +157,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - requestUpdateStackViewsClip(); + mTaskViewsClipDirty = true; + invalidate(); } }; @@ -189,10 +186,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal setStack(stack); mViewPool = new ViewPool<>(context, this); mInflater = LayoutInflater.from(context); - mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, this); + mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context); mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm); mStackScroller.setCallbacks(this); mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller); + mAnimationHelper = new TaskStackAnimationHelper(context, this); mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.fast_out_slow_in); mTaskCornerRadiusPx = res.getDimensionPixelSize( @@ -265,12 +263,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mTaskViews.add((TaskView) v); } } - mImmutableTaskViews = Collections.unmodifiableList(mTaskViews); } /** Gets the list of task views */ List<TaskView> getTaskViews() { - return mImmutableTaskViews; + return mTaskViews; } /** @@ -329,44 +326,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Reset the stack state mStack.reset(); - mStackViewsDirty = true; - mStackViewsClipDirty = true; + mTaskViewsClipDirty = true; mAwaitingFirstLayout = true; mEnterAnimationComplete = false; - if (mUIDozeTrigger != null) { - mUIDozeTrigger.stopDozing(); - mUIDozeTrigger.resetTrigger(); - } + mUIDozeTrigger.stopDozing(); + mUIDozeTrigger.resetTrigger(); mStackScroller.reset(); mLayoutAlgorithm.reset(); requestLayout(); } - /** Requests that the views be synchronized with the model */ - void requestSynchronizeStackViewsWithModel() { - requestSynchronizeStackViewsWithModel(0); - } - void requestSynchronizeStackViewsWithModel(int duration) { - if (!mStackViewsDirty) { - invalidate(); - mStackViewsDirty = true; - } - if (mAwaitingFirstLayout) { - // Skip the animation if we are awaiting first layout - mStackViewsAnimationDuration = 0; - } else { - mStackViewsAnimationDuration = Math.max(mStackViewsAnimationDuration, duration); - } - } - - /** Requests that the views clipping be updated. */ - void requestUpdateStackViewsClip() { - if (!mStackViewsClipDirty) { - invalidate(); - mStackViewsClipDirty = true; - } - } - /** Returns the stack algorithm for this task stack. */ public TaskStackLayoutAlgorithm getStackAlgorithm() { return mLayoutAlgorithm; @@ -400,15 +369,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskViewTransform frontTransform = null; for (int i = taskCount - 1; i >= 0; i--) { Task task = tasks.get(i); + TaskViewTransform transform = mLayoutAlgorithm.getStackTransform(task, stackScroll, + taskTransforms.get(i), frontTransform); + + // For freeform tasks, only calculate the stack transform and skip the calculation of + // the visible stack indices if (task.isFreeformTask()) { continue; } - TaskViewTransform transform = mLayoutAlgorithm.getStackTransform(task, stackScroll, - taskTransforms.get(i), frontTransform); - if (DEBUG) { - Log.d(TAG, "updateStackTransform: " + i + ", " + transform.visible); - } if (transform.visible) { if (frontMostVisibleIndex < 0) { frontMostVisibleIndex = i; @@ -434,144 +403,155 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return frontMostVisibleIndex != -1 && backMostVisibleIndex != -1; } - /** Synchronizes the views with the model */ - boolean synchronizeStackViewsWithModel() { - if (mStackViewsDirty) { - // Get all the task transforms - ArrayList<Task> tasks = mStack.getStackTasks(); - float stackScroll = mStackScroller.getStackScroll(); - int[] visibleStackRange = mTmpVisibleRange; - boolean isValidVisibleStackRange = updateStackTransforms(mCurrentTaskTransforms, tasks, - stackScroll, visibleStackRange); - boolean hasStackBackTransform = false; - boolean hasStackFrontTransform = false; - if (DEBUG) { - Log.d(TAG, "visibleRange: " + visibleStackRange[0] + " to " + visibleStackRange[1]); - } + /** + * Updates the children {@link TaskView}s to match the tasks in the current {@link TaskStack}. + * This call does not update the {@link TaskView}s to their position in the layout except when + * they are initially picked up from the pool, when they will be placed in a suitable initial + * position. + */ + private void bindTaskViewsWithStack() { + final float stackScroll = mStackScroller.getStackScroll(); + final int[] visibleStackRange = mTmpVisibleRange; + + // Get all the task transforms + final ArrayList<Task> tasks = mStack.getStackTasks(); + final boolean isValidVisibleStackRange = updateStackTransforms(mCurrentTaskTransforms, tasks, + stackScroll, visibleStackRange); + + // Return all the invisible children to the pool + mTmpTaskViewMap.clear(); + final List<TaskView> taskViews = getTaskViews(); + final int taskViewCount = taskViews.size(); + int lastFocusedTaskIndex = -1; + for (int i = taskViewCount - 1; i >= 0; i--) { + final TaskView tv = taskViews.get(i); + final Task task = tv.getTask(); + final int taskIndex = mStack.indexOfStackTask(task); - // Return all the invisible children to the pool - mTmpTaskViewMap.clear(); - List<TaskView> taskViews = getTaskViews(); - int lastFocusedTaskIndex = -1; - int taskViewCount = taskViews.size(); - for (int i = taskViewCount - 1; i >= 0; i--) { - TaskView tv = taskViews.get(i); - Task task = tv.getTask(); - int taskIndex = mStack.indexOfStackTask(task); - if (task.isFreeformTask() || - visibleStackRange[1] <= taskIndex && taskIndex <= visibleStackRange[0]) { - mTmpTaskViewMap.put(task, tv); - } else { - if (mTouchExplorationEnabled) { - lastFocusedTaskIndex = taskIndex; - resetFocusedTask(task); - } - if (DEBUG) { - Log.d(TAG, "returning to pool: " + task.key); - } - mViewPool.returnViewToPool(tv); + if (task.isFreeformTask() || + visibleStackRange[1] <= taskIndex && taskIndex <= visibleStackRange[0]) { + mTmpTaskViewMap.put(task, tv); + } else { + if (mTouchExplorationEnabled) { + lastFocusedTaskIndex = taskIndex; + resetFocusedTask(task); } + mViewPool.returnViewToPool(tv); } + } - // Pick up all the freeform tasks - int firstVisStackIndex = isValidVisibleStackRange ? visibleStackRange[0] : 0; - for (int i = mStack.getStackTaskCount() - 1; i >= firstVisStackIndex; i--) { - Task task = tasks.get(i); - if (!task.isFreeformTask()) { - continue; - } - TaskViewTransform transform = mLayoutAlgorithm.getStackTransform(task, stackScroll, - mCurrentTaskTransforms.get(i), null); - TaskView tv = mTmpTaskViewMap.get(task); - if (tv == null) { - if (DEBUG) { - Log.d(TAG, "picking up from pool: " + task.key); - } - tv = mViewPool.pickUpViewFromPool(task, task); - } else { - // Reattach it in the right z order - int taskIndex = mStack.indexOfStackTask(task); - int insertIndex = findTaskViewInsertIndex(task, taskIndex); - if (insertIndex != getTaskViews().indexOf(tv)){ - detachViewFromParent(tv); - attachViewToParent(tv, insertIndex, tv.getLayoutParams()); - } - } - - // Animate the task into place - tv.updateViewPropertiesToTaskTransform(transform, 0, - mStackViewsAnimationDuration, mFastOutSlowInInterpolator, - mRequestUpdateClippingListener); + // Pick up all the newly visible children + int lastVisStackIndex = isValidVisibleStackRange ? visibleStackRange[1] : 0; + for (int i = mStack.getStackTaskCount() - 1; i >= lastVisStackIndex; i--) { + final Task task = tasks.get(i); + final TaskViewTransform transform = mCurrentTaskTransforms.get(i); - // Update the task views list after adding the new task view - updateTaskViewsList(); + // Skip the invisible non-freeform stack tasks + if (i > visibleStackRange[0] && !task.isFreeformTask()) { + continue; } - // Pick up all the newly visible children and update all the existing children - for (int i = visibleStackRange[0]; - isValidVisibleStackRange && i >= visibleStackRange[1]; i--) { - Task task = tasks.get(i); - TaskViewTransform transform = mCurrentTaskTransforms.get(i); - TaskView tv = mTmpTaskViewMap.get(task); - - if (tv == null) { - tv = mViewPool.pickUpViewFromPool(task, task); - if (mStackViewsAnimationDuration > 0) { - // For items in the list, put them in start animating them from the - // approriate ends of the list where they are expected to appear - if (Float.compare(transform.p, 0f) <= 0) { - if (!hasStackBackTransform) { - hasStackBackTransform = true; - mLayoutAlgorithm.getStackTransform( - mLayoutAlgorithm.getStackBackTaskProgress(0f), 0f, - mTmpStackBackTransform, null); - } - tv.updateViewPropertiesToTaskTransform(mTmpStackBackTransform, 0, 0, - mFastOutSlowInInterpolator, mRequestUpdateClippingListener); - } else { - if (!hasStackFrontTransform) { - hasStackFrontTransform = true; - mLayoutAlgorithm.getStackTransform( - mLayoutAlgorithm.getStackFrontTaskProgress(0f), 0f, - mTmpStackFrontTransform, null); - } - tv.updateViewPropertiesToTaskTransform(mTmpStackFrontTransform, 0, 0, - mFastOutSlowInInterpolator, mRequestUpdateClippingListener); - } + TaskView tv = mTmpTaskViewMap.get(task); + if (tv == null) { + tv = mViewPool.pickUpViewFromPool(task, task); + if (task.isFreeformTask()) { + tv.updateViewPropertiesToTaskTransform(transform, TaskViewAnimation.IMMEDIATE, + mRequestUpdateClippingListener); + } else { + if (Float.compare(transform.p, 0f) <= 0) { + tv.updateViewPropertiesToTaskTransform( + mLayoutAlgorithm.getBackOfStackTransform(), + TaskViewAnimation.IMMEDIATE, mRequestUpdateClippingListener); + } else { + tv.updateViewPropertiesToTaskTransform( + mLayoutAlgorithm.getFrontOfStackTransform(), + TaskViewAnimation.IMMEDIATE, mRequestUpdateClippingListener); } } - - // Animate the task into place, the clip for stack tasks will be calculated in - // clipTaskViews() - tv.updateViewPropertiesToTaskTransform(transform, - tv.getViewBounds().getClipBottom(), mStackViewsAnimationDuration, - mFastOutSlowInInterpolator, mRequestUpdateClippingListener); + } else { + // Reattach it in the right z order + final int taskIndex = mStack.indexOfStackTask(task); + final int insertIndex = findTaskViewInsertIndex(task, taskIndex); + if (insertIndex != getTaskViews().indexOf(tv)){ + detachViewFromParent(tv); + attachViewToParent(tv, insertIndex, tv.getLayoutParams()); + updateTaskViewsList(); + } } + } - // Update the focus if the previous focused task was returned to the view pool - if (lastFocusedTaskIndex != -1) { - if (lastFocusedTaskIndex < visibleStackRange[1]) { - setFocusedTask(visibleStackRange[1], false /* animated */, - true /* requestViewFocus */); - } else { - setFocusedTask(visibleStackRange[0], false /* animated */, - true /* requestViewFocus */); - } + // Update the focus if the previous focused task was returned to the view pool + if (lastFocusedTaskIndex != -1) { + if (lastFocusedTaskIndex < visibleStackRange[1]) { + setFocusedTask(visibleStackRange[1], false /* scrollToTask */, + true /* requestViewFocus */); + } else { + setFocusedTask(visibleStackRange[0], false /* scrollToTask */, + true /* requestViewFocus */); } + } + } - // Reset the request-synchronize params - mStackViewsAnimationDuration = 0; - mStackViewsDirty = false; - mStackViewsClipDirty = true; - return true; + /** + * Cancels any existing {@link TaskView} animations, and updates each {@link TaskView} to its + * current position as defined by the {@link TaskStackLayoutAlgorithm}. + */ + private void updateTaskViewsToLayout(TaskViewAnimation animation) { + // If we had a deferred animation, cancel that + mDeferredTaskViewUpdateAnimation = null; + + // Cancel all task view animations + cancelAllTaskViewAnimations(); + + // Fetch the current set of TaskViews + bindTaskViewsWithStack(); + + // Animate them to their final transforms with the given animation + List<TaskView> taskViews = getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = 0; i < taskViewCount; i++) { + final TaskView tv = taskViews.get(i); + final int taskIndex = mStack.indexOfStackTask(tv.getTask()); + final TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex); + + updateTaskViewToTransform(tv, transform, animation); + } + } + + /** + * Posts an update to synchronize the {@link TaskView}s with the stack on the next frame. + */ + private void updateTaskViewsToLayoutOnNextFrame(TaskViewAnimation animation) { + mDeferredTaskViewUpdateAnimation = animation; + postInvalidateOnAnimation(); + } + + /** + * Called to update a specific {@link TaskView} to a given {@link TaskViewTransform} with a + * given set of {@link TaskViewAnimation} properties. + */ + public void updateTaskViewToTransform(TaskView taskView, TaskViewTransform transform, + TaskViewAnimation animation) { + taskView.updateViewPropertiesToTaskTransform(transform, animation, + mRequestUpdateClippingListener); + } + + /** + * Cancels all {@link TaskView} animations. + */ + private void cancelAllTaskViewAnimations() { + List<TaskView> taskViews = getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = 0; i < taskViewCount; i++) { + final TaskView tv = taskViews.get(i); + tv.cancelTransformAnimation(); } - return false; } /** * Updates the clip for each of the task views from back to front. */ - void clipTaskViews(boolean forceUpdate) { + private void clipTaskViews() { RecentsConfiguration config = Recents.getConfiguration(); // Update the clip on each task child @@ -586,6 +566,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Find the next view to clip against for (int j = i + 1; j < taskViewCount; j++) { tmpTv = taskViews.get(j); + if (tmpTv.shouldClipViewInStack()) { frontTv = tmpTv; break; @@ -604,12 +585,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } } - tv.getViewBounds().setClipBottom(clipBottom, forceUpdate); + tv.getViewBounds().setClipBottom(clipBottom); if (!config.useHardwareLayers) { tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom()); } } - mStackViewsClipDirty = false; + mTaskViewsClipDirty = false; } /** Updates the min and max virtual scroll bounds */ @@ -640,16 +621,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal * * @return whether or not the stack will scroll as a part of this focus change */ - private boolean setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated) { - return setFocusedTask(taskIndex, scrollToTask, animated, true); - } - - /** - * Sets the focused task to the provided (bounded taskIndex). - * - * @return whether or not the stack will scroll as a part of this focus change - */ - private boolean setFocusedTask(int taskIndex, boolean scrollToTask, final boolean animated, + private boolean setFocusedTask(int taskIndex, boolean scrollToTask, final boolean requestViewFocus) { // Find the next task to focus int newFocusedTaskIndex = mStack.getStackTaskCount() > 0 ? @@ -670,7 +642,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public void run() { TaskView tv = getChildViewForTask(newFocusedTask); if (tv != null) { - tv.setFocusedState(true, animated, requestViewFocus); + tv.setFocusedState(true, requestViewFocus); } } }; @@ -685,10 +657,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Cancel any running enter animations at this point when we scroll as well if (!mEnterAnimationComplete) { - final List<TaskView> taskViews = getTaskViews(); - for (TaskView tv : taskViews) { - tv.cancelEnterRecentsAnimation(); - } + cancelAllTaskViewAnimations(); } } else { focusTaskRunnable.run(); @@ -763,7 +732,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } if (newIndex != -1) { - boolean willScroll = setFocusedTask(newIndex, true, animated); + boolean willScroll = setFocusedTask(newIndex, true /* scrollToTask */, + true /* requestViewFocus */); if (willScroll && cancelWindowAnimations) { // As we iterate to the next/previous task, cancel any current/lagging window // transition animations @@ -779,7 +749,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (task != null) { TaskView tv = getChildViewForTask(task); if (tv != null) { - tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */); + tv.setFocusedState(false, false /* requestViewFocus */); } } mFocusedTask = null; @@ -884,12 +854,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void computeScroll() { - mStackScroller.computeScroll(); - // Synchronize the views - synchronizeStackViewsWithModel(); - clipTaskViews(false /* forceUpdate */); - // Notify accessibility - sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); + if (mStackScroller.computeScroll()) { + // Notify accessibility + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SCROLLED); + } + if (mDeferredTaskViewUpdateAnimation != null) { + updateTaskViewsToLayout(mDeferredTaskViewUpdateAnimation); + mTaskViewsClipDirty = true; + mDeferredTaskViewUpdateAnimation = null; + } + if (mTaskViewsClipDirty) { + clipTaskViews(); + } } /** Computes the stack and task rects */ @@ -936,13 +912,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Compute our stack/task rects computeRects(mTaskStackBounds); - // If this is the first layout, then scroll to the front of the stack and synchronize the - // stack views immediately to load all the views + // If this is the first layout, then scroll to the front of the stack, then update the + // TaskViews with the stack so that we can lay them out if (mAwaitingFirstLayout) { mStackScroller.setStackScrollToInitialState(); - requestSynchronizeStackViewsWithModel(); - synchronizeStackViewsWithModel(); } + bindTaskViewsWithStack(); // Measure each of the TaskViews mTmpTaskViews.clear(); @@ -992,52 +967,25 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom); } - if (mAwaitingFirstLayout) { - mAwaitingFirstLayout = false; - onFirstLayout(); - } - - requestSynchronizeStackViewsWithModel(); if (changed) { if (mStackScroller.isScrollOutOfBounds()) { mStackScroller.boundScroll(); } - synchronizeStackViewsWithModel(); - requestUpdateStackViewsClip(); - clipTaskViews(true /* forceUpdate */); + } + updateTaskViewsToLayout(TaskViewAnimation.IMMEDIATE); + clipTaskViews(); + + if (mAwaitingFirstLayout || !mEnterAnimationComplete) { + mAwaitingFirstLayout = false; + onFirstLayout(); + return; } } /** Handler for the first layout. */ void onFirstLayout() { - int offscreenY = mLayoutAlgorithm.mStackRect.bottom; - - // Find the launch target task - Task launchTargetTask = mStack.getLaunchTarget(); - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); - - // Prepare the first view for its enter animation - for (int i = taskViewCount - 1; i >= 0; i--) { - TaskView tv = taskViews.get(i); - Task task = tv.getTask(); - boolean hideTask = false; - boolean occludesLaunchTarget = false; - if (launchTargetTask != null) { - occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(task, - launchTargetTask); - hideTask = launchTargetTask.isFreeformTask() && task.isFreeformTask(); - } - tv.prepareEnterRecentsAnimation(hideTask, occludesLaunchTarget, offscreenY); - } - - // If the enter animation started already and we haven't completed a layout yet, do the - // enter animation now - if (mStartEnterAnimationRequestedAfterLayout) { - startEnterRecentsAnimation(mStartEnterAnimationContext); - mStartEnterAnimationRequestedAfterLayout = false; - mStartEnterAnimationContext = null; - } + // Setup the view for the enter animation + mAnimationHelper.prepareForEnterAnimation(); // Animate in the freeform workspace animateFreeformWorkspaceBackgroundAlpha( @@ -1050,7 +998,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal RecentsActivityLaunchState launchState = config.getLaunchState(); int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getStackTaskCount()); if (focusedTaskIndex != -1) { - setFocusedTask(focusedTaskIndex, false /* scrollToTask */, false /* animated */, + setFocusedTask(focusedTaskIndex, false /* scrollToTask */, false /* requestViewFocus */); } @@ -1061,102 +1009,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } else { EventBus.getDefault().send(new HideHistoryButtonEvent()); } - - // Start dozing - mUIDozeTrigger.startDozing(); - } - - /** Requests this task stacks to start it's enter-recents animation */ - public void startEnterRecentsAnimation(ViewAnimation.TaskViewEnterContext ctx) { - // If we are still waiting to layout, then just defer until then - if (mAwaitingFirstLayout) { - mStartEnterAnimationRequestedAfterLayout = true; - mStartEnterAnimationContext = ctx; - return; - } - - if (mStack.getStackTaskCount() > 0) { - // Find the launch target task - Task launchTargetTask = mStack.getLaunchTarget(); - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); - - // Animate all the task views into view - for (int i = taskViewCount - 1; i >= 0; i--) { - TaskView tv = taskViews.get(i); - Task task = tv.getTask(); - ctx.currentTaskTransform = new TaskViewTransform(); - ctx.currentStackViewIndex = i; - ctx.currentStackViewCount = taskViewCount; - ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect; - ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) && - launchTargetTask.group.isTaskAboveTask(task, launchTargetTask); - ctx.isScreenPinningEnabled = mScreenPinningEnabled; - ctx.updateListener = mRequestUpdateClippingListener; - mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(), - ctx.currentTaskTransform, null); - tv.startEnterRecentsAnimation(ctx); - } - - // Add a runnable to the post animation ref counter to clear all the views - ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() { - @Override - public void run() { - // Poke the dozer to restart the trigger after the animation completes - mUIDozeTrigger.poke(); - - // Update the focused state here -- since we only set the focused task without - // requesting view focus in onFirstLayout(), actually request view focus and - // animate the focused state if we are alt-tabbing now, after the window enter - // animation is completed - if (mFocusedTask != null) { - RecentsConfiguration config = Recents.getConfiguration(); - RecentsActivityLaunchState launchState = config.getLaunchState(); - setFocusedTask(mStack.indexOfStackTask(mFocusedTask), - false /* scrollToTask */, launchState.launchedWithAltTab); - } - } - }); - } - } - - /** Requests this task stack to start it's exit-recents animation. */ - public void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { - // Stop any scrolling - mStackScroller.stopScroller(); - mStackScroller.stopBoundScrollAnimation(); - // Animate all the task views out of view - ctx.offscreenTranslationY = mLayoutAlgorithm.mStackRect.bottom; - // Dismiss the freeform workspace background - int taskViewExitToHomeDuration = getResources().getInteger( - R.integer.recents_task_exit_to_home_duration); - animateFreeformWorkspaceBackgroundAlpha(0, taskViewExitToHomeDuration, - mFastOutSlowInInterpolator); - - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); - for (int i = 0; i < taskViewCount; i++) { - TaskView tv = taskViews.get(i); - tv.startExitToHomeAnimation(ctx); - } - } - - /** Animates a task view in this stack as it launches. */ - public void startLaunchTaskAnimation(TaskView tv, Runnable r, boolean lockToTask) { - Task launchTargetTask = tv.getTask(); - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); - for (int i = 0; i < taskViewCount; i++) { - TaskView t = taskViews.get(i); - if (t == tv) { - t.setClipViewInStack(false); - t.startLaunchTaskAnimation(r, true, true, lockToTask); - } else { - boolean occludesLaunchTarget = launchTargetTask.group.isTaskAboveTask(t.getTask(), - launchTargetTask); - t.startLaunchTaskAnimation(null, false, occludesLaunchTarget, lockToTask); - } - } } public boolean isTransformedTouchPointInView(float x, float y, TaskView tv) { @@ -1194,11 +1046,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal * Launches the freeform tasks. */ public boolean launchFreeformTasks() { - Task frontTask = mStack.getStackFrontMostTask(); - if (frontTask != null && frontTask.isFreeformTask()) { - EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask), - frontTask, null, INVALID_STACK_ID, false)); - return true; + ArrayList<Task> tasks = mStack.getFreeformTasks(); + if (!tasks.isEmpty()) { + Task frontTask = tasks.get(tasks.size() - 1); + if (frontTask != null && frontTask.isFreeformTask()) { + EventBus.getDefault().send(new LaunchTaskEvent(getChildViewForTask(frontTask), + frontTask, null, INVALID_STACK_ID, false)); + return true; + } } return false; } @@ -1211,7 +1066,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal updateLayout(true); // Animate all the tasks into place - requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION); + updateTaskViewsToLayout(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, + mFastOutSlowInInterpolator)); } @Override @@ -1258,9 +1114,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mStackScroller.setStackScroll(mStackScroller.getStackScroll() + stackScrollOffset); mStackScroller.boundScroll(); } - - // Animate all the tasks into place - requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION); } else { // Remove the view associated with this task, we can't rely on updateTransforms // to work here because the task is no longer in the list @@ -1271,11 +1124,12 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Update the min/max scroll and animate other task views into their new positions updateLayout(true); - - // Animate all the tasks into place - requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION); } + // Animate all the tasks into place + updateTaskViewsToLayout(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, + mFastOutSlowInInterpolator)); + // Update the new front most task's action button if (mScreenPinningEnabled && newFrontMostTask != null) { TaskView frontTv = getChildViewForTask(newFrontMostTask); @@ -1319,19 +1173,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Reset the view properties and view state tv.resetViewProperties(); - tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */); + tv.setFocusedState(false, false /* requestViewFocus */); tv.setClipViewInStack(false); if (mScreenPinningEnabled) { - tv.hideActionButton(); + tv.hideActionButton(false /* fadeOut */, 0 /* duration */, false /* scaleDown */, null); } } @Override public void prepareViewToLeavePool(TaskView tv, Task task, boolean isNewView) { - // It is possible for a view to be returned to the view pool before it is laid out, - // which means that we will need to relayout the view when it is first used next. - boolean requiresRelayout = tv.getWidth() <= 0 && !isNewView; - // Rebind the task and request that this task's data be filled into the TaskView tv.onTaskBound(task); @@ -1350,9 +1200,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal addView(tv, insertIndex); } else { attachViewToParent(tv, insertIndex, tv.getLayoutParams()); - if (requiresRelayout) { - tv.requestLayout(); - } } // Update the task views list after adding the new task view updateTaskViewsList(); @@ -1362,7 +1209,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal tv.setTouchEnabled(true); tv.setClipViewInStack(true); if (mFocusedTask == task) { - tv.setFocusedState(true, false /* animated */, false /* requestViewFocus */); + tv.setFocusedState(true, false /* requestViewFocus */); } // Restore the action button visibility if it is the front most task view @@ -1380,16 +1227,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @Override public void onTaskViewClipStateChanged(TaskView tv) { - requestUpdateStackViewsClip(); + clipTaskViews(); } /**** TaskStackViewScroller.TaskStackViewScrollerCallbacks ****/ @Override - public void onScrollChanged(float prevScroll, float curScroll) { + public void onScrollChanged(float prevScroll, float curScroll, TaskViewAnimation animation) { mUIDozeTrigger.poke(); - requestSynchronizeStackViewsWithModel(); - postInvalidateOnAnimation(); + updateTaskViewsToLayoutOnNextFrame(animation); if (shouldShowHistoryButton() && prevScroll > SHOW_HISTORY_BUTTON_SCROLL_THRESHOLD && @@ -1416,12 +1262,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal final TaskView tv = getChildViewForTask(t); if (tv != null) { // For visible children, defer removing the task until after the animation - tv.startDeleteTaskAnimation(new Runnable() { - @Override - public void run() { - removeTaskViewFromStack(tv); - } - }, 0); + tv.dismissTask(); } else { // Otherwise, remove the task from the stack immediately mStack.removeTask(t); @@ -1435,17 +1276,24 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mUIDozeTrigger.stopDozing(); } - public final void onBusEvent(DismissTaskViewEvent event) { - removeTaskViewFromStack(event.taskView); - EventBus.getDefault().send(new DismissTaskEvent(event.task)); + public final void onBusEvent(LaunchTaskStartedEvent event) { + mAnimationHelper.startLaunchTaskAnimation(event.taskView, event.screenPinningRequested, + event.getAnimationTrigger()); } - public final void onBusEvent(FocusNextTaskViewEvent event) { - setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */); - } + public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) { + // Stop any scrolling + mStackScroller.stopScroller(); + mStackScroller.stopBoundScrollAnimation(); - public final void onBusEvent(FocusPreviousTaskViewEvent event) { - setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */); + // Start the task animations + mAnimationHelper.startExitToHomeAnimation(event.animated, event.getAnimationTrigger()); + + // Dismiss the freeform workspace background + int taskViewExitToHomeDuration = getResources().getInteger( + R.integer.recents_task_exit_to_home_duration); + animateFreeformWorkspaceBackgroundAlpha(0, taskViewExitToHomeDuration, + mFastOutSlowInInterpolator); } public final void onBusEvent(DismissFocusedTaskViewEvent event) { @@ -1458,6 +1306,25 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } + public final void onBusEvent(final DismissTaskViewEvent event) { + // For visible children, defer removing the task until after the animation + mAnimationHelper.startDeleteTaskAnimation(event.task, event.taskView, + event.getAnimationTrigger()); + } + + public final void onBusEvent(TaskViewDismissedEvent event) { + removeTaskViewFromStack(event.taskView); + EventBus.getDefault().send(new DeleteTaskDataEvent(event.task)); + } + + public final void onBusEvent(FocusNextTaskViewEvent event) { + setRelativeFocusedTask(true, false /* stackTasksOnly */, true /* animated */); + } + + public final void onBusEvent(FocusPreviousTaskViewEvent event) { + setRelativeFocusedTask(false, false /* stackTasksOnly */, true /* animated */); + } + public final void onBusEvent(UserInteractionEvent event) { // Poke the doze trigger on user interaction mUIDozeTrigger.poke(); @@ -1475,6 +1342,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mStackScroller.animateScroll(mStackScroller.getStackScroll(), mLayoutAlgorithm.mInitialScrollP, null); } + + // Enlarge the dragged view slightly + float finalScale = event.taskView.getScaleX() * DRAG_SCALE_FACTOR; + mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(), + mTmpTransform, null); + mTmpTransform.scale = finalScale; + updateTaskViewToTransform(event.taskView, mTmpTransform, + new TaskViewAnimation(DRAG_SCALE_DURATION, mFastOutSlowInInterpolator)); } public final void onBusEvent(DragStartInitializeDropTargetsEvent event) { @@ -1520,8 +1395,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } }); } - event.getAnimationTrigger().increment(); - event.taskView.animate().withEndAction(event.getAnimationTrigger().decrementAsRunnable()); // We translated the view but we need to animate it back from the current layout-space rect // to its final layout-space rect @@ -1535,8 +1408,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top, taskViewRect.right, taskViewRect.bottom); - // Animate the tack view back into position - requestSynchronizeStackViewsWithModel(250); + // Animate all the TaskViews back into position + mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(), + mTmpTransform, null); + event.getAnimationTrigger().increment(); + updateTaskViewsToLayout(new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, + mFastOutSlowInInterpolator)); + updateTaskViewToTransform(event.taskView, mTmpTransform, + new TaskViewAnimation(DEFAULT_SYNC_STACK_DURATION, mFastOutSlowInInterpolator, + event.getAnimationTrigger().decrementOnAnimationEnd())); } public final void onBusEvent(StackViewScrolledEvent event) { @@ -1548,11 +1428,35 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Cancel the previous task's window transition before animating the focused state EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null)); } - mLayoutAlgorithm.animateFocusState(mLayoutAlgorithm.getDefaultFocusState()); } public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) { mEnterAnimationComplete = true; + + if (mStack.getStackTaskCount() > 0) { + // Start the task enter animations + mAnimationHelper.startEnterAnimation(event.getAnimationTrigger()); + + // Add a runnable to the post animation ref counter to clear all the views + event.addPostAnimationCallback(new Runnable() { + @Override + public void run() { + // Start the dozer to trigger to trigger any UI that shows after a timeout + mUIDozeTrigger.startDozing(); + + // Update the focused state here -- since we only set the focused task without + // requesting view focus in onFirstLayout(), actually request view focus and + // animate the focused state if we are alt-tabbing now, after the window enter + // animation is completed + if (mFocusedTask != null) { + RecentsConfiguration config = Recents.getConfiguration(); + RecentsActivityLaunchState launchState = config.getLaunchState(); + setFocusedTask(mStack.indexOfStackTask(mFocusedTask), + false /* scrollToTask */, launchState.launchedWithAltTab); + } + } + }); + } } public final void onBusEvent(UpdateFreeformTaskViewVisibilityEvent event) { @@ -1568,48 +1472,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } public final void onBusEvent(ShowHistoryEvent event) { - // The history view's animation will be deferred until all the stack task views are animated - // away - int historyTransitionDuration = - getResources().getInteger(R.integer.recents_history_transition_duration); - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); - for (int i = taskViewCount - 1; i >= 0; i--) { - TaskView tv = taskViews.get(i); - tv.animate() - .alpha(0f) - .setDuration(historyTransitionDuration) - .setUpdateListener(null) - .setListener(null) - .withLayer() - .withEndAction(event.getAnimationTrigger().decrementAsRunnable()) - .start(); - event.getAnimationTrigger().increment(); - } + mAnimationHelper.startShowHistoryAnimation(event.getAnimationTrigger()); } public final void onBusEvent(HideHistoryEvent event) { - // The stack task view animations will be deferred until the history view has been animated - // away - final int historyTransitionDuration = - getResources().getInteger(R.integer.recents_history_transition_duration); - List<TaskView> taskViews = getTaskViews(); - int taskViewCount = taskViews.size(); - for (int i = taskViewCount - 1; i >= 0; i--) { - final TaskView tv = taskViews.get(i); - event.addPostAnimationCallback(new Runnable() { - @Override - public void run() { - tv.animate() - .alpha(1f) - .setDuration(historyTransitionDuration) - .setUpdateListener(null) - .setListener(null) - .withLayer() - .start(); - } - }); - } + mAnimationHelper.startHideHistoryAnimation(event.getAnimationTrigger()); } /** diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java index 56942a87e0f5..32f02acd9d77 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java @@ -34,7 +34,7 @@ public class TaskStackViewScroller { private static final boolean DEBUG = false; public interface TaskStackViewScrollerCallbacks { - void onScrollChanged(float prevScroll, float curScroll); + void onScrollChanged(float prevScroll, float curScroll, TaskViewAnimation animation); } Context mContext; @@ -57,7 +57,6 @@ public class TaskStackViewScroller { mLayoutAlgorithm = layoutAlgorithm; mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.linear_out_slow_in); - setStackScroll(getStackScroll()); } /** Resets the task scroller. */ @@ -75,12 +74,22 @@ public class TaskStackViewScroller { return mStackScrollP; } - /** Sets the current stack scroll */ + /** + * Sets the current stack scroll immediately. + */ public void setStackScroll(float s) { + setStackScroll(s, TaskViewAnimation.IMMEDIATE); + } + + /** + * Sets the current stack scroll, but indicates to the callback the preferred animation to + * update to this new scroll. + */ + public void setStackScroll(float s, TaskViewAnimation animation) { float prevStackScroll = mStackScrollP; mStackScrollP = s; if (mCb != null) { - mCb.onScrollChanged(prevStackScroll, mStackScrollP); + mCb.onScrollChanged(prevStackScroll, mStackScrollP, animation); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index 1a6f1294f36e..c748efcc842b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -33,8 +33,8 @@ import com.android.systemui.recents.Constants; import com.android.systemui.recents.Recents; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.HideRecentsEvent; -import com.android.systemui.recents.events.ui.DismissTaskViewEvent; import com.android.systemui.recents.events.ui.StackViewScrolledEvent; +import com.android.systemui.recents.events.ui.TaskViewDismissedEvent; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.statusbar.FlingAnimationUtils; @@ -295,6 +295,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { Rect freeformRect = mSv.mLayoutAlgorithm.mFreeformRect; if (freeformRect.top <= y && y <= freeformRect.bottom) { if (mSv.launchFreeformTasks()) { + // TODO: Animate Recents away as we launch the freeform tasks return; } } @@ -367,7 +368,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // Re-enable touch events from this task view tv.setTouchEnabled(true); // Remove the task view from the stack - EventBus.getDefault().send(new DismissTaskViewEvent(tv.getTask(), tv)); + EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv)); // Keep track of deletions by keyboard MetricsLogger.histogram(tv.getContext(), "overview_task_dismissed_source", Constants.Metrics.DismissSourceSwipeGesture); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 14909c50ef94..e8652f5b5d7b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -31,7 +31,9 @@ import android.graphics.PorterDuff; import android.graphics.PorterDuffColorFilter; import android.graphics.Rect; import android.util.AttributeSet; -import android.util.Log; +import android.util.FloatProperty; +import android.util.IntProperty; +import android.util.Property; import android.view.MotionEvent; import android.view.View; import android.view.ViewOutlineProvider; @@ -42,35 +44,64 @@ import android.widget.FrameLayout; import com.android.systemui.R; import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivity; -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.LaunchTaskEvent; import com.android.systemui.recents.events.ui.DismissTaskViewEvent; +import com.android.systemui.recents.events.ui.TaskViewDismissedEvent; import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent; import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent; +import com.android.systemui.recents.misc.ReferenceCountedTrigger; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import com.android.systemui.statusbar.phone.PhoneStatusBar; +import java.util.ArrayList; + import static android.app.ActivityManager.StackId.INVALID_STACK_ID; /* A task view */ public class TaskView extends FrameLayout implements Task.TaskCallbacks, - View.OnClickListener, View.OnLongClickListener { - - private final static String TAG = "TaskView"; - private final static boolean DEBUG = false; + TaskStackAnimationHelper.Callbacks, View.OnClickListener, View.OnLongClickListener { /** The TaskView callbacks */ interface TaskViewCallbacks { void onTaskViewClipStateChanged(TaskView tv); } + /** + * The dim overlay is generally calculated from the task progress, but occasionally (like when + * launching) needs to be animated independently of the task progress. + */ + public static final Property<TaskView, Integer> DIM = + new IntProperty<TaskView>("dim") { + @Override + public void setValue(TaskView tv, int dim) { + tv.setDim(dim); + } + + @Override + public Integer get(TaskView tv) { + return tv.getDim(); + } + }; + + public static final Property<TaskView, Float> TASK_PROGRESS = + new FloatProperty<TaskView>("taskProgress") { + @Override + public void setValue(TaskView tv, float p) { + tv.setTaskProgress(p); + } + + @Override + public Float get(TaskView tv) { + return tv.getTaskProgress(); + } + }; + float mTaskProgress; - ObjectAnimator mTaskProgressAnimator; float mMaxDimScale; int mDimAlpha; AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(3f); @@ -80,9 +111,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, Task mTask; boolean mTaskDataLoaded; - boolean mClipViewInStack; + boolean mClipViewInStack = true; AnimateableViewBounds mViewBounds; - private AnimatorSet mClipAnimation; + + private AnimatorSet mTransformAnimation; + private ArrayList<Animator> mTmpAnimators = new ArrayList<>(); View mContent; TaskViewThumbnail mThumbnailView; @@ -93,18 +126,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, Point mDownTouchPos = new Point(); Interpolator mFastOutSlowInInterpolator; - Interpolator mFastOutLinearInInterpolator; - Interpolator mQuintOutInterpolator; - - // Optimizations - ValueAnimator.AnimatorUpdateListener mUpdateDimListener = - new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - setTaskProgress((Float) animation.getAnimatedValue()); - } - }; - public TaskView(Context context) { this(context, null); @@ -123,17 +144,10 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, RecentsConfiguration config = Recents.getConfiguration(); Resources res = context.getResources(); mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f; - mClipViewInStack = true; mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize( R.dimen.recents_task_view_rounded_corners_radius)); mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, com.android.internal.R.interpolator.fast_out_slow_in); - mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.fast_out_linear_in); - mQuintOutInterpolator = AnimationUtils.loadInterpolator(context, - com.android.internal.R.interpolator.decelerate_quint); - setTaskProgress(getTaskProgress()); - setDim(getDim()); if (config.fakeShadows) { setBackground(new FakeShadowDrawable(res, config)); } @@ -227,294 +241,69 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, invalidateOutline(); } - /** Synchronizes this view's properties with the task's transform */ - void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int clipBottom, - int duration, Interpolator interpolator, - ValueAnimator.AnimatorUpdateListener updateCallback) { + void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, + TaskViewAnimation toAnimation, ValueAnimator.AnimatorUpdateListener updateCallback) { RecentsConfiguration config = Recents.getConfiguration(); - Utilities.cancelAnimationWithoutCallbacks(mClipAnimation); - - // Apply the transform - toTransform.applyToTaskView(this, duration, interpolator, false, - !config.fakeShadows, updateCallback); - - // Update the clipping - if (duration > 0) { - mClipAnimation = new AnimatorSet(); - mClipAnimation.playTogether( - ObjectAnimator.ofInt(mViewBounds, AnimateableViewBounds.CLIP_BOTTOM, - mViewBounds.getClipBottom(), clipBottom), - ObjectAnimator.ofInt(this, TaskViewTransform.LEFT, getLeft(), - (int) toTransform.rect.left), - ObjectAnimator.ofInt(this, TaskViewTransform.TOP, getTop(), - (int) toTransform.rect.top), - ObjectAnimator.ofInt(this, TaskViewTransform.RIGHT, getRight(), - (int) toTransform.rect.right), - ObjectAnimator.ofInt(this, TaskViewTransform.BOTTOM, getBottom(), - (int) toTransform.rect.bottom), - ObjectAnimator.ofFloat(mThumbnailView, TaskViewThumbnail.BITMAP_SCALE, - mThumbnailView.getBitmapScale(), toTransform.thumbnailScale)); - mClipAnimation.setStartDelay(toTransform.startDelay); - mClipAnimation.setDuration(duration); - mClipAnimation.setInterpolator(interpolator); - mClipAnimation.start(); - } else { - mViewBounds.setClipBottom(clipBottom, false /* forceUpdate */); - mThumbnailView.setBitmapScale(toTransform.thumbnailScale); - setLeftTopRightBottom((int) toTransform.rect.left, (int) toTransform.rect.top, - (int) toTransform.rect.right, (int) toTransform.rect.bottom); - } - if (!config.useHardwareLayers) { - mThumbnailView.updateThumbnailVisibility(clipBottom - getPaddingBottom()); - } + Utilities.cancelAnimation(mTransformAnimation); - // Update the task progress - Utilities.cancelAnimationWithoutCallbacks(mTaskProgressAnimator); - if (duration <= 0) { + // Compose the animations for the transform + mTmpAnimators.clear(); + boolean requiresHwLayers = toTransform.applyToTaskView(this, mTmpAnimators, toAnimation, + !config.fakeShadows); + if (toAnimation.isImmediate()) { + mThumbnailView.setBitmapScale(toTransform.thumbnailScale); setTaskProgress(toTransform.p); + if (toAnimation.listener != null) { + toAnimation.listener.onAnimationEnd(null); + } } else { - mTaskProgressAnimator = ObjectAnimator.ofFloat(this, "taskProgress", toTransform.p); - mTaskProgressAnimator.setDuration(duration); - mTaskProgressAnimator.addUpdateListener(mUpdateDimListener); - mTaskProgressAnimator.start(); + if (Float.compare(mThumbnailView.getBitmapScale(), toTransform.thumbnailScale) != 0) { + mTmpAnimators.add(ObjectAnimator.ofFloat(mThumbnailView, + TaskViewThumbnail.BITMAP_SCALE, mThumbnailView.getBitmapScale(), + toTransform.thumbnailScale)); + } + if (Float.compare(getTaskProgress(), toTransform.p) != 0) { + mTmpAnimators.add(ObjectAnimator.ofFloat(this, TASK_PROGRESS, getTaskProgress(), + toTransform.p)); + } + ValueAnimator updateCallbackAnim = ValueAnimator.ofInt(0, 1); + updateCallbackAnim.addUpdateListener(updateCallback); + mTmpAnimators.add(updateCallbackAnim); + + // Create the animator + mTransformAnimation = toAnimation.createAnimator(mTmpAnimators); + if (requiresHwLayers) { + setLayerType(View.LAYER_TYPE_HARDWARE, null); + mTransformAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + setLayerType(View.LAYER_TYPE_NONE, null); + } + }); + } + mTransformAnimation.start(); } } /** Resets this view's properties */ void resetViewProperties() { + Utilities.cancelAnimation(mTransformAnimation); setDim(0); setVisibility(View.VISIBLE); getViewBounds().reset(); TaskViewTransform.reset(this); - if (mActionButtonView != null) { - mActionButtonView.setScaleX(1f); - mActionButtonView.setScaleY(1f); - mActionButtonView.setAlpha(1f); - mActionButtonView.setTranslationZ(mActionButtonTranslationZ); - } - } - - /** Prepares this task view for the enter-recents animations. This is called earlier in the - * first layout because the actual animation into recents may take a long time. */ - void prepareEnterRecentsAnimation(boolean hideTask, boolean occludesLaunchTarget, - int offscreenY) { - RecentsConfiguration config = Recents.getConfiguration(); - RecentsActivityLaunchState launchState = config.getLaunchState(); - int initialDim = getDim(); - if (hideTask) { - setVisibility(View.INVISIBLE); - } else if (launchState.launchedHasConfigurationChanged) { - // Just load the views as-is - } else if (launchState.launchedFromAppWithThumbnail) { - if (mTask.isLaunchTarget) { - // Set the dim to 0 so we can animate it in - initialDim = 0; - // Hide the action button - mActionButtonView.setAlpha(0f); - } else if (occludesLaunchTarget) { - // Move the task view off screen (below) so we can animate it in - setTranslationY(offscreenY); - } - - } else if (launchState.launchedFromHome) { - // Move the task view off screen (below) so we can animate it in - setTranslationY(offscreenY); - setTranslationZ(0); - setScaleX(1f); - setScaleY(1f); - } - // Apply the current dim - setDim(initialDim); - } - - /** Animates this task view as it enters recents */ - void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) { - RecentsConfiguration config = Recents.getConfiguration(); - RecentsActivityLaunchState launchState = config.getLaunchState(); - Resources res = mContext.getResources(); - final TaskViewTransform transform = ctx.currentTaskTransform; - final int taskViewEnterFromAppDuration = res.getInteger( - R.integer.recents_task_enter_from_app_duration); - final int taskViewEnterFromHomeDuration = res.getInteger( - R.integer.recents_task_enter_from_home_duration); - final int taskViewEnterFromHomeStaggerDelay = res.getInteger( - R.integer.recents_task_enter_from_home_stagger_delay); - final int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( - R.dimen.recents_task_view_affiliate_group_enter_offset); - - if (launchState.launchedFromAppWithThumbnail) { - if (mTask.isLaunchTarget) { - ctx.postAnimationTrigger.increment(); - // Start the dim animation - animateDimToProgress(taskViewEnterFromAppDuration, - ctx.postAnimationTrigger.decrementOnAnimationEnd()); - - // Start the action button animation - if (ctx.isScreenPinningEnabled) { - showActionButton(true /* fadeIn */, - taskViewEnterFromAppDuration /* fadeInDuration */); - } - } else { - // Animate the task up if it was occluding the launch target - if (ctx.currentTaskOccludesLaunchTarget) { - setTranslationY(taskViewAffiliateGroupEnterOffset); - setAlpha(0f); - animate().alpha(1f) - .translationY(0) - .setUpdateListener(null) - .setListener(new AnimatorListenerAdapter() { - private boolean hasEnded; - - // We use the animation listener instead of withEndAction() to - // ensure that onAnimationEnd() is called when the animator is - // cancelled - @Override - public void onAnimationEnd(Animator animation) { - if (hasEnded) return; - ctx.postAnimationTrigger.decrement(); - hasEnded = true; - } - }) - .setInterpolator(mFastOutSlowInInterpolator) - .setDuration(taskViewEnterFromHomeDuration) - .start(); - ctx.postAnimationTrigger.increment(); - } - } - - } else if (launchState.launchedFromHome) { - // Animate the tasks up - int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1); - int delay = frontIndex * taskViewEnterFromHomeStaggerDelay; - - setScaleX(transform.scale); - setScaleY(transform.scale); - if (!config.fakeShadows) { - animate().translationZ(transform.translationZ); - } - animate() - .translationY(0) - .setStartDelay(delay) - .setUpdateListener(ctx.updateListener) - .setListener(new AnimatorListenerAdapter() { - private boolean hasEnded; - - // We use the animation listener instead of withEndAction() to ensure that - // onAnimationEnd() is called when the animator is cancelled - @Override - public void onAnimationEnd(Animator animation) { - if (hasEnded) return; - ctx.postAnimationTrigger.decrement(); - hasEnded = true; - } - }) - .setInterpolator(mQuintOutInterpolator) - .setDuration(taskViewEnterFromHomeDuration + - frontIndex * taskViewEnterFromHomeStaggerDelay) - .start(); - ctx.postAnimationTrigger.increment(); - } - } - public void cancelEnterRecentsAnimation() { - animate().cancel(); - } - - /** Animates this task view as it leaves recents by pressing home. */ - void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { - int taskViewExitToHomeDuration = getResources().getInteger( - R.integer.recents_task_exit_to_home_duration); - animate() - .translationY(ctx.offscreenTranslationY) - .setStartDelay(0) - .setUpdateListener(null) - .setListener(null) - .setInterpolator(mFastOutLinearInInterpolator) - .setDuration(taskViewExitToHomeDuration) - .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable()) - .start(); - ctx.postAnimationTrigger.increment(); - } - - /** Animates this task view as it exits recents */ - void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask, - boolean occludesLaunchTarget, boolean lockToTask) { - final int taskViewExitToAppDuration = mContext.getResources().getInteger( - R.integer.recents_task_exit_to_app_duration); - final int taskViewAffiliateGroupEnterOffset = mContext.getResources().getDimensionPixelSize( - R.dimen.recents_task_view_affiliate_group_enter_offset); - - if (isLaunchingTask) { - // Animate the dim - if (mDimAlpha > 0) { - ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0); - anim.setDuration(taskViewExitToAppDuration); - anim.setInterpolator(mFastOutLinearInInterpolator); - anim.start(); - } - - // Animate the action button away - if (!lockToTask) { - float toScale = 0.9f; - mActionButtonView.animate() - .scaleX(toScale) - .scaleY(toScale); - } - mActionButtonView.animate() - .alpha(0f) - .setStartDelay(0) - .setDuration(taskViewExitToAppDuration) - .setInterpolator(PhoneStatusBar.ALPHA_OUT) - .withEndAction(postAnimRunnable) - .withLayer() - .start(); - } else { - // Hide the dismiss button - mHeaderView.startLaunchTaskDismissAnimation(postAnimRunnable); - // If this is another view in the task grouping and is in front of the launch task, - // animate it away first - if (occludesLaunchTarget) { - animate().alpha(0f) - .translationY(getTranslationY() + taskViewAffiliateGroupEnterOffset) - .setStartDelay(0) - .setUpdateListener(null) - .setListener(null) - .setInterpolator(mFastOutLinearInInterpolator) - .setDuration(taskViewExitToAppDuration) - .start(); - } - } + mActionButtonView.setScaleX(1f); + mActionButtonView.setScaleY(1f); + mActionButtonView.setAlpha(1f); + mActionButtonView.setTranslationZ(mActionButtonTranslationZ); } - /** Animates the deletion of this task view */ - void startDeleteTaskAnimation(final Runnable r, int delay) { - int taskViewRemoveAnimDuration = getResources().getInteger( - R.integer.recents_animate_task_view_remove_duration); - int taskViewRemoveAnimTranslationXPx = getResources().getDimensionPixelSize( - R.dimen.recents_task_view_remove_anim_translation_x); - - // Disabling clipping with the stack while the view is animating away - setClipViewInStack(false); - - animate().translationX(taskViewRemoveAnimTranslationXPx) - .alpha(0f) - .setStartDelay(delay) - .setUpdateListener(null) - .setListener(null) - .setInterpolator(mFastOutSlowInInterpolator) - .setDuration(taskViewRemoveAnimDuration) - .withEndAction(new Runnable() { - @Override - public void run() { - if (r != null) { - r.run(); - } - - // Re-enable clipping with the stack (we will reuse this view) - setClipViewInStack(true); - } - }) - .start(); + /** + * Cancels any current transform animations. + */ + public void cancelTransformAnimation() { + Utilities.cancelAnimation(mTransformAnimation); } /** Enables/disables handling touch on this task view. */ @@ -541,12 +330,14 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, void dismissTask() { // Animate out the view and call the callback final TaskView tv = this; - startDeleteTaskAnimation(new Runnable() { + DismissTaskViewEvent dismissEvent = new DismissTaskViewEvent(tv, mTask); + dismissEvent.addPostAnimationCallback(new Runnable() { @Override public void run() { - EventBus.getDefault().send(new DismissTaskViewEvent(mTask, tv)); + EventBus.getDefault().send(new TaskViewDismissedEvent(mTask, tv)); } - }, 0); + }); + EventBus.getDefault().send(dismissEvent); } /** @@ -597,12 +388,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } } else { float dimAlpha = mDimAlpha / 255.0f; - if (mThumbnailView != null) { - mThumbnailView.setDimAlpha(dimAlpha); - } - if (mHeaderView != null) { - mHeaderView.setDimAlpha(dim); - } + mThumbnailView.setDimAlpha(dimAlpha); + mHeaderView.setDimAlpha(dim); } } @@ -612,18 +399,18 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } /** Animates the dim to the task progress. */ - void animateDimToProgress(int duration, Animator.AnimatorListener postAnimRunnable) { + void animateDimToProgress(int duration, Animator.AnimatorListener animListener) { // Animate the dim into view as well int toDim = getDimFromTaskProgress(); if (toDim != getDim()) { - ObjectAnimator anim = ObjectAnimator.ofInt(TaskView.this, "dim", toDim); + ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), toDim); anim.setDuration(duration); - if (postAnimRunnable != null) { - anim.addListener(postAnimRunnable); + if (animListener != null) { + anim.addListener(animListener); } anim.start(); } else { - postAnimRunnable.onAnimationEnd(null); + animListener.onAnimationEnd(null); } } @@ -644,14 +431,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** * Explicitly sets the focused state of this task. */ - public void setFocusedState(boolean isFocused, boolean animated, boolean requestViewFocus) { - if (DEBUG) { - Log.d(TAG, "setFocusedState: " + mTask.title + " focused: " + isFocused + - " animated: " + animated + " requestViewFocus: " + requestViewFocus + - " isFocused(): " + isFocused() + - " isAccessibilityFocused(): " + isAccessibilityFocused()); - } - + public void setFocusedState(boolean isFocused, boolean requestViewFocus) { SystemServicesProxy ssp = Recents.getSystemServices(); if (isFocused) { if (requestViewFocus && !isFocused()) { @@ -678,28 +458,101 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, if (fadeIn) { if (mActionButtonView.getAlpha() < 1f) { - mActionButtonView.setAlpha(0f); - mActionButtonView.animate().alpha(1f) + mActionButtonView.animate() + .alpha(1f) + .scaleX(1f) + .scaleY(1f) .setDuration(fadeInDuration) .setInterpolator(PhoneStatusBar.ALPHA_IN) .withLayer() .start(); } } else { + mActionButtonView.setScaleX(1f); + mActionButtonView.setScaleY(1f); mActionButtonView.setAlpha(1f); + mActionButtonView.setTranslationZ(mActionButtonTranslationZ); } } /** * Immediately hides the action button. + * + * @param fadeOut whether or not to animate the action button out. */ - public void hideActionButton() { - mActionButtonView.setVisibility(View.INVISIBLE); + public void hideActionButton(boolean fadeOut, int fadeOutDuration, boolean scaleDown, + final Animator.AnimatorListener animListener) { + if (fadeOut) { + if (mActionButtonView.getAlpha() > 0f) { + if (scaleDown) { + float toScale = 0.9f; + mActionButtonView.animate() + .scaleX(toScale) + .scaleY(toScale); + } + mActionButtonView.animate() + .alpha(0f) + .setDuration(fadeOutDuration) + .setInterpolator(PhoneStatusBar.ALPHA_OUT) + .withEndAction(new Runnable() { + @Override + public void run() { + if (animListener != null) { + animListener.onAnimationEnd(null); + } + mActionButtonView.setVisibility(View.INVISIBLE); + } + }) + .withLayer() + .start(); + } + } else { + mActionButtonView.setAlpha(0f); + mActionButtonView.setVisibility(View.INVISIBLE); + if (animListener != null) { + animListener.onAnimationEnd(null); + } + } + } + + /**** TaskStackAnimationHelper.Callbacks Implementation ****/ + + @Override + public void onPrepareLaunchTargetForEnterAnimation() { + // These values will be animated in when onStartLaunchTargetEnterAnimation() is called + setDim(0); + mActionButtonView.setAlpha(0f); + } + + @Override + public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled, + ReferenceCountedTrigger postAnimationTrigger) { + postAnimationTrigger.increment(); + animateDimToProgress(duration, postAnimationTrigger.decrementOnAnimationEnd()); + + if (screenPinningEnabled) { + showActionButton(true /* fadeIn */, duration /* fadeInDuration */); + } + } + + @Override + public void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested, + ReferenceCountedTrigger postAnimationTrigger) { + if (mDimAlpha > 0) { + ObjectAnimator anim = ObjectAnimator.ofInt(this, DIM, getDim(), 0); + anim.setDuration(duration); + anim.setInterpolator(PhoneStatusBar.ALPHA_OUT); + anim.start(); + } + + postAnimationTrigger.increment(); + hideActionButton(true /* fadeOut */, duration, + !screenPinningRequested /* scaleDown */, + postAnimationTrigger.decrementOnAnimationEnd()); } /**** TaskCallbacks Implementation ****/ - /** Binds this task view to the task */ public void onTaskBound(Task t) { mTask = t; mTask.addCallback(this); @@ -707,22 +560,18 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, @Override public void onTaskDataLoaded(Task task) { - if (mThumbnailView != null && mHeaderView != null) { - // Bind each of the views to the new task data - mThumbnailView.rebindToTask(mTask); - mHeaderView.rebindToTask(mTask); - } + // Bind each of the views to the new task data + mThumbnailView.rebindToTask(mTask); + mHeaderView.rebindToTask(mTask); mTaskDataLoaded = true; } @Override public void onTaskDataUnloaded() { - if (mThumbnailView != null && mHeaderView != null) { - // Unbind each of the views from the task data and remove the task callback - mTask.removeCallback(this); - mThumbnailView.unbindFromTask(); - mHeaderView.unbindFromTask(); - } + // Unbind each of the views from the task data and remove the task callback + mTask.removeCallback(this); + mThumbnailView.unbindFromTask(); + mHeaderView.unbindFromTask(); mTaskDataLoaded = false; } @@ -758,17 +607,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // Start listening for drag events setClipViewInStack(false); - // Enlarge the view slightly - final float finalScale = getScaleX() * 1.05f; - animate() - .scaleX(finalScale) - .scaleY(finalScale) - .setDuration(175) - .setUpdateListener(null) - .setListener(null) - .setInterpolator(mFastOutSlowInInterpolator) - .start(); - mDownTouchPos.x += ((1f - getScaleX()) * getWidth()) / 2; mDownTouchPos.y += ((1f - getScaleY()) * getHeight()) / 2; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java new file mode 100644 index 000000000000..363ad667bc7d --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAnimation.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package com.android.systemui.recents.views; + +import android.animation.Animator; +import android.animation.AnimatorSet; +import android.view.animation.Interpolator; +import android.view.animation.LinearInterpolator; + +import java.util.List; + +/** + * The animation properties to animate a {@link TaskView} to a given {@link TaskViewTransform}. + */ +public class TaskViewAnimation { + + public static final TaskViewAnimation IMMEDIATE = new TaskViewAnimation(0, + new LinearInterpolator()); + + public final int startDelay; + public final int duration; + public final Interpolator interpolator; + public final Animator.AnimatorListener listener; + + public TaskViewAnimation(int duration, Interpolator interpolator) { + this(0 /* startDelay */, duration, interpolator, null); + } + + public TaskViewAnimation(int duration, Interpolator interpolator, + Animator.AnimatorListener listener) { + this(0 /* startDelay */, duration, interpolator, listener); + } + + public TaskViewAnimation(int startDelay, int duration, Interpolator interpolator, + Animator.AnimatorListener listener) { + this.startDelay = startDelay; + this.duration = duration; + this.interpolator = interpolator; + this.listener = listener; + } + + /** + * Creates a new {@link AnimatorSet} that will animate the given animators with the current + * animation properties. + */ + public AnimatorSet createAnimator(List<Animator> animators) { + AnimatorSet anim = new AnimatorSet(); + anim.setStartDelay(startDelay); + anim.setDuration(duration); + anim.setInterpolator(interpolator); + if (listener != null) { + anim.addListener(listener); + } + anim.playTogether(animators); + return anim; + } + + /** + * Returns whether this animation has any duration. + */ + public boolean isImmediate() { + return duration <= 0; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index 9a2ffe712248..e8b7574b0ffb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -291,22 +291,6 @@ public class TaskViewHeader extends FrameLayout mMoveTaskButton.setOnClickListener(null); } - /** Animates this task bar dismiss button when launching a task. */ - void startLaunchTaskDismissAnimation(final Runnable postAnimationRunanble) { - if (mDismissButton.getVisibility() == View.VISIBLE) { - int taskViewExitToAppDuration = mContext.getResources().getInteger( - R.integer.recents_task_exit_to_app_duration); - mDismissButton.animate().cancel(); - mDismissButton.animate() - .alpha(0f) - .setStartDelay(0) - .setInterpolator(mFastOutSlowInInterpolator) - .setDuration(taskViewExitToAppDuration) - .withEndAction(postAnimationRunanble) - .start(); - } - } - /** Animates this task bar if the user does not interact with the stack after a certain time. */ void startNoUserInteractionAnimation() { if (mDismissButton.getVisibility() != View.VISIBLE) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java index 3ee50ac1cafa..14bab6462da3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java @@ -16,16 +16,19 @@ package com.android.systemui.recents.views; -import android.animation.ValueAnimator; +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.animation.PropertyValuesHolder; import android.graphics.RectF; import android.util.IntProperty; import android.util.Property; import android.view.View; -import android.view.ViewPropertyAnimator; -import android.view.animation.Interpolator; +import java.util.ArrayList; -/* The transform state for a task view */ +/** + * The visual properties for a {@link TaskView}. + */ public class TaskViewTransform { public static final Property<View, Integer> LEFT = @@ -80,9 +83,6 @@ public class TaskViewTransform { } }; - // TODO: Move this out of the transform - public int startDelay = 0; - public float translationZ = 0; public float scale = 1f; public float alpha = 1f; @@ -94,15 +94,10 @@ public class TaskViewTransform { // This is a window-space rect used for positioning the task in the stack and freeform workspace public RectF rect = new RectF(); - public TaskViewTransform() { - // Do nothing - } - /** * Resets the current transform. */ public void reset() { - startDelay = 0; translationZ = 0; scale = 1f; alpha = 1f; @@ -116,83 +111,83 @@ public class TaskViewTransform { public boolean hasAlphaChangedFrom(float v) { return (Float.compare(alpha, v) != 0); } + public boolean hasScaleChangedFrom(float v) { return (Float.compare(scale, v) != 0); } + public boolean hasTranslationZChangedFrom(float v) { return (Float.compare(translationZ, v) != 0); } - /** Applies this transform to a view. */ - public void applyToTaskView(TaskView v, int duration, Interpolator interp, boolean allowLayers, - boolean allowShadows, ValueAnimator.AnimatorUpdateListener updateCallback) { - // Check to see if any properties have changed, and update the task view - if (duration > 0) { - ViewPropertyAnimator anim = v.animate(); - boolean requiresLayers = false; + public boolean hasRectChangedFrom(View v) { + return ((int) rect.left != v.getLeft()) || ((int) rect.right != v.getRight()) || + ((int) rect.top != v.getTop()) || ((int) rect.bottom != v.getBottom()); + } + + /** + * Applies this transform to a view. + * + * @return whether hardware layers are required for this animation. + */ + public boolean applyToTaskView(TaskView v, ArrayList<Animator> animators, + TaskViewAnimation taskAnimation, boolean allowShadows) { + // Return early if not visible + boolean requiresHwLayers = false; + if (!visible) { + return requiresHwLayers; + } - // Animate to the final state + if (taskAnimation.isImmediate()) { if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) { - anim.translationZ(translationZ); + v.setTranslationZ(translationZ); } if (hasScaleChangedFrom(v.getScaleX())) { - anim.scaleX(scale) - .scaleY(scale); - requiresLayers = true; + v.setScaleX(scale); + v.setScaleY(scale); } if (hasAlphaChangedFrom(v.getAlpha())) { - // Use layers if we animate alpha - anim.alpha(alpha); - requiresLayers = true; - } - if (requiresLayers && allowLayers) { - anim.withLayer(); + v.setAlpha(alpha); } - if (updateCallback != null) { - anim.setUpdateListener(updateCallback); - } else { - anim.setUpdateListener(null); + if (hasRectChangedFrom(v)) { + v.setLeftTopRightBottom((int) rect.left, (int) rect.top, (int) rect.right, + (int) rect.bottom); } - anim.setListener(null); - anim.setStartDelay(startDelay) - .setDuration(duration) - .setInterpolator(interp) - .start(); } else { - // Set the changed properties if (allowShadows && hasTranslationZChangedFrom(v.getTranslationZ())) { - v.setTranslationZ(translationZ); + animators.add(ObjectAnimator.ofFloat(v, View.TRANSLATION_Z, v.getTranslationZ(), + translationZ)); } if (hasScaleChangedFrom(v.getScaleX())) { - v.setScaleX(scale); - v.setScaleY(scale); + animators.add(ObjectAnimator.ofPropertyValuesHolder(v, + PropertyValuesHolder.ofFloat(View.SCALE_X, v.getScaleX(), scale), + PropertyValuesHolder.ofFloat(View.SCALE_Y, v.getScaleX(), scale))); } if (hasAlphaChangedFrom(v.getAlpha())) { - v.setAlpha(alpha); + animators.add(ObjectAnimator.ofFloat(v, View.ALPHA, v.getAlpha(), alpha)); + requiresHwLayers = true; + } + if (hasRectChangedFrom(v)) { + animators.add(ObjectAnimator.ofPropertyValuesHolder(v, + PropertyValuesHolder.ofInt(LEFT, v.getLeft(), (int) rect.left), + PropertyValuesHolder.ofInt(TOP, v.getTop(), (int) rect.top), + PropertyValuesHolder.ofInt(RIGHT, v.getRight(), (int) rect.right), + PropertyValuesHolder.ofInt(BOTTOM, v.getBottom(), (int) rect.bottom))); } } + return requiresHwLayers; } /** Reset the transform on a view. */ public static void reset(TaskView v) { - // Cancel any running animations and reset the translation in case something else (like a - // dismiss animation) changes it - v.animate().cancel(); v.setTranslationX(0f); v.setTranslationY(0f); v.setTranslationZ(0f); v.setScaleX(1f); v.setScaleY(1f); v.setAlpha(1f); - v.getViewBounds().setClipBottom(0, false /* forceUpdate */); + v.getViewBounds().setClipBottom(0); v.setLeftTopRightBottom(0, 0, 0, 0); v.mThumbnailView.setBitmapScale(1f); } - - @Override - public String toString() { - return "TaskViewTransform delay: " + startDelay + " z: " + translationZ + - " scale: " + scale + " alpha: " + alpha + " visible: " + visible + - " rect: " + rect + " p: " + p; - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java deleted file mode 100644 index eaef51c4869a..000000000000 --- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java +++ /dev/null @@ -1,68 +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 android.animation.ValueAnimator; -import android.graphics.Rect; -import com.android.systemui.recents.misc.ReferenceCountedTrigger; - -/* Common code related to view animations */ -public class ViewAnimation { - - /* The animation context for a task view animation into Recents */ - public static class TaskViewEnterContext { - // A trigger to run some logic when all the animations complete. This works around the fact - // that it is difficult to coordinate ViewPropertyAnimators - public ReferenceCountedTrigger postAnimationTrigger; - // An update listener to notify as the enter animation progresses (used for the home transition) - ValueAnimator.AnimatorUpdateListener updateListener; - - // These following properties are updated for each task view we start the enter animation on - - // Whether or not screen pinning is enabled - boolean isScreenPinningEnabled; - // Whether or not the current task occludes the launch target - boolean currentTaskOccludesLaunchTarget; - // The task rect for the current stack - Rect currentTaskRect; - // The transform of the current task view - TaskViewTransform currentTaskTransform; - // The view index of the current task view - int currentStackViewIndex; - // The total number of task views - int currentStackViewCount; - - public TaskViewEnterContext(ReferenceCountedTrigger t) { - postAnimationTrigger = t; - } - } - - /* The animation context for a task view animation out of Recents */ - public static class TaskViewExitContext { - // A trigger to run some logic when all the animations complete. This works around the fact - // that it is difficult to coordinate ViewPropertyAnimators - ReferenceCountedTrigger postAnimationTrigger; - - // The translationY to apply to a TaskView to move it off the bottom of the task stack - int offscreenTranslationY; - - public TaskViewExitContext(ReferenceCountedTrigger t) { - postAnimationTrigger = t; - } - } - -} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 5906bdac4523..6efb7746d4a7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -16,14 +16,11 @@ package com.android.systemui.statusbar; -import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.TimeInterpolator; import android.app.ActivityManager; import android.app.ActivityManagerNative; -import android.app.INotificationManager; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -80,18 +77,13 @@ import android.view.WindowManager; import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityManager; import android.view.animation.AnimationUtils; -import android.widget.DateTimeView; -import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.RemoteViews; -import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; - import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.StatusBarIcon; -import com.android.internal.statusbar.StatusBarIconList; import com.android.internal.util.NotificationColorUtil; import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; @@ -116,6 +108,7 @@ import java.util.ArrayList; import java.util.List; import java.util.Locale; +import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_MAX; import static com.android.keyguard.KeyguardHostView.OnDismissAction; public abstract class BaseStatusBar extends SystemUI implements @@ -126,9 +119,6 @@ public abstract class BaseStatusBar extends SystemUI implements public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); public static final boolean MULTIUSER_DEBUG = false; - // STOPSHIP disable once we resolve b/18102199 - private static final boolean NOTIFICATION_CLICK_DEBUG = true; - public static final boolean ENABLE_REMOTE_INPUT = SystemProperties.getBoolean("debug.enable_remote_input", true); public static final boolean ENABLE_CHILD_NOTIFICATIONS @@ -141,11 +131,9 @@ public abstract class BaseStatusBar extends SystemUI implements protected static final int MSG_CANCEL_PRELOAD_RECENT_APPS = 1023; protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024; protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025; - protected static final int MSG_SHOW_KEYBOARD_SHORTCUTS_MENU = 1026; + protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026; protected static final boolean ENABLE_HEADS_UP = true; - // scores above this threshold should be displayed in heads up mode. - protected static final int INTERRUPTION_THRESHOLD = 10; protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up"; // Should match the values in PhoneWindowManager @@ -200,14 +188,10 @@ public abstract class BaseStatusBar extends SystemUI implements protected IDreamManager mDreamManager; PowerManager mPowerManager; protected StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; - protected int mRowMinHeightLegacy; - protected int mRowMinHeight; - protected int mRowMaxHeight; // public mode, private notifications, etc private boolean mLockscreenPublicMode = false; private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray(); - private NotificationColorUtil mNotificationColorUtil; private UserManager mUserManager; @@ -237,6 +221,8 @@ public abstract class BaseStatusBar extends SystemUI implements private TimeInterpolator mLinearOutSlowIn, mFastOutLinearIn; + private KeyboardShortcuts mKeyboardShortcuts; + /** * The {@link StatusBarState} of the status bar. */ @@ -357,9 +343,6 @@ public abstract class BaseStatusBar extends SystemUI implements ViewGroup actionGroup = (ViewGroup) parent; index = actionGroup.indexOfChild(view); } - if (NOTIFICATION_CLICK_DEBUG) { - Log.d(TAG, "Clicked on button " + index + " for " + key); - } try { mBarService.onNotificationActionClick(key, index); } catch (RemoteException e) { @@ -617,8 +600,6 @@ public abstract class BaseStatusBar extends SystemUI implements mDevicePolicyManager = (DevicePolicyManager)mContext.getSystemService( Context.DEVICE_POLICY_SERVICE); - mNotificationColorUtil = NotificationColorUtil.getInstance(mContext); - mNotificationData = new NotificationData(this); mAccessibilityManager = (AccessibilityManager) @@ -663,13 +644,14 @@ public abstract class BaseStatusBar extends SystemUI implements android.R.interpolator.fast_out_linear_in); // Connect in to the status bar manager service - StatusBarIconList iconList = new StatusBarIconList(); - mCommandQueue = new CommandQueue(this, iconList); + mCommandQueue = new CommandQueue(this); int[] switches = new int[8]; ArrayList<IBinder> binders = new ArrayList<IBinder>(); + ArrayList<String> iconSlots = new ArrayList<>(); + ArrayList<StatusBarIcon> icons = new ArrayList<>(); try { - mBarService.registerStatusBar(mCommandQueue, iconList, switches, binders); + mBarService.registerStatusBar(mCommandQueue, iconSlots, icons, switches, binders); } catch (RemoteException ex) { // If the system process isn't there we're doomed anyway. } @@ -684,14 +666,10 @@ public abstract class BaseStatusBar extends SystemUI implements setImeWindowStatus(binders.get(0), switches[3], switches[4], switches[5] != 0); // Set up the initial icon state - int N = iconList.size(); + int N = iconSlots.size(); int viewIndex = 0; - for (int i=0; i<N; i++) { - StatusBarIcon icon = iconList.getIcon(i); - if (icon != null) { - addIcon(iconList.getSlot(i), i, viewIndex, icon); - viewIndex++; - } + for (int i=0; i < N; i++) { + setIcon(iconSlots.get(i), icons.get(i)); } // Set up the initial notification state. @@ -707,7 +685,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (DEBUG) { Log.d(TAG, String.format( "init: icons=%d disabled=0x%08x lights=0x%08x menu=0x%08x imeButton=0x%08x", - iconList.size(), + icons.size(), switches[0], switches[1], switches[2], @@ -987,6 +965,7 @@ public abstract class BaseStatusBar extends SystemUI implements row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { + guts.saveImportance(sbn); dismissPopups(); } }); @@ -1118,8 +1097,8 @@ public abstract class BaseStatusBar extends SystemUI implements } @Override - public void showKeyboardShortcutsMenu() { - int msg = MSG_SHOW_KEYBOARD_SHORTCUTS_MENU; + public void toggleKeyboardShortcutsMenu() { + int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU; mHandler.removeMessages(msg); mHandler.sendEmptyMessage(msg); } @@ -1142,7 +1121,7 @@ public abstract class BaseStatusBar extends SystemUI implements return new H(); } - static void sendCloseSystemWindows(Context context, String reason) { + protected void sendCloseSystemWindows(String reason) { if (ActivityManagerNative.isSystemReady()) { try { ActivityManagerNative.getDefault().closeSystemDialogs(reason); @@ -1177,7 +1156,7 @@ public abstract class BaseStatusBar extends SystemUI implements protected void showRecents(boolean triggeredFromAltTab) { if (mRecents != null) { - sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS); + sendCloseSystemWindows(SYSTEM_DIALOG_REASON_RECENT_APPS); mRecents.showRecents(triggeredFromAltTab, getStatusBarView()); } } @@ -1200,8 +1179,8 @@ public abstract class BaseStatusBar extends SystemUI implements } } - protected void showKeyboardShortcuts() { - Toast.makeText(mContext, "Show keyboard shortcuts screen", Toast.LENGTH_LONG).show(); + protected void toggleKeyboardShortcuts() { + getKeyboardShortcuts().toggleKeyboardShortcuts(mContext); } protected void cancelPreloadingRecents() { @@ -1324,8 +1303,8 @@ public abstract class BaseStatusBar extends SystemUI implements case MSG_SHOW_PREV_AFFILIATED_TASK: showRecentsPreviousAffiliatedTask(); break; - case MSG_SHOW_KEYBOARD_SHORTCUTS_MENU: - showKeyboardShortcuts(); + case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU: + toggleKeyboardShortcuts(); break; } } @@ -1531,6 +1510,14 @@ public abstract class BaseStatusBar extends SystemUI implements } } + protected KeyboardShortcuts getKeyboardShortcuts() { + if (mKeyboardShortcuts == null) { + mKeyboardShortcuts = new KeyboardShortcuts(); + } + + return mKeyboardShortcuts; + } + public void startPendingIntentDismissingKeyguard(final PendingIntent intent) { if (!isDeviceProvisioned()) return; @@ -1613,9 +1600,6 @@ public abstract class BaseStatusBar extends SystemUI implements } }); - if (NOTIFICATION_CLICK_DEBUG) { - Log.d(TAG, "Clicked on content of " + notificationKey); - } final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing(); final boolean afterKeyguardGone = intent.isActivity() && PreviewInflater.wouldLaunchResolverActivity(mContext, intent.getIntent(), diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java index deedae0f6a80..cc2622340a4e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java @@ -21,10 +21,8 @@ import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.util.Pair; - import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.StatusBarIcon; -import com.android.internal.statusbar.StatusBarIconList; /** * This class takes the functions from IStatusBar that come in on @@ -65,7 +63,7 @@ public class CommandQueue extends IStatusBar.Stub { private static final int MSG_ASSIST_DISCLOSURE = 22 << MSG_SHIFT; private static final int MSG_START_ASSIST = 23 << MSG_SHIFT; private static final int MSG_CAMERA_LAUNCH_GESTURE = 24 << MSG_SHIFT; - private static final int MSG_SHOW_KEYBOARD_SHORTCUTS = 25 << MSG_SHIFT; + private static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS = 25 << MSG_SHIFT; public static final int FLAG_EXCLUDE_NONE = 0; public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0; @@ -76,7 +74,7 @@ public class CommandQueue extends IStatusBar.Stub { private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey"; - private StatusBarIconList mList; + private final Object mLock = new Object(); private Callbacks mCallbacks; private Handler mHandler = new H(); @@ -84,10 +82,8 @@ public class CommandQueue extends IStatusBar.Stub { * These methods are called back on the main thread. */ public interface Callbacks { - public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon); - public void updateIcon(String slot, int index, int viewIndex, - StatusBarIcon old, StatusBarIcon icon); - public void removeIcon(String slot, int index, int viewIndex); + public void setIcon(String slot, StatusBarIcon icon); + public void removeIcon(String slot); public void disable(int state1, int state2, boolean animate); public void animateExpandNotificationsPanel(); public void animateCollapsePanels(int flags); @@ -100,7 +96,7 @@ public class CommandQueue extends IStatusBar.Stub { public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey); public void toggleRecentApps(); public void preloadRecentApps(); - public void showKeyboardShortcutsMenu(); + public void toggleKeyboardShortcutsMenu(); public void cancelPreloadRecentApps(); public void setWindowState(int window, int state); public void buzzBeepBlinked(); @@ -115,57 +111,55 @@ public class CommandQueue extends IStatusBar.Stub { public void onCameraLaunchGestureDetected(int source); } - public CommandQueue(Callbacks callbacks, StatusBarIconList list) { + public CommandQueue(Callbacks callbacks) { mCallbacks = callbacks; - mList = list; } - public void setIcon(int index, StatusBarIcon icon) { - synchronized (mList) { - int what = MSG_ICON | index; - mHandler.removeMessages(what); - mHandler.obtainMessage(what, OP_SET_ICON, 0, icon.clone()).sendToTarget(); + public void setIcon(String slot, StatusBarIcon icon) { + synchronized (mLock) { + // don't coalesce these + mHandler.obtainMessage(MSG_ICON, OP_SET_ICON, 0, + new Pair<String, StatusBarIcon>(slot, icon)).sendToTarget(); } } - public void removeIcon(int index) { - synchronized (mList) { - int what = MSG_ICON | index; - mHandler.removeMessages(what); - mHandler.obtainMessage(what, OP_REMOVE_ICON, 0, null).sendToTarget(); + public void removeIcon(String slot) { + synchronized (mLock) { + // don't coalesce these + mHandler.obtainMessage(MSG_ICON, OP_REMOVE_ICON, 0, slot).sendToTarget(); } } public void disable(int state1, int state2) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_DISABLE); mHandler.obtainMessage(MSG_DISABLE, state1, state2, null).sendToTarget(); } } public void animateExpandNotificationsPanel() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_EXPAND_NOTIFICATIONS); mHandler.sendEmptyMessage(MSG_EXPAND_NOTIFICATIONS); } } public void animateCollapsePanels() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_COLLAPSE_PANELS); mHandler.sendEmptyMessage(MSG_COLLAPSE_PANELS); } } public void animateExpandSettingsPanel(String subPanel) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_EXPAND_SETTINGS); mHandler.obtainMessage(MSG_EXPAND_SETTINGS, subPanel).sendToTarget(); } } public void setSystemUiVisibility(int vis, int mask) { - synchronized (mList) { + synchronized (mLock) { // Don't coalesce these, since it might have one time flags set such as // STATUS_BAR_UNHIDE which might get lost. mHandler.obtainMessage(MSG_SET_SYSTEMUI_VISIBILITY, vis, mask, null).sendToTarget(); @@ -173,7 +167,7 @@ public class CommandQueue extends IStatusBar.Stub { } public void topAppWindowChanged(boolean menuVisible) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_TOP_APP_WINDOW_CHANGED); mHandler.obtainMessage(MSG_TOP_APP_WINDOW_CHANGED, menuVisible ? 1 : 0, 0, null).sendToTarget(); @@ -182,7 +176,7 @@ public class CommandQueue extends IStatusBar.Stub { public void setImeWindowStatus(IBinder token, int vis, int backDisposition, boolean showImeSwitcher) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_SHOW_IME_BUTTON); Message m = mHandler.obtainMessage(MSG_SHOW_IME_BUTTON, vis, backDisposition, token); m.getData().putBoolean(SHOW_IME_SWITCHER_KEY, showImeSwitcher); @@ -191,7 +185,7 @@ public class CommandQueue extends IStatusBar.Stub { } public void showRecentApps(boolean triggeredFromAltTab) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_SHOW_RECENT_APPS); mHandler.obtainMessage(MSG_SHOW_RECENT_APPS, triggeredFromAltTab ? 1 : 0, 0, null).sendToTarget(); @@ -199,7 +193,7 @@ public class CommandQueue extends IStatusBar.Stub { } public void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_HIDE_RECENT_APPS); mHandler.obtainMessage(MSG_HIDE_RECENT_APPS, triggeredFromAltTab ? 1 : 0, triggeredFromHomeKey ? 1 : 0, @@ -208,83 +202,83 @@ public class CommandQueue extends IStatusBar.Stub { } public void toggleRecentApps() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_TOGGLE_RECENT_APPS); mHandler.obtainMessage(MSG_TOGGLE_RECENT_APPS, 0, 0, null).sendToTarget(); } } public void preloadRecentApps() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_PRELOAD_RECENT_APPS); mHandler.obtainMessage(MSG_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); } } public void cancelPreloadRecentApps() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_CANCEL_PRELOAD_RECENT_APPS); mHandler.obtainMessage(MSG_CANCEL_PRELOAD_RECENT_APPS, 0, 0, null).sendToTarget(); } } @Override - public void showKeyboardShortcutsMenu() { - synchronized (mList) { - mHandler.removeMessages(MSG_SHOW_KEYBOARD_SHORTCUTS); - mHandler.obtainMessage(MSG_SHOW_KEYBOARD_SHORTCUTS).sendToTarget(); + public void toggleKeyboardShortcutsMenu() { + synchronized (mLock) { + mHandler.removeMessages(MSG_TOGGLE_KEYBOARD_SHORTCUTS); + mHandler.obtainMessage(MSG_TOGGLE_KEYBOARD_SHORTCUTS).sendToTarget(); } } public void setWindowState(int window, int state) { - synchronized (mList) { + synchronized (mLock) { // don't coalesce these mHandler.obtainMessage(MSG_SET_WINDOW_STATE, window, state, null).sendToTarget(); } } public void buzzBeepBlinked() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_BUZZ_BEEP_BLINKED); mHandler.sendEmptyMessage(MSG_BUZZ_BEEP_BLINKED); } } public void notificationLightOff() { - synchronized (mList) { + synchronized (mLock) { mHandler.sendEmptyMessage(MSG_NOTIFICATION_LIGHT_OFF); } } public void notificationLightPulse(int argb, int onMillis, int offMillis) { - synchronized (mList) { + synchronized (mLock) { mHandler.obtainMessage(MSG_NOTIFICATION_LIGHT_PULSE, onMillis, offMillis, argb) .sendToTarget(); } } public void showScreenPinningRequest() { - synchronized (mList) { + synchronized (mLock) { mHandler.sendEmptyMessage(MSG_SHOW_SCREEN_PIN_REQUEST); } } public void appTransitionPending() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_APP_TRANSITION_PENDING); mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING); } } public void appTransitionCancelled() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_APP_TRANSITION_PENDING); mHandler.sendEmptyMessage(MSG_APP_TRANSITION_PENDING); } } public void appTransitionStarting(long startTime, long duration) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_APP_TRANSITION_STARTING); mHandler.obtainMessage(MSG_APP_TRANSITION_STARTING, Pair.create(startTime, duration)) .sendToTarget(); @@ -292,14 +286,14 @@ public class CommandQueue extends IStatusBar.Stub { } public void showAssistDisclosure() { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_ASSIST_DISCLOSURE); mHandler.obtainMessage(MSG_ASSIST_DISCLOSURE).sendToTarget(); } } public void startAssist(Bundle args) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_START_ASSIST); mHandler.obtainMessage(MSG_START_ASSIST, args).sendToTarget(); } @@ -307,7 +301,7 @@ public class CommandQueue extends IStatusBar.Stub { @Override public void onCameraLaunchGestureDetected(int source) { - synchronized (mList) { + synchronized (mLock) { mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE); mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget(); } @@ -318,27 +312,14 @@ public class CommandQueue extends IStatusBar.Stub { final int what = msg.what & MSG_MASK; switch (what) { case MSG_ICON: { - final int index = msg.what & INDEX_MASK; - final int viewIndex = mList.getViewIndex(index); switch (msg.arg1) { case OP_SET_ICON: { - StatusBarIcon icon = (StatusBarIcon)msg.obj; - StatusBarIcon old = mList.getIcon(index); - if (old == null) { - mList.setIcon(index, icon); - mCallbacks.addIcon(mList.getSlot(index), index, viewIndex, icon); - } else { - mList.setIcon(index, icon); - mCallbacks.updateIcon(mList.getSlot(index), index, viewIndex, - old, icon); - } + Pair<String, StatusBarIcon> p = (Pair<String, StatusBarIcon>) msg.obj; + mCallbacks.setIcon(p.first, p.second); break; } case OP_REMOVE_ICON: - if (mList.getIcon(index) != null) { - mList.removeIcon(index); - mCallbacks.removeIcon(mList.getSlot(index), index, viewIndex); - } + mCallbacks.removeIcon((String) msg.obj); break; } break; @@ -380,8 +361,8 @@ public class CommandQueue extends IStatusBar.Stub { case MSG_CANCEL_PRELOAD_RECENT_APPS: mCallbacks.cancelPreloadRecentApps(); break; - case MSG_SHOW_KEYBOARD_SHORTCUTS: - mCallbacks.showKeyboardShortcutsMenu(); + case MSG_TOGGLE_KEYBOARD_SHORTCUTS: + mCallbacks.toggleKeyboardShortcutsMenu(); break; case MSG_SET_WINDOW_STATE: mCallbacks.setWindowState(msg.arg1, msg.arg2); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java new file mode 100644 index 000000000000..3e0ea90f7694 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java @@ -0,0 +1,81 @@ +/* + * 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 + */ + +package com.android.systemui.statusbar; + +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.Context; +import android.graphics.drawable.ColorDrawable; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; + +import com.android.systemui.R; + +/** + * Contains functionality for handling keyboard shortcuts. + */ +public class KeyboardShortcuts { + private Dialog mKeyboardShortcutsDialog; + + public KeyboardShortcuts() {} + + public void toggleKeyboardShortcuts(Context context) { + if (mKeyboardShortcutsDialog == null) { + // Create dialog. + AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); + LayoutInflater inflater = (LayoutInflater) context.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + final View keyboardShortcutsView = inflater.inflate( + R.layout.keyboard_shortcuts_view, null); + + populateKeyboardShortcuts(keyboardShortcutsView.findViewById( + R.id.keyboard_shortcuts_wrapper)); + dialogBuilder.setView(keyboardShortcutsView); + mKeyboardShortcutsDialog = dialogBuilder.create(); + mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true); + + // Setup window. + Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow(); + keyboardShortcutsWindow.setType( + WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); + keyboardShortcutsWindow.setBackgroundDrawable( + new ColorDrawable(android.graphics.Color.TRANSPARENT)); + keyboardShortcutsWindow.setGravity(Gravity.TOP); + mKeyboardShortcutsDialog.show(); + } else { + dismissKeyboardShortcutsDialog(); + } + } + + public void dismissKeyboardShortcutsDialog() { + if (mKeyboardShortcutsDialog != null) { + mKeyboardShortcutsDialog.dismiss(); + mKeyboardShortcutsDialog = null; + } + } + + /** + * @return {@code true} if the keyboard shortcuts have been successfully populated. + */ + private boolean populateKeyboardShortcuts(View keyboardShortcutsLayout) { + // TODO: Populate shortcuts. + return true; + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java index 6850f7ecf122..20a6e7c090a8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java @@ -46,6 +46,10 @@ public class NotificationGuts extends LinearLayout { private int mClipTopAmount; private int mActualHeight; private boolean mExposed; + private RadioButton mApplyToTopic; + private SeekBar mSeekBar; + private Notification.Topic mTopic; + private INotificationManager mINotificationManager; public NotificationGuts(Context context, AttributeSet attrs) { super(context, attrs); @@ -98,67 +102,39 @@ public class NotificationGuts extends LinearLayout { void bindImportance(final StatusBarNotification sbn, final ExpandableNotificationRow row, final int importance) { - final INotificationManager sINM = INotificationManager.Stub.asInterface( + mINotificationManager = INotificationManager.Stub.asInterface( ServiceManager.getService(Context.NOTIFICATION_SERVICE)); - final Notification.Topic topic = sbn.getNotification().getTopic() == null + mTopic = sbn.getNotification().getTopic() == null ? new Notification.Topic(Notification.TOPIC_DEFAULT, mContext.getString( com.android.internal.R.string.default_notification_topic_label)) : sbn.getNotification().getTopic(); boolean doesAppUseTopics = false; try { - doesAppUseTopics = sINM.doesAppUseTopics(sbn.getPackageName(), sbn.getUid()); + doesAppUseTopics = + mINotificationManager.doesAppUseTopics(sbn.getPackageName(), sbn.getUid()); } catch (RemoteException e) {} final boolean appUsesTopics = doesAppUseTopics; - final RadioButton applyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic); - applyToTopic.setChecked(true); + mApplyToTopic = (RadioButton) row.findViewById(R.id.apply_to_topic); + if (appUsesTopics) { + mApplyToTopic.setChecked(true); + } final View applyToApp = row.findViewById(R.id.apply_to_app); final TextView topicSummary = ((TextView) row.findViewById(R.id.summary)); final TextView topicTitle = ((TextView) row.findViewById(R.id.title)); - final SeekBar seekBar = (SeekBar) row.findViewById(R.id.seekbar); - final RadioGroup applyTo = (RadioGroup) row.findViewById(R.id.apply_to); - applyTo.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) { - try { - switch (checkedId) { - case R.id.apply_to_topic: - sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic, - seekBar.getProgress()); - break; - default: - sINM.setAppImportance(sbn.getPackageName(), sbn.getUid(), - seekBar.getProgress()); - } - } catch (RemoteException e) { - // :( - } - } - }); - - seekBar.setMax(4); - seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { + mSeekBar = (SeekBar) row.findViewById(R.id.seekbar); + mSeekBar.setMax(4); + mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { updateTitleAndSummary(progress); if (fromUser) { if (appUsesTopics) { - applyToTopic.setVisibility(View.VISIBLE); - - applyToTopic.setText( - mContext.getString(R.string.apply_to_topic, topic.getLabel())); + mApplyToTopic.setVisibility(View.VISIBLE); + mApplyToTopic.setText( + mContext.getString(R.string.apply_to_topic, mTopic.getLabel())); applyToApp.setVisibility(View.VISIBLE); } - try { - if (applyToTopic.isChecked()) { - sINM.setTopicImportance(sbn.getPackageName(), sbn.getUid(), topic, - progress); - } else { - sINM.setAppImportance(sbn.getPackageName(), sbn.getUid(), progress); - } - } catch (RemoteException e) { - // :( - } } } @@ -202,7 +178,22 @@ public class NotificationGuts extends LinearLayout { } } }); - seekBar.setProgress(importance); + mSeekBar.setProgress(importance); + } + + void saveImportance(final StatusBarNotification sbn) { + int progress = mSeekBar.getProgress(); + try { + if (mApplyToTopic.isChecked()) { + mINotificationManager.setTopicImportance(sbn.getPackageName(), sbn.getUid(), mTopic, + progress); + } else { + mINotificationManager.setAppImportance( + sbn.getPackageName(), sbn.getUid(), progress); + } + } catch (RemoteException e) { + // :( + } } public void setActualHeight(int actualHeight) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java index f243b00143a2..d7e47c27dc71 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/RemoteInputController.java @@ -30,11 +30,11 @@ import java.util.ArrayList; public class RemoteInputController { private final ArrayList<WeakReference<NotificationData.Entry>> mRemoteInputs = new ArrayList<>(); - private final StatusBarWindowManager mStatusBarWindowManager; + private final ArrayList<Callback> mCallbacks = new ArrayList<>(3); private final HeadsUpManager mHeadsUpManager; public RemoteInputController(StatusBarWindowManager sbwm, HeadsUpManager headsUpManager) { - mStatusBarWindowManager = sbwm; + addCallback(sbwm); mHeadsUpManager = headsUpManager; } @@ -59,8 +59,12 @@ public class RemoteInputController { } private void apply(NotificationData.Entry entry) { - mStatusBarWindowManager.setRemoteInputActive(isRemoteInputActive()); mHeadsUpManager.setRemoteInputActive(entry, isRemoteInputActive(entry)); + boolean remoteInputActive = isRemoteInputActive(); + int N = mCallbacks.size(); + for (int i = 0; i < N; i++) { + mCallbacks.get(i).onRemoteInputActive(remoteInputActive); + } } /** @@ -99,4 +103,12 @@ public class RemoteInputController { } + public void addCallback(Callback callback) { + Preconditions.checkNotNull(callback); + mCallbacks.add(callback); + } + + public interface Callback { + void onRemoteInputActive(boolean active); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java index db2415a2d41e..de7a8dbc9483 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java @@ -30,8 +30,6 @@ import android.util.AttributeSet; import android.util.Log; import android.view.ViewDebug; import android.view.accessibility.AccessibilityEvent; -import android.widget.ImageView; - import com.android.internal.statusbar.StatusBarIcon; import com.android.systemui.R; @@ -76,7 +74,7 @@ public class StatusBarIconView extends AnimatedImageView { setScaleY(scale); } - setScaleType(ImageView.ScaleType.CENTER); + setScaleType(ScaleType.CENTER); } public void setNotification(Notification notification) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java new file mode 100644 index 000000000000..e2d64b049ca0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarNavigationBarView.java @@ -0,0 +1,159 @@ +/* + * 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.statusbar.car; + +import android.content.Context; +import android.content.Intent; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; +import android.R.color; +import android.util.AttributeSet; +import android.util.Log; +import android.view.View; +import android.widget.ImageButton; +import android.widget.ImageView.ScaleType; +import android.widget.LinearLayout; + +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.ActivityStarter; +import com.android.systemui.statusbar.phone.NavigationBarView; +import com.android.systemui.statusbar.phone.NavigationBarGestureHelper; +import com.android.systemui.statusbar.policy.KeyButtonView; + +import java.net.URISyntaxException; + +/** + * A custom navigation bar for the automotive use case. + * <p> + * The navigation bar in the automotive use case is more like a list of shortcuts, which we + * expect to be customizable by the car OEMs. This implementation populates the nav_buttons layout + * from resources rather than the layout file so customization would then mean updating + * arrays_car.xml appropriately in an overlay. + */ +class CarNavigationBarView extends NavigationBarView { + private ActivityStarter mActivityStarter; + + public CarNavigationBarView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + public void onFinishInflate() { + // Read up arrays_car.xml and populate the navigation bar here. + Context context = getContext(); + Resources r = getContext().getResources(); + TypedArray icons = r.obtainTypedArray(R.array.car_shortcut_icons); + TypedArray intents = r.obtainTypedArray(R.array.car_shortcut_intent_uris); + TypedArray longpressIntents = + r.obtainTypedArray(R.array.car_shortcut_longpress_intent_uris); + + if (icons.length() != intents.length()) { + throw new RuntimeException("car_shortcut_icons and car_shortcut_intents do not match"); + } + + LinearLayout navButtons = (LinearLayout) findViewById(R.id.nav_buttons); + LinearLayout lightsOut = (LinearLayout) findViewById(R.id.lights_out); + + for (int i = 0; i < icons.length(); i++) { + Drawable icon = icons.getDrawable(i); + + try { + Intent intent = Intent.parseUri(intents.getString(i), Intent.URI_INTENT_SCHEME); + Intent longpress = null; + String longpressUri = longpressIntents.getString(i); + if (!longpressUri.isEmpty()) { + longpress = Intent.parseUri(longpressUri, Intent.URI_INTENT_SCHEME); + } + + // nav_buttons and lights_out should match exactly. + navButtons.addView(makeButton(context, icon, intent, longpress)); + lightsOut.addView(makeButton(context, icon, intent, longpress)); + } catch (URISyntaxException e) { + throw new RuntimeException("Malformed intent uri", e); + } + } + } + + private ImageButton makeButton(Context context, Drawable icon, + final Intent intent, final Intent longpress) { + ImageButton button = new ImageButton(context); + + button.setImageDrawable(icon); + button.setScaleType(ScaleType.CENTER); + button.setBackgroundColor(color.transparent); + LinearLayout.LayoutParams lp = + new LinearLayout.LayoutParams(0, LayoutParams.MATCH_PARENT, 1); + button.setLayoutParams(lp); + + button.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (mActivityStarter != null) { + mActivityStarter.startActivity(intent, true); + } + } + }); + + // Long click handlers are optional. + if (longpress != null) { + button.setLongClickable(true); + button.setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + if (mActivityStarter != null) { + mActivityStarter.startActivity(longpress, true); + return true; + } + return false; + } + }); + } else { + button.setLongClickable(false); + } + + return button; + } + + public void setActivityStarter(ActivityStarter activityStarter) { + mActivityStarter = activityStarter; + } + + @Override + public void setDisabledFlags(int disabledFlags, boolean force) { + // TODO: Populate. + } + + @Override + public void reorient() { + // We expect the car head unit to always have a fixed rotation so we ignore this. The super + // class implentation expects mRotatedViews to be populated, so if you call into it, there + // is a possibility of a NullPointerException. + } + + @Override + public View getCurrentView() { + return this; + } + + @Override + public void setNavigationIconHints(int hints, boolean force) { + // We do not need to set the navigation icon hints for a vehicle + // Calling setNavigationIconHints in the base class will result in a NPE as the car + // navigation bar does not have a back button. + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java new file mode 100644 index 000000000000..31631f8efa66 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java @@ -0,0 +1,66 @@ +/* + * 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.statusbar.car; + +import android.content.Context; +import android.graphics.PixelFormat; +import android.view.View; +import android.view.ViewGroup.LayoutParams; +import android.view.WindowManager; + +import com.android.systemui.R; +import com.android.systemui.statusbar.phone.PhoneStatusBar; + +/** + * A status bar (and navigation bar) tailored for the automotive use case. + */ +public class CarStatusBar extends PhoneStatusBar { + @Override + protected void addNavigationBar() { + WindowManager.LayoutParams lp = new WindowManager.LayoutParams( + LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, + WindowManager.LayoutParams.TYPE_NAVIGATION_BAR, + WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING + | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE + | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL + | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, + PixelFormat.TRANSLUCENT); + lp.setTitle("CarNavigationBar"); + lp.windowAnimations = 0; + mWindowManager.addView(mNavigationBarView, lp); + } + + @Override + protected void createNavigationBarView(Context context) { + if (mNavigationBarView != null) { + return; + } + + CarNavigationBarView carNavBar = + (CarNavigationBarView) View.inflate(context, R.layout.car_navigation_bar, null); + carNavBar.setActivityStarter(this); + mNavigationBarView = carNavBar; + } + + @Override + protected void repositionNavigationBar() { + // The navigation bar for a vehicle will not need to be repositioned, as it is always + // set at the bottom. + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index a3d0ce69bdd6..55c7cb7b2909 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -69,7 +69,6 @@ public class NavigationBarView extends LinearLayout { View mCurrentView = null; View[] mRotatedViews = new View[4]; - int mBarSize; boolean mVertical; boolean mScreenOn; @@ -78,6 +77,9 @@ public class NavigationBarView extends LinearLayout { int mNavigationIconHints = 0; private Drawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon; + private Drawable mBackCarModeIcon, mBackLandCarModeIcon; + private Drawable mBackAltCarModeIcon, mBackAltLandCarModeIcon; + private Drawable mHomeDefaultIcon, mHomeCarModeIcon; private Drawable mRecentIcon; private Drawable mRecentLandIcon; @@ -96,6 +98,7 @@ public class NavigationBarView extends LinearLayout { private boolean mIsLayoutRtl; private boolean mLayoutTransitionsEnabled = true; private boolean mWakeAndUnlocking; + private boolean mCarMode = false; private class NavTransitionListener implements TransitionListener { private boolean mBackTransitioning; @@ -157,8 +160,8 @@ public class NavigationBarView extends LinearLayout { final String how = "" + m.obj; final int w = getWidth(); final int h = getHeight(); - final int vw = mCurrentView.getWidth(); - final int vh = mCurrentView.getHeight(); + final int vw = getCurrentView().getWidth(); + final int vh = getCurrentView().getHeight(); if (h != vh || w != vw) { Log.w(TAG, String.format( @@ -176,16 +179,15 @@ public class NavigationBarView extends LinearLayout { public NavigationBarView(Context context, AttributeSet attrs) { super(context, attrs); - mDisplay = ((WindowManager)context.getSystemService( + mDisplay = ((WindowManager) context.getSystemService( Context.WINDOW_SERVICE)).getDefaultDisplay(); final Resources res = getContext().getResources(); - mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size); mVertical = false; mShowMenu = false; mGestureHelper = new NavigationBarGestureHelper(context); - getIcons(res); + getIcons(context); mBarTransitions = new NavigationBarTransitions(this); } @@ -230,41 +232,53 @@ public class NavigationBarView extends LinearLayout { } public KeyButtonView getRecentsButton() { - return (KeyButtonView) mCurrentView.findViewById(R.id.recent_apps); + return (KeyButtonView) getCurrentView().findViewById(R.id.recent_apps); } public View getMenuButton() { - return mCurrentView.findViewById(R.id.menu); + return getCurrentView().findViewById(R.id.menu); } public View getBackButton() { - return mCurrentView.findViewById(R.id.back); + return getCurrentView().findViewById(R.id.back); } public KeyButtonView getHomeButton() { - return (KeyButtonView) mCurrentView.findViewById(R.id.home); + return (KeyButtonView) getCurrentView().findViewById(R.id.home); } public View getImeSwitchButton() { - return mCurrentView.findViewById(R.id.ime_switcher); + return getCurrentView().findViewById(R.id.ime_switcher); } public View getAppShelf() { - return mCurrentView.findViewById(R.id.app_shelf); + return getCurrentView().findViewById(R.id.app_shelf); } - private void getIcons(Resources res) { - mBackIcon = res.getDrawable(R.drawable.ic_sysbar_back); + private void getCarModeIcons(Context ctx) { + mBackCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_carmode); + mBackLandCarModeIcon = mBackCarModeIcon; + mBackAltCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime_carmode); + mBackAltLandCarModeIcon = mBackAltCarModeIcon; + mHomeCarModeIcon = ctx.getDrawable(R.drawable.ic_sysbar_home_carmode); + } + + private void getIcons(Context ctx) { + mBackIcon = ctx.getDrawable(R.drawable.ic_sysbar_back); mBackLandIcon = mBackIcon; - mBackAltIcon = res.getDrawable(R.drawable.ic_sysbar_back_ime); + mBackAltIcon = ctx.getDrawable(R.drawable.ic_sysbar_back_ime); mBackAltLandIcon = mBackAltIcon; - mRecentIcon = res.getDrawable(R.drawable.ic_sysbar_recent); + + mHomeDefaultIcon = ctx.getDrawable(R.drawable.ic_sysbar_home); + + mRecentIcon = ctx.getDrawable(R.drawable.ic_sysbar_recent); mRecentLandIcon = mRecentIcon; + getCarModeIcons(ctx); } @Override public void setLayoutDirection(int layoutDirection) { - getIcons(getContext().getResources()); + getIcons(getContext()); super.setLayoutDirection(layoutDirection); } @@ -278,6 +292,18 @@ public class NavigationBarView extends LinearLayout { setNavigationIconHints(hints, false); } + private Drawable getBackIconWithAlt(boolean carMode, boolean landscape) { + return landscape + ? carMode ? mBackAltLandCarModeIcon : mBackAltLandIcon + : carMode ? mBackAltCarModeIcon : mBackAltIcon; + } + + private Drawable getBackIcon(boolean carMode, boolean landscape) { + return landscape + ? carMode ? mBackLandCarModeIcon : mBackLandIcon + : carMode ? mBackCarModeIcon : mBackIcon; + } + public void setNavigationIconHints(int hints, boolean force) { if (!force && hints == mNavigationIconHints) return; final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0; @@ -292,11 +318,23 @@ public class NavigationBarView extends LinearLayout { mNavigationIconHints = hints; - ((ImageView)getBackButton()).setImageDrawable(backAlt - ? (mVertical ? mBackAltLandIcon : mBackAltIcon) - : (mVertical ? mBackLandIcon : mBackIcon)); + // We have to replace or restore the back and home button icons when exiting or entering + // carmode, respectively. Recents are not available in CarMode in nav bar so change + // to recent icon is not required. + Drawable backIcon = (backAlt) + ? getBackIconWithAlt(mCarMode, mVertical) + : getBackIcon(mCarMode, mVertical); - ((ImageView)getRecentsButton()).setImageDrawable(mVertical ? mRecentLandIcon : mRecentIcon); + ((ImageView) getBackButton()).setImageDrawable(backIcon); + + ((ImageView) getRecentsButton()).setImageDrawable( + mVertical ? mRecentLandIcon : mRecentIcon); + + if (mCarMode) { + ((ImageView) getHomeButton()).setImageDrawable(mHomeCarModeIcon); + } else { + ((ImageView) getHomeButton()).setImageDrawable(mHomeDefaultIcon); + } final boolean showImeButton = ((hints & StatusBarManager.NAVIGATION_HINT_IME_SHOWN) != 0); getImeSwitchButton().setVisibility(showImeButton ? View.VISIBLE : View.INVISIBLE); @@ -326,7 +364,7 @@ public class NavigationBarView extends LinearLayout { setSlippery(disableHome && disableRecent && disableBack && disableSearch); } - ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons); + ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons); if (navButtons != null) { LayoutTransition lt = navButtons.getLayoutTransition(); if (lt != null) { @@ -379,7 +417,7 @@ public class NavigationBarView extends LinearLayout { private void updateLayoutTransitionsEnabled() { boolean enabled = !mWakeAndUnlocking && mLayoutTransitionsEnabled; - ViewGroup navButtons = (ViewGroup) mCurrentView.findViewById(R.id.nav_buttons); + ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons); LayoutTransition lt = navButtons.getLayoutTransition(); if (lt != null) { if (enabled) { @@ -546,8 +584,33 @@ public class NavigationBarView extends LinearLayout { @Override protected void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); + boolean uiCarModeChanged = updateCarMode(newConfig); updateRTLOrder(); updateTaskSwitchHelper(); + if (uiCarModeChanged) { + // uiMode changed either from carmode or to carmode. + // replace the nav bar button icons based on which mode + // we are switching to. + setNavigationIconHints(mNavigationIconHints, true); + } + } + + /** + * If the configuration changed, update the carmode and return that it was updated. + */ + private boolean updateCarMode(Configuration newConfig) { + boolean uiCarModeChanged = false; + if (newConfig != null) { + int uiMode = newConfig.uiMode & Configuration.UI_MODE_TYPE_MASK; + if (mCarMode && uiMode != Configuration.UI_MODE_TYPE_CAR) { + mCarMode = false; + uiCarModeChanged = true; + } else if (uiMode == Configuration.UI_MODE_TYPE_CAR) { + mCarMode = true; + uiCarModeChanged = true; + } + } + return uiCarModeChanged; } /** diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java index 42fd8722931d..ba20679980d6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -1318,7 +1318,6 @@ public class NotificationPanelView extends PanelView implements mHeader.setExpansion(getHeaderExpansionFraction()); setQsTranslation(height); requestScrollerTopPaddingUpdate(false /* animate */); - updateNotificationScrim(height); if (mKeyguardShowing) { updateHeaderKeyguard(); } @@ -1355,12 +1354,6 @@ public class NotificationPanelView extends PanelView implements } } - private void updateNotificationScrim(float height) { - int startDistance = mQsMinExpansionHeight + mNotificationScrimWaitDistance; - float progress = (height - startDistance) / (mQsMaxExpansionHeight - startDistance); - progress = Math.max(0.0f, Math.min(progress, 1.0f)); - } - private float getHeaderExpansionFraction() { if (!mKeyguardShowing) { return getQsExpansionFraction(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java index e1a400d43638..6aa072ff2c81 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -71,7 +71,6 @@ public abstract class PanelBar extends FrameLayout { Log.e(TAG, "setPanelHolder: null PanelHolder", new Throwable()); return; } - ph.setBar(this); mPanelHolder = ph; final int N = ph.getChildCount(); for (int i=0; i<N; i++) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java index d7f34d5b1396..5095ebb95ec1 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelHolder.java @@ -28,7 +28,6 @@ public class PanelHolder extends FrameLayout { public static final boolean DEBUG_GESTURES = true; private int mSelectedPanelIndex = -1; - private PanelBar mBar; public PanelHolder(Context context, AttributeSet attrs) { super(context, attrs); @@ -79,8 +78,4 @@ public class PanelHolder extends FrameLayout { } return false; } - - public void setBar(PanelBar panelBar) { - mBar = panelBar; - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java index 5e54ba7d9ce4..7b2498f2ac72 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -58,7 +58,6 @@ public abstract class PanelView extends FrameLayout { private float mPeekHeight; private float mHintDistance; - private int mEdgeTapAreaWidth; private float mInitialOffsetOnTouch; private boolean mCollapsedAndHeadsUpOnDown; private float mExpandedFraction = 0; @@ -202,7 +201,6 @@ public abstract class PanelView extends FrameLayout { final ViewConfiguration configuration = ViewConfiguration.get(getContext()); mTouchSlop = configuration.getScaledTouchSlop(); mHintDistance = res.getDimension(R.dimen.hint_move_distance); - mEdgeTapAreaWidth = res.getDimensionPixelSize(R.dimen.edge_tap_area_width); mUnlockFalsingThreshold = res.getDimensionPixelSize(R.dimen.unlock_falsing_threshold); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java index 78d09e3e03a4..d721a77b4055 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -83,7 +83,6 @@ import android.view.MotionEvent; import android.view.ThreadedRenderer; import android.view.VelocityTracker; import android.view.View; -import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; import android.view.ViewStub; import android.view.WindowManager; @@ -95,7 +94,6 @@ import android.view.animation.LinearInterpolator; import android.view.animation.PathInterpolator; import android.widget.ImageView; import android.widget.TextView; - import com.android.internal.logging.MetricsLogger; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.StatusBarIcon; @@ -152,7 +150,6 @@ import com.android.systemui.statusbar.policy.LocationControllerImpl; import com.android.systemui.statusbar.policy.NetworkControllerImpl; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.PreviewInflater; -import com.android.systemui.statusbar.policy.RemoteInputView; import com.android.systemui.statusbar.policy.RotationLockControllerImpl; import com.android.systemui.statusbar.policy.SecurityControllerImpl; import com.android.systemui.statusbar.policy.UserInfoController; @@ -637,8 +634,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, addNavigationBar(); // Lastly, call to the icon policy to install/update all the icons. - mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController, - mUserInfoController, mBluetoothController); + mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController, + mHotspotController, mUserInfoController, mBluetoothController); mIconPolicy.setCurrentUserSetup(mUserSetup); mSettingsObserver.onChange(false); // set up @@ -728,32 +725,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, boolean showNav = mWindowManagerService.hasNavigationBar(); if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav); if (showNav) { - // Optionally show app shortcuts in the nav bar "shelf" area. - if (shouldShowAppShelf()) { - mNavigationBarView = (NavigationBarView) View.inflate( - context, R.layout.navigation_bar_with_apps, null); - } else { - mNavigationBarView = (NavigationBarView) View.inflate( - context, R.layout.navigation_bar, null); - } - mNavigationBarView.setDisabledFlags(mDisabled1); - mNavigationBarView.setComponents(mRecents, getComponent(Divider.class)); - mNavigationBarView.setOnVerticalChangedListener( - new NavigationBarView.OnVerticalChangedListener() { - @Override - public void onVerticalChanged(boolean isVertical) { - if (mAssistManager != null) { - mAssistManager.onConfigurationChanged(); - } - mNotificationPanel.setQsScrimEnabled(!isVertical); - } - }); - mNavigationBarView.setOnTouchListener(new View.OnTouchListener() { - @Override - public boolean onTouch(View v, MotionEvent event) { - checkUserAutohide(v, event); - return false; - }}); + createNavigationBarView(context); } } catch (RemoteException ex) { // no window manager? good luck with that @@ -919,7 +891,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mNetworkController, mZenModeController, mHotspotController, mCastController, mFlashlightController, mUserSwitcherController, mUserInfoController, mKeyguardMonitor, - mSecurityController, mBatteryController); + mSecurityController, mBatteryController, mIconController); mQSPanel.setHost(qsh); mQSPanel.setTiles(qsh.getTiles()); mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow); @@ -979,6 +951,35 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return mStatusBarView; } + protected void createNavigationBarView(Context context) { + // Optionally show app shortcuts in the nav bar "shelf" area. + if (shouldShowAppShelf()) { + mNavigationBarView = (NavigationBarView) View.inflate( + context, R.layout.navigation_bar_with_apps, null); + } else { + mNavigationBarView = (NavigationBarView) View.inflate( + context, R.layout.navigation_bar, null); + } + mNavigationBarView.setDisabledFlags(mDisabled1); + mNavigationBarView.setComponents(mRecents, getComponent(Divider.class)); + mNavigationBarView.setOnVerticalChangedListener( + new NavigationBarView.OnVerticalChangedListener() { + @Override + public void onVerticalChanged(boolean isVertical) { + if (mAssistManager != null) { + mAssistManager.onConfigurationChanged(); + } + mNotificationPanel.setQsScrimEnabled(!isVertical); + } + }); + mNavigationBarView.setOnTouchListener(new View.OnTouchListener() { + @Override + public boolean onTouch(View v, MotionEvent event) { + checkUserAutohide(v, event); + return false; + }}); + } + /** Returns true if the app shelf should be shown in the nav bar. */ private boolean shouldShowAppShelf() { // Allow adb to override the default shelf behavior: @@ -1086,6 +1087,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardIndicationController.setStatusBarKeyguardViewManager( mStatusBarKeyguardViewManager); mFingerprintUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mRemoteInputController.addCallback(mStatusBarKeyguardViewManager); mKeyguardViewMediatorCallback = keyguardViewMediator.getViewMediatorCallback(); } @@ -1191,7 +1193,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } // For small-screen devices (read: phones) that lack hardware navigation buttons - private void addNavigationBar() { + protected void addNavigationBar() { if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView); if (mNavigationBarView == null) return; @@ -1200,7 +1202,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams()); } - private void repositionNavigationBar() { + protected void repositionNavigationBar() { if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return; prepareNavigationBarView(); @@ -1234,17 +1236,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, return lp; } - public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { - mIconController.addSystemIcon(slot, index, viewIndex, icon); - } - - public void updateIcon(String slot, int index, int viewIndex, - StatusBarIcon old, StatusBarIcon icon) { - mIconController.updateSystemIcon(slot, index, viewIndex, old, icon); + @Override + public void setIcon(String slot, StatusBarIcon icon) { + mIconController.setIcon(slot, icon); } - public void removeIcon(String slot, int index, int viewIndex) { - mIconController.removeSystemIcon(slot, index, viewIndex); + @Override + public void removeIcon(String slot) { + mIconController.removeIcon(slot); } public UserHandle getCurrentUserHandle() { @@ -2987,6 +2986,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (DEBUG) Log.v(TAG, "onReceive: " + intent); String action = intent.getAction(); if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { + getKeyboardShortcuts().dismissKeyboardShortcutsDialog(); if (isCurrentProfile(getSendingUserId())) { int flags = CommandQueue.FLAG_EXCLUDE_NONE; String reason = intent.getStringExtra("reason"); 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 b89cd228819c..59d831c921db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -20,7 +20,6 @@ import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AlarmManager; import android.app.AlarmManager.AlarmClockInfo; -import android.app.StatusBarManager; import android.app.SynchronousUserSwitchObserver; import android.content.BroadcastReceiver; import android.content.Context; @@ -35,7 +34,6 @@ import android.os.UserManager; import android.provider.Settings.Global; import android.telecom.TelecomManager; import android.util.Log; - import com.android.internal.telephony.IccCardConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.systemui.R; @@ -66,13 +64,13 @@ public class PhoneStatusBarPolicy implements Callback { private static final String SLOT_MANAGED_PROFILE = "managed_profile"; private final Context mContext; - private final StatusBarManager mService; private final Handler mHandler = new Handler(); private final CastController mCast; private final HotspotController mHotspot; private final AlarmManager mAlarmManager; private final UserInfoController mUserInfoController; private final UserManager mUserManager; + private final StatusBarIconController mIconController; // Assume it's all good unless we hear otherwise. We don't always seem // to get broadcasts that it *is* there. @@ -97,18 +95,14 @@ public class PhoneStatusBarPolicy implements Callback { String action = intent.getAction(); if (action.equals(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED)) { updateAlarm(); - } - else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) || + } else if (action.equals(AudioManager.RINGER_MODE_CHANGED_ACTION) || action.equals(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION)) { updateVolumeZen(); - } - else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { + } else if (action.equals(TelephonyIntents.ACTION_SIM_STATE_CHANGED)) { updateSimState(intent); - } - else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) { + } else if (action.equals(TelecomManager.ACTION_CURRENT_TTY_MODE_CHANGED)) { updateTTY(intent); - } - else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) { + } else if (action.equals(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED)) { updateQuietState(); updateManagedProfile(); } @@ -119,18 +113,19 @@ public class PhoneStatusBarPolicy implements Callback { @Override public void run() { if (DEBUG) Log.v(TAG, "updateCast: hiding icon NOW"); - mService.setIconVisibility(SLOT_CAST, false); + mIconController.setIconVisibility(SLOT_CAST, false); } }; - public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot, - UserInfoController userInfoController, BluetoothController bluetooth) { + public PhoneStatusBarPolicy(Context context, StatusBarIconController iconController, + CastController cast, HotspotController hotspot, UserInfoController userInfoController, + BluetoothController bluetooth) { mContext = context; + mIconController = iconController; mCast = cast; mHotspot = hotspot; mBluetooth = bluetooth; mBluetooth.addStateChangedCallback(this); - mService = (StatusBarManager) context.getSystemService(Context.STATUS_BAR_SERVICE); mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); mUserInfoController = userInfoController; mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); @@ -153,40 +148,40 @@ public class PhoneStatusBarPolicy implements Callback { } // TTY status - mService.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, 0, null); - mService.setIconVisibility(SLOT_TTY, false); + mIconController.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, null); + mIconController.setIconVisibility(SLOT_TTY, false); // bluetooth status updateBluetooth(); // Alarm clock - mService.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, 0, null); - mService.setIconVisibility(SLOT_ALARM_CLOCK, false); + mIconController.setIcon(SLOT_ALARM_CLOCK, R.drawable.stat_sys_alarm, null); + mIconController.setIconVisibility(SLOT_ALARM_CLOCK, false); // zen - mService.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, 0, null); - mService.setIconVisibility(SLOT_ZEN, false); + mIconController.setIcon(SLOT_ZEN, R.drawable.stat_sys_zen_important, null); + mIconController.setIconVisibility(SLOT_ZEN, false); // volume - mService.setIcon(SLOT_VOLUME, R.drawable.stat_sys_ringer_vibrate, 0, null); - mService.setIconVisibility(SLOT_VOLUME, false); + mIconController.setIcon(SLOT_VOLUME, R.drawable.stat_sys_ringer_vibrate, null); + mIconController.setIconVisibility(SLOT_VOLUME, false); updateVolumeZen(); // cast - mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, null); - mService.setIconVisibility(SLOT_CAST, false); + mIconController.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, null); + mIconController.setIconVisibility(SLOT_CAST, false); mCast.addCallback(mCastCallback); // hotspot - mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, + mIconController.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, mContext.getString(R.string.accessibility_status_bar_hotspot)); - mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled()); + mIconController.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled()); mHotspot.addCallback(mHotspotCallback); // managed profile - mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0, + mIconController.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, mContext.getString(R.string.accessibility_managed_profile)); - mService.setIconVisibility(SLOT_MANAGED_PROFILE, mManagedProfileIconVisible); + mIconController.setIconVisibility(SLOT_MANAGED_PROFILE, mManagedProfileIconVisible); } public void setZenMode(int zen) { @@ -198,32 +193,27 @@ public class PhoneStatusBarPolicy implements Callback { final AlarmClockInfo alarm = mAlarmManager.getNextAlarmClock(UserHandle.USER_CURRENT); final boolean hasAlarm = alarm != null && alarm.getTriggerTime() > 0; final boolean zenNone = mZen == Global.ZEN_MODE_NO_INTERRUPTIONS; - mService.setIcon(SLOT_ALARM_CLOCK, zenNone ? R.drawable.stat_sys_alarm_dim - : R.drawable.stat_sys_alarm, 0, null); - mService.setIconVisibility(SLOT_ALARM_CLOCK, mCurrentUserSetup && hasAlarm); + mIconController.setIcon(SLOT_ALARM_CLOCK, zenNone ? R.drawable.stat_sys_alarm_dim + : R.drawable.stat_sys_alarm, null); + mIconController.setIconVisibility(SLOT_ALARM_CLOCK, mCurrentUserSetup && hasAlarm); } private final void updateSimState(Intent intent) { String stateExtra = intent.getStringExtra(IccCardConstants.INTENT_KEY_ICC_STATE); if (IccCardConstants.INTENT_VALUE_ICC_ABSENT.equals(stateExtra)) { mSimState = IccCardConstants.State.ABSENT; - } - else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) { + } else if (IccCardConstants.INTENT_VALUE_ICC_CARD_IO_ERROR.equals(stateExtra)) { mSimState = IccCardConstants.State.CARD_IO_ERROR; - } - else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { + } else if (IccCardConstants.INTENT_VALUE_ICC_READY.equals(stateExtra)) { mSimState = IccCardConstants.State.READY; - } - else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { + } else if (IccCardConstants.INTENT_VALUE_ICC_LOCKED.equals(stateExtra)) { final String lockedReason = intent.getStringExtra(IccCardConstants.INTENT_KEY_LOCKED_REASON); if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PIN.equals(lockedReason)) { mSimState = IccCardConstants.State.PIN_REQUIRED; - } - else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { + } else if (IccCardConstants.INTENT_VALUE_LOCKED_ON_PUK.equals(lockedReason)) { mSimState = IccCardConstants.State.PUK_REQUIRED; - } - else { + } else { mSimState = IccCardConstants.State.NETWORK_LOCKED; } } else { @@ -270,18 +260,18 @@ public class PhoneStatusBarPolicy implements Callback { } if (zenVisible) { - mService.setIcon(SLOT_ZEN, zenIconId, 0, zenDescription); + mIconController.setIcon(SLOT_ZEN, zenIconId, zenDescription); } if (zenVisible != mZenVisible) { - mService.setIconVisibility(SLOT_ZEN, zenVisible); + mIconController.setIconVisibility(SLOT_ZEN, zenVisible); mZenVisible = zenVisible; } if (volumeVisible) { - mService.setIcon(SLOT_VOLUME, volumeIconId, 0, volumeDescription); + mIconController.setIcon(SLOT_VOLUME, volumeIconId, volumeDescription); } if (volumeVisible != mVolumeVisible) { - mService.setIconVisibility(SLOT_VOLUME, volumeVisible); + mIconController.setIconVisibility(SLOT_VOLUME, volumeVisible); mVolumeVisible = volumeVisible; } updateAlarm(); @@ -310,8 +300,8 @@ public class PhoneStatusBarPolicy implements Callback { } } - mService.setIcon(SLOT_BLUETOOTH, iconId, 0, contentDescription); - mService.setIconVisibility(SLOT_BLUETOOTH, bluetoothEnabled); + mIconController.setIcon(SLOT_BLUETOOTH, iconId, contentDescription); + mIconController.setIconVisibility(SLOT_BLUETOOTH, bluetoothEnabled); } private final void updateTTY(Intent intent) { @@ -324,13 +314,13 @@ public class PhoneStatusBarPolicy implements Callback { if (enabled) { // TTY is on if (DEBUG) Log.v(TAG, "updateTTY: set TTY on"); - mService.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, 0, + mIconController.setIcon(SLOT_TTY, R.drawable.stat_sys_tty_mode, mContext.getString(R.string.accessibility_tty_enabled)); - mService.setIconVisibility(SLOT_TTY, true); + mIconController.setIconVisibility(SLOT_TTY, true); } else { // TTY is off if (DEBUG) Log.v(TAG, "updateTTY: set TTY off"); - mService.setIconVisibility(SLOT_TTY, false); + mIconController.setIconVisibility(SLOT_TTY, false); } } @@ -346,9 +336,9 @@ public class PhoneStatusBarPolicy implements Callback { if (DEBUG) Log.v(TAG, "updateCast: isCasting: " + isCasting); mHandler.removeCallbacks(mRemoveCastIconRunnable); if (isCasting) { - mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, + mIconController.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, mContext.getString(R.string.accessibility_casting)); - mService.setIconVisibility(SLOT_CAST, true); + mIconController.setIconVisibility(SLOT_CAST, true); } else { // don't turn off the screen-record icon for a few seconds, just to make sure the user // has seen it @@ -392,17 +382,19 @@ public class PhoneStatusBarPolicy implements Callback { final boolean showIcon; if (mManagedProfileFocused && !mKeyguardVisible) { showIcon = true; - mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status, 0, + mIconController.setIcon(SLOT_MANAGED_PROFILE, + R.drawable.stat_sys_managed_profile_status, mContext.getString(R.string.accessibility_managed_profile)); } else if (mManagedProfileInQuietMode) { showIcon = true; - mService.setIcon(SLOT_MANAGED_PROFILE, R.drawable.stat_sys_managed_profile_status_off, 0, + mIconController.setIcon(SLOT_MANAGED_PROFILE, + R.drawable.stat_sys_managed_profile_status_off, mContext.getString(R.string.accessibility_managed_profile)); } else { showIcon = false; } if (mManagedProfileIconVisible != showIcon) { - mService.setIconVisibility(SLOT_MANAGED_PROFILE, showIcon); + mIconController.setIconVisibility(SLOT_MANAGED_PROFILE, showIcon); mManagedProfileIconVisible = showIcon; } } @@ -431,7 +423,7 @@ public class PhoneStatusBarPolicy implements Callback { private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() { @Override public void onHotspotChanged(boolean enabled) { - mService.setIconVisibility(SLOT_HOTSPOT, enabled); + mIconController.setIconVisibility(SLOT_HOTSPOT, enabled); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java index c0887ca78b25..ab37e6abc32b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -51,7 +51,6 @@ public class PhoneStatusBarView extends PanelBar { public PhoneStatusBarView(Context context, AttributeSet attrs) { super(context, attrs); - Resources res = getContext().getResources(); mBarTransitions = new PhoneStatusBarTransitions(this); } @@ -102,7 +101,6 @@ public class PhoneStatusBarView extends PanelBar { @Override public PanelView selectPanelForTouch(MotionEvent touch) { - // No double swiping. If either panel is open, nothing else can be pulled down. return mNotificationPanel.getExpandedHeight() > 0 ? null : mNotificationPanel; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java index 90a688ff4364..336b208cb50b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -95,17 +95,19 @@ public final class QSTileHost implements QSTile.Host, Tunable { private final KeyguardMonitor mKeyguard; private final SecurityController mSecurity; private final BatteryController mBattery; + private final StatusBarIconController mIconController; private final TileServices mServices; private final List<Callback> mCallbacks = new ArrayList<>(); public QSTileHost(Context context, PhoneStatusBar statusBar, - BluetoothController bluetooth, LocationController location, - RotationLockController rotation, NetworkController network, - ZenModeController zen, HotspotController hotspot, - CastController cast, FlashlightController flashlight, - UserSwitcherController userSwitcher, UserInfoController userInfo, KeyguardMonitor keyguard, - SecurityController security, BatteryController battery) { + BluetoothController bluetooth, LocationController location, + RotationLockController rotation, NetworkController network, + ZenModeController zen, HotspotController hotspot, + CastController cast, FlashlightController flashlight, + UserSwitcherController userSwitcher, UserInfoController userInfo, + KeyguardMonitor keyguard, SecurityController security, + BatteryController battery, StatusBarIconController iconController) { mContext = context; mStatusBar = statusBar; mBluetooth = bluetooth; @@ -121,6 +123,7 @@ public final class QSTileHost implements QSTile.Host, Tunable { mKeyguard = keyguard; mSecurity = security; mBattery = battery; + mIconController = iconController; final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(), Process.THREAD_PRIORITY_BACKGROUND); @@ -258,6 +261,10 @@ public final class QSTileHost implements QSTile.Host, Tunable { return mServices; } + public StatusBarIconController getIconController() { + return mIconController; + } + @Override public void onTuningChanged(String key, String newValue) { if (!TILES_SETTING.equals(key)) { @@ -332,7 +339,10 @@ public final class QSTileHost implements QSTile.Host, Tunable { // Intent tiles. else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec); else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec); - else throw new IllegalArgumentException("Bad tile spec: " + tileSpec); + else { + Log.w(TAG, "Bad tile spec: " + tileSpec); + return null; + } } public static List<String> loadTileSpecs(Context context, String tileList) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java index 1372ccaa824e..3692aeeb20c5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java @@ -24,7 +24,6 @@ import android.graphics.Rect; import android.graphics.drawable.Animatable; import android.graphics.drawable.RippleDrawable; import android.util.AttributeSet; -import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -135,7 +134,6 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements @Override public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) { mNextAlarm = nextAlarm; - Log.d(TAG, "Got alarm update " + (nextAlarm != null)); if (nextAlarm != null) { mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm)); } @@ -179,10 +177,8 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements private void updateListeners() { if (mListening) { - Log.d(TAG, "Listening for Alarms"); mNextAlarmController.addStateChangedCallback(this); } else { - Log.d(TAG, "Not listening for Alarms"); mNextAlarmController.removeStateChangedCallback(this); } } @@ -209,7 +205,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements host.getCastController(), host.getFlashlightController(), host.getUserSwitcherController(), host.getUserInfoController(), host.getKeyguardMonitor(), host.getSecurityController(), - host.getBatteryController()); + host.getBatteryController(), host.getIconController()); mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this); mHeaderQsPanel.setHost(myHost); mHeaderQsPanel.setMaxTiles(5); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java index d5b980e59307..5e98ec1a5b60 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconController.java @@ -21,9 +21,11 @@ import android.animation.ValueAnimator; import android.content.Context; import android.content.res.ColorStateList; import android.graphics.Color; +import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; +import android.os.UserHandle; import android.text.TextUtils; import android.util.ArraySet; import android.view.View; @@ -33,7 +35,6 @@ import android.view.animation.Interpolator; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; - import com.android.internal.statusbar.StatusBarIcon; import com.android.internal.util.NotificationColorUtil; import com.android.systemui.BatteryMeterView; @@ -54,7 +55,7 @@ import java.util.ArrayList; * limited to: notification icons, signal cluster, additional status icons, and clock in the status * bar. */ -public class StatusBarIconController implements Tunable { +public class StatusBarIconController extends StatusBarIconList implements Tunable { public static final long DEFAULT_TINT_ANIMATION_DURATION = 120; @@ -146,23 +147,27 @@ public class StatusBarIconController implements Tunable { } // Remove all the icons. for (int i = views.size() - 1; i >= 0; i--) { - removeSystemIcon(views.get(i).getSlot(), i, i); + removeIcon(views.get(i).getSlot()); } // Add them all back for (int i = 0; i < views.size(); i++) { - addSystemIcon(views.get(i).getSlot(), i, i, views.get(i).getStatusBarIcon()); + setIcon(views.get(i).getSlot(), views.get(i).getStatusBarIcon()); } - }; + } public void updateResources() { mIconSize = mContext.getResources().getDimensionPixelSize( com.android.internal.R.dimen.status_bar_icon_size); mIconHPadding = mContext.getResources().getDimensionPixelSize( R.dimen.status_bar_icon_padding); + defineSlots(mContext.getResources().getStringArray( + com.android.internal.R.array.config_statusBarIcons)); FontSizeUtils.updateFontSize(mClock, R.dimen.status_bar_clock_size); } - public void addSystemIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { + private void addSystemIcon(int index, StatusBarIcon icon) { + String slot = getSlot(index); + int viewIndex = getViewIndex(index); boolean blocked = mIconBlacklist.contains(slot); StatusBarIconView view = new StatusBarIconView(mContext, slot, null, blocked); view.set(icon); @@ -175,8 +180,77 @@ public class StatusBarIconController implements Tunable { applyIconTint(); } - public void updateSystemIcon(String slot, int index, int viewIndex, - StatusBarIcon old, StatusBarIcon icon) { + public void setIcon(String slot, int resourceId, CharSequence contentDescription) { + int index = getSlotIndex(slot); + StatusBarIcon icon = getIcon(index); + if (icon == null) { + icon = new StatusBarIcon(UserHandle.SYSTEM, mContext.getPackageName(), + Icon.createWithResource(mContext, resourceId), 0, 0, contentDescription); + setIcon(slot, icon); + } else { + icon.icon = Icon.createWithResource(mContext, resourceId); + icon.contentDescription = contentDescription; + handleSet(index, icon); + } + } + + public void setExternalIcon(String slot) { + int viewIndex = getViewIndex(getSlotIndex(slot)); + ImageView imageView = (ImageView) mStatusIcons.getChildAt(viewIndex); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setAdjustViewBounds(true); + imageView = (ImageView) mStatusIconsKeyguard.getChildAt(viewIndex); + imageView.setScaleType(ImageView.ScaleType.FIT_CENTER); + imageView.setAdjustViewBounds(true); + } + + public void setIcon(String slot, StatusBarIcon icon) { + setIcon(getSlotIndex(slot), icon); + } + + public void removeIcon(String slot) { + int index = getSlotIndex(slot); + removeIcon(index); + } + + public void setIconVisibility(String slot, boolean visibility) { + int index = getSlotIndex(slot); + StatusBarIcon icon = getIcon(index); + if (icon == null || icon.visible == visibility) { + return; + } + icon.visible = visibility; + handleSet(index, icon); + } + + @Override + public void removeIcon(int index) { + if (getIcon(index) == null) { + return; + } + super.removeIcon(index); + int viewIndex = getViewIndex(index); + mStatusIcons.removeViewAt(viewIndex); + mStatusIconsKeyguard.removeViewAt(viewIndex); + } + + @Override + public void setIcon(int index, StatusBarIcon icon) { + if (icon == null) { + removeIcon(index); + return; + } + boolean isNew = getIcon(index) == null; + super.setIcon(index, icon); + if (isNew) { + addSystemIcon(index, icon); + } else { + handleSet(index, icon); + } + } + + private void handleSet(int index, StatusBarIcon icon) { + int viewIndex = getViewIndex(index); StatusBarIconView view = (StatusBarIconView) mStatusIcons.getChildAt(viewIndex); view.set(icon); view = (StatusBarIconView) mStatusIconsKeyguard.getChildAt(viewIndex); @@ -184,11 +258,6 @@ public class StatusBarIconController implements Tunable { applyIconTint(); } - public void removeSystemIcon(String slot, int index, int viewIndex) { - mStatusIcons.removeViewAt(viewIndex); - mStatusIconsKeyguard.removeViewAt(viewIndex); - } - public void updateNotificationIcons(NotificationData notificationData) { final LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( mIconSize + 2*mIconHPadding, mPhoneStatusBar.getStatusBarHeight()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java new file mode 100644 index 000000000000..62d6b7675a05 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarIconList.java @@ -0,0 +1,86 @@ +/* + * 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.statusbar.phone; + +import com.android.internal.statusbar.StatusBarIcon; + +import java.io.PrintWriter; +import java.util.ArrayList; + +public class StatusBarIconList { + private ArrayList<String> mSlots = new ArrayList<>(); + private ArrayList<StatusBarIcon> mIcons = new ArrayList<>(); + + public void defineSlots(String[] slots) { + final int N = slots.length; + for (int i=0; i < N; i++) { + mSlots.add(slots[i]); + mIcons.add(null); + } + } + + public int getSlotIndex(String slot) { + final int N = mSlots.size(); + for (int i=0; i<N; i++) { + if (slot.equals(mSlots.get(i))) { + return i; + } + } + // Auto insert new items at the beginning. + mSlots.add(0, slot); + mIcons.add(0, null); + return 0; + } + + public int size() { + return mSlots.size(); + } + + public void setIcon(int index, StatusBarIcon icon) { + mIcons.set(index, icon); + } + + public void removeIcon(int index) { + mIcons.set(index, null); + } + + public String getSlot(int index) { + return mSlots.get(index); + } + + public StatusBarIcon getIcon(int index) { + return mIcons.get(index); + } + + public int getViewIndex(int index) { + int count = 0; + for (int i = 0; i < index; i++) { + if (mIcons.get(i) != null) { + count++; + } + } + return count; + } + + public void dump(PrintWriter pw) { + final int N = mSlots.size(); + pw.println("Icon list:"); + for (int i=0; i<N; i++) { + pw.printf(" %2d: (%s) %s\n", i, mSlots.get(i), mIcons.get(i)); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 05f6e57d9199..f14f0d4c28a4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -31,6 +31,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.ViewMediatorCallback; import com.android.systemui.statusbar.CommandQueue; +import com.android.systemui.statusbar.RemoteInputController; import static com.android.keyguard.KeyguardHostView.OnDismissAction; @@ -40,7 +41,7 @@ import static com.android.keyguard.KeyguardHostView.OnDismissAction; * which is in turn, reported to this class by the current * {@link com.android.keyguard.KeyguardViewBase}. */ -public class StatusBarKeyguardViewManager { +public class StatusBarKeyguardViewManager implements RemoteInputController.Callback { // When hiding the Keyguard with timing supplied from WindowManager, better be early than late. private static final long HIDE_TIMING_CORRECTION_MS = -3 * 16; @@ -69,12 +70,15 @@ public class StatusBarKeyguardViewManager { private KeyguardBouncer mBouncer; private boolean mShowing; private boolean mOccluded; + private boolean mRemoteInputActive; private boolean mFirstUpdate = true; private boolean mLastShowing; private boolean mLastOccluded; private boolean mLastBouncerShowing; private boolean mLastBouncerDismissible; + private boolean mLastRemoteInputActive; + private OnDismissAction mAfterKeyguardGoneAction; private boolean mDeviceWillWakeUp; private boolean mDeferScrimFadeOut; @@ -199,6 +203,12 @@ public class StatusBarKeyguardViewManager { mPhoneStatusBar.onScreenTurnedOn(); } + @Override + public void onRemoteInputActive(boolean active) { + mRemoteInputActive = active; + updateStates(); + } + public void onScreenTurnedOff() { mScreenTurnedOn = false; } @@ -429,18 +439,21 @@ public class StatusBarKeyguardViewManager { boolean occluded = mOccluded; boolean bouncerShowing = mBouncer.isShowing(); boolean bouncerDismissible = !mBouncer.isFullscreenBouncer(); + boolean remoteInputActive = mRemoteInputActive; - if ((bouncerDismissible || !showing) != (mLastBouncerDismissible || !mLastShowing) + if ((bouncerDismissible || !showing || remoteInputActive) != + (mLastBouncerDismissible || !mLastShowing || mLastRemoteInputActive) || mFirstUpdate) { - if (bouncerDismissible || !showing) { + if (bouncerDismissible || !showing || remoteInputActive) { mContainer.setSystemUiVisibility(vis & ~View.STATUS_BAR_DISABLE_BACK); } else { mContainer.setSystemUiVisibility(vis | View.STATUS_BAR_DISABLE_BACK); } } - boolean navBarVisible = (!(showing && !occluded) || bouncerShowing); - boolean lastNavBarVisible = (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing); + boolean navBarVisible = (!(showing && !occluded) || bouncerShowing || remoteInputActive); + boolean lastNavBarVisible = (!(mLastShowing && !mLastOccluded) || mLastBouncerShowing + || mLastRemoteInputActive); if (navBarVisible != lastNavBarVisible || mFirstUpdate) { if (mPhoneStatusBar.getNavigationBarView() != null) { if (navBarVisible) { @@ -477,6 +490,7 @@ public class StatusBarKeyguardViewManager { mLastOccluded = occluded; mLastBouncerShowing = bouncerShowing; mLastBouncerDismissible = bouncerDismissible; + mLastRemoteInputActive = remoteInputActive; mPhoneStatusBar.onKeyguardViewManagerStatesUpdated(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java index abe51ac3a5d0..9d2f0de4c1e0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java @@ -30,6 +30,7 @@ import android.view.WindowManager; import com.android.keyguard.R; import com.android.systemui.keyguard.KeyguardViewMediator; import com.android.systemui.statusbar.BaseStatusBar; +import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarState; import java.io.FileDescriptor; @@ -39,7 +40,7 @@ import java.lang.reflect.Field; /** * Encapsulates all logic for the status bar window state management. */ -public class StatusBarWindowManager { +public class StatusBarWindowManager implements RemoteInputController.Callback { private final Context mContext; private final WindowManager mWindowManager; @@ -292,7 +293,8 @@ public class StatusBarWindowManager { apply(mCurrentState); } - public void setRemoteInputActive(boolean remoteInputActive) { + @Override + public void onRemoteInputActive(boolean remoteInputActive) { mCurrentState.remoteInputActive = remoteInputActive; apply(mCurrentState); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java index 44b41c55b4de..0406ae3e7920 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java @@ -33,16 +33,11 @@ import com.android.systemui.statusbar.NotificationData; public class TvStatusBar extends BaseStatusBar { @Override - public void addIcon(String slot, int index, int viewIndex, StatusBarIcon icon) { + public void setIcon(String slot, StatusBarIcon icon) { } @Override - public void updateIcon(String slot, int index, int viewIndex, StatusBarIcon old, - StatusBarIcon icon) { - } - - @Override - public void removeIcon(String slot, int index, int viewIndex) { + public void removeIcon(String slot) { } @Override diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java index 9081af156f00..47a4667f29f0 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java @@ -32,7 +32,7 @@ import android.os.Looper; import android.os.UserHandle; import android.provider.Settings; import android.util.ArrayMap; - +import android.util.ArraySet; import com.android.systemui.BatteryMeterDrawable; import com.android.systemui.DemoMode; import com.android.systemui.R; @@ -41,9 +41,8 @@ import com.android.systemui.SystemUIApplication; import com.android.systemui.settings.CurrentUserTracker; import com.android.systemui.statusbar.phone.SystemUIDialog; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; +import java.util.Set; public class TunerService extends SystemUI { @@ -54,7 +53,7 @@ public class TunerService extends SystemUI { // Map of Uris we listen on to their settings keys. private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>(); // Map of settings keys to the listener. - private final HashMap<String, List<Tunable>> mTunableLookup = new HashMap<>(); + private final HashMap<String, Set<Tunable>> mTunableLookup = new HashMap<>(); private ContentResolver mContentResolver; private int mCurrentUser; @@ -85,7 +84,7 @@ public class TunerService extends SystemUI { private void addTunable(Tunable tunable, String key) { if (!mTunableLookup.containsKey(key)) { - mTunableLookup.put(key, new ArrayList<Tunable>()); + mTunableLookup.put(key, new ArraySet<Tunable>()); } mTunableLookup.get(key).add(tunable); Uri uri = Settings.Secure.getUriFor(key); @@ -99,7 +98,7 @@ public class TunerService extends SystemUI { } public void removeTunable(Tunable tunable) { - for (List<Tunable> list : mTunableLookup.values()) { + for (Set<Tunable> list : mTunableLookup.values()) { list.remove(tunable); } } @@ -116,7 +115,7 @@ public class TunerService extends SystemUI { public void reloadSetting(Uri uri) { String key = mListeningUris.get(uri); - List<Tunable> tunables = mTunableLookup.get(key); + Set<Tunable> tunables = mTunableLookup.get(key); if (tunables == null) { return; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java index 7a3ce878b8cc..c4ca039fab0c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java @@ -35,7 +35,7 @@ public class TileServicesTests extends SysuiTestCase { super.setUp(); mManagers = new ArrayList<>(); QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null, - null, null, null, null, null, null); + null, null, null, null, null, null, null); mTileService = new TestTileServices(host, Looper.myLooper()); } diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java index 4569daee029e..b5ea64123311 100644 --- a/services/core/java/com/android/server/AssetAtlasService.java +++ b/services/core/java/com/android/server/AssetAtlasService.java @@ -176,7 +176,8 @@ public class AssetAtlasService extends IAssetAtlas.Stub { private static String queryVersionName(Context context) { try { String packageName = context.getPackageName(); - PackageInfo info = context.getPackageManager().getPackageInfo(packageName, 0); + PackageInfo info = context.getPackageManager().getPackageInfo(packageName, + PackageManager.MATCH_DEBUG_TRIAGED_MISSING); return info.versionName; } catch (PackageManager.NameNotFoundException e) { Log.w(LOG_TAG, "Could not get package info", e); diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index f329cff2c98d..c1a082b3cb11 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -268,8 +268,8 @@ class BluetoothManagerService extends IBluetoothManager.Stub { int sysUiUid = -1; try { - sysUiUid = mContext.getPackageManager().getPackageUid("com.android.systemui", - UserHandle.USER_SYSTEM); + sysUiUid = mContext.getPackageManager().getPackageUidAsUser("com.android.systemui", + PackageManager.MATCH_SYSTEM_ONLY, UserHandle.USER_SYSTEM); } catch (PackageManager.NameNotFoundException e) { // Some platforms, such as wearables do not have a system ui. Log.w(TAG, "Unable to resolve SystemUI's UID.", e); diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index f5ed83ed5f1d..bd9589234b38 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -1052,12 +1052,11 @@ public class DeviceIdleController extends SystemService for (int i=0; i<allowPowerExceptIdle.size(); i++) { String pkg = allowPowerExceptIdle.valueAt(i); try { - ApplicationInfo ai = pm.getApplicationInfo(pkg, 0); - if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - int appid = UserHandle.getAppId(ai.uid); - mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid); - mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true); - } + ApplicationInfo ai = pm.getApplicationInfo(pkg, + PackageManager.MATCH_SYSTEM_ONLY); + int appid = UserHandle.getAppId(ai.uid); + mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid); + mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true); } catch (PackageManager.NameNotFoundException e) { } } @@ -1065,16 +1064,15 @@ public class DeviceIdleController extends SystemService for (int i=0; i<allowPower.size(); i++) { String pkg = allowPower.valueAt(i); try { - ApplicationInfo ai = pm.getApplicationInfo(pkg, 0); - if ((ai.flags&ApplicationInfo.FLAG_SYSTEM) != 0) { - int appid = UserHandle.getAppId(ai.uid); - // These apps are on both the whitelist-except-idle as well - // as the full whitelist, so they apply in all cases. - mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid); - mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true); - mPowerSaveWhitelistApps.put(ai.packageName, appid); - mPowerSaveWhitelistSystemAppIds.put(appid, true); - } + ApplicationInfo ai = pm.getApplicationInfo(pkg, + PackageManager.MATCH_SYSTEM_ONLY); + int appid = UserHandle.getAppId(ai.uid); + // These apps are on both the whitelist-except-idle as well + // as the full whitelist, so they apply in all cases. + mPowerSaveWhitelistAppsExceptIdle.put(ai.packageName, appid); + mPowerSaveWhitelistSystemAppIdsExceptIdle.put(appid, true); + mPowerSaveWhitelistApps.put(ai.packageName, appid); + mPowerSaveWhitelistSystemAppIds.put(appid, true); } catch (PackageManager.NameNotFoundException e) { } } @@ -1182,9 +1180,7 @@ public class DeviceIdleController extends SystemService synchronized (this) { try { ApplicationInfo ai = getContext().getPackageManager().getApplicationInfo(name, - PackageManager.GET_UNINSTALLED_PACKAGES - | PackageManager.GET_DISABLED_COMPONENTS - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); + PackageManager.MATCH_UNINSTALLED_PACKAGES); if (mPowerSaveWhitelistUserApps.put(name, UserHandle.getAppId(ai.uid)) == null) { reportPowerSaveWhitelistChangedLocked(); updateWhitelistAppIdsLocked(); @@ -1326,7 +1322,7 @@ public class DeviceIdleController extends SystemService void addPowerSaveTempWhitelistAppInternal(int callingUid, String packageName, long duration, int userId, boolean sync, String reason) { try { - int uid = getContext().getPackageManager().getPackageUid(packageName, userId); + int uid = getContext().getPackageManager().getPackageUidAsUser(packageName, userId); int appId = UserHandle.getAppId(uid); addPowerSaveTempWhitelistAppDirectInternal(callingUid, appId, duration, sync, reason); } catch (NameNotFoundException e) { @@ -2010,9 +2006,7 @@ public class DeviceIdleController extends SystemService if (name != null) { try { ApplicationInfo ai = pm.getApplicationInfo(name, - PackageManager.GET_UNINSTALLED_PACKAGES - | PackageManager.GET_DISABLED_COMPONENTS - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS); + PackageManager.MATCH_UNINSTALLED_PACKAGES); mPowerSaveWhitelistUserApps.put(ai.packageName, UserHandle.getAppId(ai.uid)); } catch (PackageManager.NameNotFoundException e) { diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 04abccace0a7..15b55026ae66 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -2383,10 +2383,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return; } synchronized (mMethodMap) { - if (mCurClient == null || client == null - || mCurClient.client.asBinder() != client.asBinder()) { - Slog.w(TAG, "Ignoring showInputMethodAndSubtypeEnablerFromClient of: " + client); - } executeOrSendMessage(mCurMethod, mCaller.obtainMessageO( MSG_SHOW_IM_SUBTYPE_ENABLER, inputMethodId)); } @@ -2716,9 +2712,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub return true; case MSG_SHOW_IM_SUBTYPE_ENABLER: - args = (SomeArgs)msg.obj; - showInputMethodAndSubtypeEnabler((String)args.arg1); - args.recycle(); + showInputMethodAndSubtypeEnabler((String)msg.obj); return true; case MSG_SHOW_IM_CONFIG: @@ -3005,7 +2999,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (!TextUtils.isEmpty(inputMethodId)) { intent.putExtra(Settings.EXTRA_INPUT_METHOD_ID, inputMethodId); } - mContext.startActivityAsUser(intent, null, UserHandle.CURRENT); + final int userId; + synchronized (mMethodMap) { + userId = mSettings.getCurrentUserId(); + } + mContext.startActivityAsUser(intent, null, UserHandle.of(userId)); } private void showConfigureInputMethods() { diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java index e8b90d893ec5..a291cc72ea60 100644 --- a/services/core/java/com/android/server/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/PersistentDataBlockService.java @@ -94,7 +94,8 @@ public class PersistentDataBlockService extends SystemService { PackageManager pm = mContext.getPackageManager(); int allowedUid = -1; try { - allowedUid = pm.getPackageUid(allowedPackage, userHandle); + allowedUid = pm.getPackageUidAsUser(allowedPackage, + PackageManager.MATCH_SYSTEM_ONLY, userHandle); } catch (PackageManager.NameNotFoundException e) { // not expected Slog.e(TAG, "not able to find package " + allowedPackage, e); diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index 4348913a2885..d12eadb37164 100755 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -1211,10 +1211,11 @@ public final class ActiveServices { } if (r == null) { try { - ResolveInfo rInfo = - AppGlobals.getPackageManager().resolveService( - service, resolvedType, - ActivityManagerService.STOCK_PM_FLAGS, userId); + // TODO: come back and remove this assumption to triage all services + ResolveInfo rInfo = AppGlobals.getPackageManager().resolveService(service, + resolvedType, ActivityManagerService.STOCK_PM_FLAGS + | PackageManager.MATCH_DEBUG_TRIAGED_MISSING, + userId); ServiceInfo sInfo = rInfo != null ? rInfo.serviceInfo : null; if (sInfo == null) { @@ -1244,7 +1245,7 @@ public final class ActiveServices { sInfo.applicationInfo.uid, sInfo.packageName, callingPid); if (allowed != ActivityManager.APP_START_MODE_NORMAL) { Slog.w(TAG, "Background execution not allowed: service " - + r.intent + " to " + name.flattenToShortString() + + service + " to " + name.flattenToShortString() + " from pid=" + callingPid + " uid=" + callingUid + " pkg=" + callingPackage); return null; diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 617169482ec4..ffa7cf38146f 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -255,6 +255,8 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT; import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE; +import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES; import static android.provider.Settings.Global.DEBUG_APP; @@ -1952,6 +1954,7 @@ public final class ActivityManagerService extends ActivityManagerNative } case SYSTEM_USER_UNLOCK_MSG: { mSystemServiceManager.unlockUser(msg.arg1); + mRecentTasks.cleanupLocked(msg.arg1); break; } case SYSTEM_USER_CURRENT_MSG: { @@ -2290,7 +2293,7 @@ public final class ActivityManagerService extends ActivityManagerNative ServiceManager.addService("processinfo", new ProcessInfoService(this)); ApplicationInfo info = mContext.getPackageManager().getApplicationInfo( - "android", STOCK_PM_FLAGS); + "android", STOCK_PM_FLAGS | MATCH_SYSTEM_ONLY); mSystemThread.installSystemApplicationInfo(info, getClass().getClassLoader()); synchronized (this) { @@ -2764,8 +2767,7 @@ public final class ActivityManagerService extends ActivityManagerNative } if (!r.isFocusable()) { - if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, - "setFocusedActivityLocked: unfocusable r=" + r); + if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: unfocusable r=" + r); return false; } @@ -2874,9 +2876,8 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (ActivityManagerService.this) { TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId); if (task != null) { - ActivityRecord r = task.topRunningActivityLocked(); - if (r != null) { - setFocusedActivityLocked(r, "setFocusedTask"); + final ActivityRecord r = task.topRunningActivityLocked(); + if (setFocusedActivityLocked(r, "setFocusedTask")) { mStackSupervisor.resumeFocusedStackTopActivityLocked(); } } @@ -3444,7 +3445,8 @@ public final class ActivityManagerService extends ActivityManagerNative try { checkTime(startTime, "startProcess: getting gids from package manager"); final IPackageManager pm = AppGlobals.getPackageManager(); - permGids = pm.getPackageGids(app.info.packageName, app.userId); + permGids = pm.getPackageGidsEtc(app.info.packageName, + MATCH_DEBUG_TRIAGED_MISSING, app.userId); MountServiceInternal mountServiceInternal = LocalServices.getService( MountServiceInternal.class); mountExternal = mountServiceInternal.getExternalStorageMountMode(uid, @@ -4407,7 +4409,6 @@ public final class ActivityManagerService extends ActivityManagerNative throw new IllegalArgumentException("startActivityFromRecentsInner: Task " + taskId + " can't be launch in the home stack."); } - task = mStackSupervisor.anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId); if (task == null) { throw new IllegalArgumentException( @@ -4426,7 +4427,10 @@ public final class ActivityManagerService extends ActivityManagerNative } } - if (task.getRootActivity() != null) { + // 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. + if (!mUserController.shouldConfirmCredentials(task.userId) + && task.getRootActivity() != null) { moveTaskToFrontLocked(task.taskId, 0, bOptions); return ActivityManager.START_TASK_TO_FRONT; } @@ -8636,6 +8640,35 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override + public ParceledListSlice<android.content.UriPermission> getGrantedUriPermissions( + String packageName, int userId) { + enforceCallingPermission(android.Manifest.permission.GET_APP_GRANTED_URI_PERMISSIONS, + "getGrantedUriPermissions"); + + final ArrayList<android.content.UriPermission> result = Lists.newArrayList(); + synchronized (this) { + final int size = mGrantedUriPermissions.size(); + for (int i = 0; i < size; i++) { + final ArrayMap<GrantUri, UriPermission> perms = mGrantedUriPermissions.valueAt(i); + for (UriPermission perm : perms.values()) { + if (packageName.equals(perm.targetPkg) && perm.targetUserId == userId + && perm.persistedModeFlags != 0) { + result.add(perm.buildPersistedPublicApiObject()); + } + } + } + } + return new ParceledListSlice<android.content.UriPermission>(result); + } + + @Override + public void clearGrantedUriPermissions(String packageName, int userId) { + enforceCallingPermission(android.Manifest.permission.CLEAR_APP_GRANTED_URI_PERMISSIONS, + "clearGrantedUriPermissions"); + removeUriPermissionsForPackageLocked(packageName, userId, true); + } + + @Override public void showWaitingForDebugger(IApplicationThread who, boolean waiting) { synchronized (this) { ProcessRecord app = @@ -9460,23 +9493,23 @@ public final class ActivityManagerService extends ActivityManagerNative } @Override - public void moveActivityToStack(IBinder token, int stackId) throws RemoteException { - if (stackId == HOME_STACK_ID) { - throw new IllegalArgumentException( - "moveActivityToStack: Attempt to move token " + token + " to home stack"); - } + public void exitFreeformMode(IBinder token) throws RemoteException { synchronized (this) { long ident = Binder.clearCallingIdentity(); try { final ActivityRecord r = ActivityRecord.forTokenLocked(token); if (r == null) { throw new IllegalArgumentException( - "moveActivityToStack: No activity record matching token=" + token); + "exitFreeformMode: No activity record matching token=" + token); } - if (DEBUG_STACK) Slog.d(TAG_STACK, "moveActivityToStack: moving r=" + r - + " to stackId=" + stackId); - mStackSupervisor.moveTaskToStackLocked(r.task.taskId, stackId, ON_TOP, !FORCE_FOCUS, - "moveActivityToStack", ANIMATE); + final ActivityStack stack = r.getStackLocked(token); + if (stack == null || stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) { + throw new IllegalStateException( + "exitFreeformMode: You can only go fullscreen from freeform."); + } + if (DEBUG_STACK) Slog.d(TAG_STACK, "exitFreeformMode: " + r); + mStackSupervisor.moveTaskToStackLocked(r.task.taskId, FULLSCREEN_WORKSPACE_STACK_ID, + ON_TOP, !FORCE_FOCUS, "exitFreeformMode", ANIMATE); } finally { Binder.restoreCallingIdentity(ident); } @@ -9852,7 +9885,7 @@ public final class ActivityManagerService extends ActivityManagerNative ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager() .queryContentProviders(app.processName, app.uid, STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS - | PackageManager.MATCH_DEBUG_TRIAGED_MISSING); + | MATCH_DEBUG_TRIAGED_MISSING); providers = slice != null ? slice.getList() : null; } catch (RemoteException ex) { } @@ -11375,8 +11408,23 @@ public final class ActivityManagerService extends ActivityManagerNative } } - public void requestBugReport(boolean progress) { - final String service = progress ? "bugreportplus" : "bugreport"; + public void requestBugReport(int bugreportType) { + String service = null; + switch (bugreportType) { + case ActivityManager.BUGREPORT_OPTION_FULL: + service = "bugreport"; + break; + case ActivityManager.BUGREPORT_OPTION_INTERACTIVE: + service = "bugreportplus"; + break; + case ActivityManager.BUGREPORT_OPTION_REMOTE: + service = "bugreportremote"; + break; + } + if (service == null) { + throw new IllegalArgumentException("Provided bugreport type is not correct, value: " + + bugreportType); + } enforceCallingPermission(android.Manifest.permission.DUMP, "requestBugReport"); SystemProperties.set("ctl.start", service); } @@ -12250,6 +12298,17 @@ public final class ActivityManagerService extends ActivityManagerNative com.android.internal.R.dimen.thumbnail_height); mDefaultPinnedStackBounds = Rect.unflattenFromString(res.getString( com.android.internal.R.string.config_defaultPictureInPictureBounds)); + final String appsNotReportingCrashes = res.getString( + com.android.internal.R.string.config_appsNotReportingCrashes); + if (appsNotReportingCrashes != null) { + final String[] split = appsNotReportingCrashes.split(","); + if (split.length > 0) { + mAppsNotReportingCrashes = new ArraySet<>(); + for (int i = 0; i < split.length; i++) { + mAppsNotReportingCrashes.add(split[i]); + } + } + } } } @@ -14868,7 +14927,7 @@ public final class ActivityManagerService extends ActivityManagerNative int dumpUid = -2; if (dumpPackage != null) { try { - dumpUid = mContext.getPackageManager().getPackageUid(dumpPackage, 0); + dumpUid = mContext.getPackageManager().getPackageUidAsUser(dumpPackage, 0); } catch (NameNotFoundException e) { dumpUid = -1; } @@ -15795,18 +15854,17 @@ public final class ActivityManagerService extends ActivityManagerNative pw.println(totalPss - cachedPss); } } + long lostRAM = memInfo.getTotalSizeKb() + - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() + - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb(); if (!isCompact) { pw.print(" Used RAM: "); pw.print(stringifyKBSize(totalPss - cachedPss + memInfo.getKernelUsedSizeKb())); pw.print(" ("); pw.print(stringifyKBSize(totalPss - cachedPss)); pw.print(" used pss + "); pw.print(stringifyKBSize(memInfo.getKernelUsedSizeKb())); pw.print(" kernel)\n"); - pw.print(" Lost RAM: "); pw.println(stringifyKBSize(memInfo.getTotalSizeKb() - - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - - memInfo.getKernelUsedSizeKb())); + pw.print(" Lost RAM: "); pw.println(stringifyKBSize(lostRAM)); } else { - pw.print("lostram,"); pw.println(memInfo.getTotalSizeKb() - - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - - memInfo.getKernelUsedSizeKb()); + pw.print("lostram,"); pw.println(lostRAM); } if (!brief) { if (memInfo.getZramTotalSizeKb() != 0) { @@ -16104,7 +16162,7 @@ public final class ActivityManagerService extends ActivityManagerNative memInfoBuilder.append(" Lost RAM: "); memInfoBuilder.append(stringifyKBSize(memInfo.getTotalSizeKb() - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - - memInfo.getKernelUsedSizeKb())); + - memInfo.getKernelUsedSizeKb() - memInfo.getZramTotalSizeKb())); memInfoBuilder.append("\n"); Slog.i(TAG, "Low on memory:"); Slog.i(TAG, shortNativeBuilder.toString()); @@ -17067,7 +17125,7 @@ public final class ActivityManagerService extends ActivityManagerNative private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType, int callingUid, int[] users) { // TODO: come back and remove this assumption to triage all broadcasts - int pmFlags = STOCK_PM_FLAGS | PackageManager.MATCH_DEBUG_TRIAGED_MISSING; + int pmFlags = STOCK_PM_FLAGS | MATCH_DEBUG_TRIAGED_MISSING; List<ResolveInfo> receivers = null; try { @@ -17837,6 +17895,11 @@ public final class ActivityManagerService extends ActivityManagerNative "Unable to find instrumentation target package: " + ii.targetPackage); return false; } + if (!ai.hasCode()) { + reportStartInstrumentationFailure(watcher, className, + "Instrumentation target has no code: " + ii.targetPackage); + return false; + } int match = mContext.getPackageManager().checkSignatures( ii.targetPackage, ii.packageName); diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index 8d9cb5897bd6..e123dbd3d84a 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -21,8 +21,13 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION; +import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT; +import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE; +import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS; +import static android.content.res.Configuration.SCREENLAYOUT_UNDEFINED; import static com.android.server.am.ActivityManagerDebugConfig.*; import static com.android.server.am.ActivityManagerService.LOCK_SCREEN_SHOWN; import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE; @@ -4224,20 +4229,20 @@ final class ActivityStack { int taskChanges = oldTaskOverride.diff(taskConfig); // We don't want to use size changes if they don't cross boundaries that are important to // the app. - if ((taskChanges & ActivityInfo.CONFIG_SCREEN_SIZE) != 0) { + if ((taskChanges & CONFIG_SCREEN_SIZE) != 0) { final boolean crosses = record.crossesHorizontalSizeThreshold( oldTaskOverride.screenWidthDp, taskConfig.screenWidthDp) || record.crossesVerticalSizeThreshold( oldTaskOverride.screenHeightDp, taskConfig.screenHeightDp); if (!crosses) { - taskChanges &= ~ActivityInfo.CONFIG_SCREEN_SIZE; + taskChanges &= ~CONFIG_SCREEN_SIZE; } } - if ((taskChanges & ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE) != 0) { + if ((taskChanges & CONFIG_SMALLEST_SCREEN_SIZE) != 0) { final int oldSmallest = oldTaskOverride.smallestScreenWidthDp; final int newSmallest = taskConfig.smallestScreenWidthDp; if (!record.crossesSmallestSizeThreshold(oldSmallest, newSmallest)) { - taskChanges &= ~ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; + taskChanges &= ~CONFIG_SMALLEST_SCREEN_SIZE; } } return catchConfigChangesFromUnset(taskConfig, oldTaskOverride, taskChanges); @@ -4249,7 +4254,7 @@ final class ActivityStack { // {@link Configuration#diff} doesn't catch changes from unset values. // Check for changes we care about. if (oldTaskOverride.orientation != taskConfig.orientation) { - taskChanges |= ActivityInfo.CONFIG_ORIENTATION; + taskChanges |= CONFIG_ORIENTATION; } // We want to explicitly track situations where the size configuration goes from // undefined to defined. We don't care about crossing the threshold in that case, @@ -4259,29 +4264,35 @@ final class ActivityStack { final int undefinedHeight = Configuration.SCREEN_HEIGHT_DP_UNDEFINED; if ((oldHeight == undefinedHeight && newHeight != undefinedHeight) || (oldHeight != undefinedHeight && newHeight == undefinedHeight)) { - taskChanges |= ActivityInfo.CONFIG_SCREEN_SIZE; + taskChanges |= CONFIG_SCREEN_SIZE; } final int oldWidth = oldTaskOverride.screenWidthDp; final int newWidth = taskConfig.screenWidthDp; final int undefinedWidth = Configuration.SCREEN_WIDTH_DP_UNDEFINED; if ((oldWidth == undefinedWidth && newWidth != undefinedWidth) || (oldWidth != undefinedWidth && newWidth == undefinedWidth)) { - taskChanges |= ActivityInfo.CONFIG_SCREEN_SIZE; + taskChanges |= CONFIG_SCREEN_SIZE; } final int oldSmallest = oldTaskOverride.smallestScreenWidthDp; final int newSmallest = taskConfig.smallestScreenWidthDp; final int undefinedSmallest = Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED; if ((oldSmallest == undefinedSmallest && newSmallest != undefinedSmallest) || (oldSmallest != undefinedSmallest && newSmallest == undefinedSmallest)) { - taskChanges |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; + taskChanges |= CONFIG_SMALLEST_SCREEN_SIZE; + } + final int oldLayout = oldTaskOverride.screenLayout; + final int newLayout = taskConfig.screenLayout; + if ((oldLayout == SCREENLAYOUT_UNDEFINED && newLayout != SCREENLAYOUT_UNDEFINED) + || (oldLayout != SCREENLAYOUT_UNDEFINED && newLayout == SCREENLAYOUT_UNDEFINED)) { + taskChanges |= CONFIG_SCREEN_LAYOUT; } } return taskChanges; } private static boolean isResizeOnlyChange(int change) { - return (change & ~(ActivityInfo.CONFIG_SCREEN_SIZE - | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) == 0; + return (change & ~(CONFIG_SCREEN_SIZE | CONFIG_SMALLEST_SCREEN_SIZE | CONFIG_ORIENTATION + | CONFIG_SCREEN_LAYOUT)) == 0; } private void relaunchActivityLocked( @@ -4595,7 +4606,7 @@ final class ActivityStack { a.forceNewConfig = true; if (starting != null && a == starting && a.visible) { a.startFreezingScreenLocked(starting.app, - ActivityInfo.CONFIG_SCREEN_LAYOUT); + CONFIG_SCREEN_LAYOUT); } } } diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 80a75ce74312..4672023a220e 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -1958,10 +1958,10 @@ public final class ActivityStackSupervisor implements DisplayListener { || tempOtherTaskInsetBounds != null); } - void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) { + boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) { if (!task.mResizeable) { Slog.w(TAG, "resizeTask: task " + task + " not resizeable."); - return; + return true; } adjustForMinimalTaskDimensions(task, bounds); @@ -1971,7 +1971,7 @@ public final class ActivityStackSupervisor implements DisplayListener { final boolean forced = (resizeMode & RESIZE_MODE_FORCED) != 0; if (task.mBounds != null && task.mBounds.equals(bounds) && !forced) { // Nothing to do here... - return; + return true; } if (!mWindowManager.isValidTaskId(task.taskId)) { @@ -1983,7 +1983,7 @@ public final class ActivityStackSupervisor implements DisplayListener { // re-restore the task so it can have the proper stack association. restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID); } - return; + return true; } // Do not move the task to another stack here. @@ -2012,6 +2012,7 @@ public final class ActivityStackSupervisor implements DisplayListener { mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced); Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER); + return kept; } private void adjustForMinimalTaskDimensions(TaskRecord task, Rect bounds) { @@ -2169,13 +2170,17 @@ public final class ActivityStackSupervisor implements DisplayListener { } final ActivityRecord topActivity = task.getTopActivity(); - if (StackId.preserveWindowOnTaskMove(stackId) && topActivity != null) { + final boolean mightReplaceWindow = + StackId.preserveWindowOnTaskMove(stackId) && topActivity != null; + if (mightReplaceWindow) { // We are about to relaunch the activity because its configuration changed due to // being maximized, i.e. size change. The activity will first remove the old window // and then add a new one. This call will tell window manager about this, so it can // preserve the old window until the new one is drawn. This prevents having a gap // between the removal and addition, in which no window is visible. We also want the // entrance of the new window to be properly animated. + // Note here we always set the replacing window first, as the flags might be needed + // during the relaunch. If we end up not doing any relaunch, we clear the flags later. mWindowManager.setReplacingWindow(topActivity.appToken, animate); } final ActivityStack stack = moveTaskToStackUncheckedLocked( @@ -2185,15 +2190,23 @@ public final class ActivityStackSupervisor implements DisplayListener { stack.mNoAnimActivities.add(topActivity); } + boolean kept = true; // Make sure the task has the appropriate bounds/size for the stack it is in. if (stackId == FULLSCREEN_WORKSPACE_STACK_ID && task.mBounds != null) { - resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); + kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); } else if (stackId == FREEFORM_WORKSPACE_STACK_ID && task.mBounds == null && task.mLastNonFullscreenBounds != null) { - resizeTaskLocked(task, task.mLastNonFullscreenBounds, + kept = resizeTaskLocked(task, task.mLastNonFullscreenBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); } else if (stackId == DOCKED_STACK_ID || stackId == PINNED_STACK_ID) { - resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); + kept = resizeTaskLocked(task, stack.mBounds, RESIZE_MODE_SYSTEM, !PRESERVE_WINDOWS); + } + + if (mightReplaceWindow) { + // If we didn't actual do a relaunch (indicated by kept==true meaning we kept the old + // window), we need to clear the replace window settings. Otherwise, we schedule a + // timeout to remove the old window if the replacing window is not coming in time. + mWindowManager.scheduleClearReplacingWindowIfNeeded(topActivity.appToken, !kept); } // The task might have already been running and its visibility needs to be synchronized with diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java index f2864d4dd470..f712613a2037 100644 --- a/services/core/java/com/android/server/am/ActivityStarter.java +++ b/services/core/java/com/android/server/am/ActivityStarter.java @@ -1,6 +1,7 @@ package com.android.server.am; import static android.app.Activity.RESULT_CANCELED; +import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY; import static android.app.ActivityManager.START_CLASS_NOT_FOUND; import static android.app.ActivityManager.START_DELIVERED_TO_TOP; import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED; @@ -15,8 +16,16 @@ import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; import static android.app.ActivityManager.StackId.HOME_STACK_ID; import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; +import static android.app.PendingIntent.FLAG_IMMUTABLE; +import static android.app.PendingIntent.FLAG_ONE_SHOT; +import static android.content.Context.KEYGUARD_SERVICE; +import static android.content.Intent.EXTRA_INTENT; +import static android.content.Intent.EXTRA_PACKAGE_NAME; +import static android.content.Intent.EXTRA_TASK_ID; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP; +import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS; import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; @@ -66,7 +75,6 @@ import android.app.KeyguardManager; import android.app.PendingIntent; import android.app.ProfilerInfo; import android.content.ComponentName; -import android.content.Context; import android.content.IIntentSender; import android.content.Intent; import android.content.IntentSender; @@ -91,7 +99,6 @@ import android.view.Display; import com.android.internal.app.HeavyWeightSwitcherActivity; import com.android.internal.app.IVoiceInteractor; -import com.android.internal.widget.LockPatternUtils; import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch; import com.android.server.wm.WindowManagerService; @@ -358,37 +365,25 @@ class ActivityStarter { } } - UserInfo user = mSupervisor.getUserInfo(userId); - KeyguardManager km = (KeyguardManager) mService.mContext - .getSystemService(Context.KEYGUARD_SERVICE); - if (user.isManagedProfile() - && LockPatternUtils.isSeparateWorkChallengeEnabled() - && km.isDeviceLocked(userId)) { - IIntentSender target = mService.getIntentSenderLocked( - ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage, - Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent }, - new String[]{ resolvedType }, - PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT - | PendingIntent.FLAG_IMMUTABLE, null); - final int flags = intent.getFlags(); - final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, user.id); - if (newIntent != null) { - intent = newIntent; - intent.setFlags(flags - | Intent.FLAG_ACTIVITY_NEW_TASK - | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); - intent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName); - intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target)); - - resolvedType = null; - callingUid = realCallingUid; - callingPid = realCallingPid; - - UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId); - rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id); - aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, - null /*profilerInfo*/); + final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(intent, + resolvedType, aInfo, callingPackage, userId); + if (interceptingIntent != null) { + intent = interceptingIntent; + callingPid = realCallingPid; + callingUid = realCallingUid; + resolvedType = null; + // If we are intercepting and there was a task, convert it into an extra for the + // ConfirmCredentials intent and unassign it, as otherwise the task will move to + // front even if ConfirmCredentials is cancelled. + if (inTask != null) { + intent.putExtra(EXTRA_TASK_ID, inTask.taskId); + inTask = null; } + + final UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId); + rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id); + aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags, + null /*profilerInfo*/); } if (abort) { @@ -538,6 +533,34 @@ class ActivityStarter { return err; } + /** + * Creates an intent to intercept the current activity start with Confirm Credentials if needed. + * + * @return The intercepting intent if needed. + */ + private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType, + ActivityInfo aInfo, String callingPackage, int userId) { + if (!mService.mUserController.shouldConfirmCredentials(userId)) { + return null; + } + final IIntentSender target = mService.getIntentSenderLocked( + INTENT_SENDER_ACTIVITY, callingPackage, + Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent }, + new String[]{ resolvedType }, + FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null); + final int flags = intent.getFlags(); + final KeyguardManager km = (KeyguardManager) mService.mContext + .getSystemService(KEYGUARD_SERVICE); + final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId); + if (newIntent == null) { + return null; + } + newIntent.setFlags(flags | FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); + newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName); + newIntent.putExtra(EXTRA_INTENT, new IntentSender(target)); + return newIntent; + } + void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) { mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason); startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/, diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java index f64b80323b91..82862e8a1935 100644 --- a/services/core/java/com/android/server/am/BatteryStatsService.java +++ b/services/core/java/com/android/server/am/BatteryStatsService.java @@ -1114,7 +1114,7 @@ public final class BatteryStatsService extends IBatteryStats.Stub } else { // Not an option, last argument must be a package name. try { - reqUid = mContext.getPackageManager().getPackageUid(arg, + reqUid = mContext.getPackageManager().getPackageUidAsUser(arg, UserHandle.getCallingUserId()); } catch (PackageManager.NameNotFoundException e) { pw.println("Unknown package: " + arg); diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java index c63eaac448d5..52d23cf05888 100644 --- a/services/core/java/com/android/server/am/RecentTasks.java +++ b/services/core/java/com/android/server/am/RecentTasks.java @@ -130,9 +130,11 @@ class RecentTasks extends ArrayList<TaskRecord> { ActivityInfo ai = tmpAvailActCache.get(task.realActivity); if (ai == null) { try { + // At this first cut, we're only interested in + // activities that are fully runnable based on + // current system state. ai = pm.getActivityInfo(task.realActivity, - PackageManager.GET_UNINSTALLED_PACKAGES - | PackageManager.GET_DISABLED_COMPONENTS, user); + PackageManager.MATCH_DEBUG_TRIAGED_MISSING, user); } catch (RemoteException e) { // Will never happen. continue; @@ -150,8 +152,7 @@ class RecentTasks extends ArrayList<TaskRecord> { if (app == null) { try { app = pm.getApplicationInfo(task.realActivity.getPackageName(), - PackageManager.GET_UNINSTALLED_PACKAGES - | PackageManager.GET_DISABLED_COMPONENTS, user); + PackageManager.MATCH_UNINSTALLED_PACKAGES, user); } catch (RemoteException e) { // Will never happen. continue; diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index c97d09c2ebbd..ae987e6f4402 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -1298,6 +1298,9 @@ final class TaskRecord { (mOverrideConfig.screenWidthDp <= mOverrideConfig.screenHeightDp) ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; + final int sl = Configuration.resetScreenLayout(serviceConfig.screenLayout); + mOverrideConfig.screenLayout = Configuration.reduceScreenLayout( + sl, mOverrideConfig.screenWidthDp, mOverrideConfig.screenHeightDp); } if (mFullscreen != oldFullscreen) { diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java index f2c5206f2e1b..717285930f5b 100644 --- a/services/core/java/com/android/server/am/UserController.java +++ b/services/core/java/com/android/server/am/UserController.java @@ -22,6 +22,7 @@ import static android.app.ActivityManager.USER_OP_ERROR_IS_SYSTEM; import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP; import static android.app.ActivityManager.USER_OP_IS_CURRENT; import static android.app.ActivityManager.USER_OP_SUCCESS; +import static android.content.Context.KEYGUARD_SERVICE; import static android.os.Process.SYSTEM_UID; import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; @@ -43,6 +44,7 @@ import android.app.AppOpsManager; import android.app.Dialog; import android.app.IStopUserCallback; import android.app.IUserSwitchObserver; +import android.app.KeyguardManager; import android.content.Context; import android.content.IIntentReceiver; import android.content.Intent; @@ -73,6 +75,7 @@ import android.util.SparseIntArray; import com.android.internal.R; import com.android.internal.annotations.GuardedBy; import com.android.internal.util.ArrayUtils; +import com.android.internal.widget.LockPatternUtils; import com.android.server.pm.UserManagerService; import java.io.PrintWriter; @@ -1286,6 +1289,20 @@ final class UserController { return mCurrentProfileIds; } + /** + * Returns whether the given user requires credential entry at this time. This is used to + * intercept activity launches for work apps when the Work Challenge is present. + */ + boolean shouldConfirmCredentials(int userId) { + final UserInfo user = getUserInfo(userId); + if (!user.isManagedProfile() || !LockPatternUtils.isSeparateWorkChallengeEnabled()) { + return false; + } + final KeyguardManager km = (KeyguardManager) mService.mContext + .getSystemService(KEYGUARD_SERVICE); + return km.isDeviceLocked(user.id); + } + void dump(PrintWriter pw, boolean dumpAll) { pw.println(" mStartedUsers:"); for (int i = 0; i < mStartedUsers.size(); i++) { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 40d01e7359d5..b8cbecb48928 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -220,6 +220,7 @@ public class AudioService extends IAudioService.Stub { private static final int MSG_UNMUTE_STREAM = 24; private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25; private static final int MSG_INDICATE_SYSTEM_READY = 26; + private static final int MSG_PERSIST_MASTER_MONO = 27; // start of messages handled under wakelock // these messages can only be queued, i.e. sent with queueMsgUnderWakeLock(), // and not with sendMsg(..., ..., SENDMSG_QUEUE, ...) @@ -820,6 +821,12 @@ public class AudioService extends IAudioService.Stub { streamState.applyAllVolumes(); } + // Restore mono mode + final boolean masterMono = System.getIntForUser( + mContentResolver, System.MASTER_MONO, + 0 /* default */, UserHandle.USER_CURRENT) == 1; + AudioSystem.setMasterMono(masterMono); + // Restore ringer mode setRingerModeInt(getRingerModeInternal(), false); @@ -1079,6 +1086,14 @@ public class AudioService extends IAudioService.Stub { } AudioSystem.muteMicrophone(microphoneMute); + final boolean masterMono = System.getIntForUser( + cr, System.MASTER_MONO, 0 /* default */, UserHandle.USER_CURRENT) == 1; + if (DEBUG_VOL) { + Log.d(TAG, String.format("Master mono %b, user=%d", masterMono, currentUser)); + } + AudioSystem.setMasterMono(masterMono); + broadcastMasterMonoStatus(masterMono); + // Each stream will read its own persisted settings // Broadcast the sticky intents @@ -1835,6 +1850,52 @@ public class AudioService extends IAudioService.Stub { userId); } + /** @hide */ + public boolean isMasterMono() { + return AudioSystem.getMasterMono(); + } + + /** @hide */ + public void setMasterMono(boolean mono, String callingPackage, int userId) { + int callingUid = Binder.getCallingUid(); + // If we are being called by the system check for user we are going to change + // so we handle user restrictions correctly. + if (callingUid == android.os.Process.SYSTEM_UID) { + callingUid = UserHandle.getUid(userId, UserHandle.getAppId(callingUid)); + } + + if (userId != UserHandle.getCallingUserId() && + mContext.checkCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) + != PackageManager.PERMISSION_GRANTED) { + return; + } + if (DEBUG_VOL) { + Log.d(TAG, String.format("Master mono %b, user=%d", mono, userId)); + } + + if (getCurrentUserId() == userId) { + if (mono != AudioSystem.getMasterMono()) { + AudioSystem.setMasterMono(mono); + // Post a persist master mono msg + sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1 + : 0 /* value */, userId, null /* obj */, 0 /* delay */); + // notify apps and settings + broadcastMasterMonoStatus(mono); + } + } else { + // Post a persist master mono msg + sendMsg(mAudioHandler, MSG_PERSIST_MASTER_MONO, SENDMSG_REPLACE, mono ? 1 + : 0 /* value */, userId, null /* obj */, 0 /* delay */); + } + } + + private void broadcastMasterMonoStatus(boolean mono) { + Intent intent = new Intent(AudioManager.MASTER_MONO_CHANGED_ACTION); + intent.putExtra(AudioManager.EXTRA_MASTER_MONO, mono); + sendBroadcastToAll(intent); + } + /** @see AudioManager#getStreamVolume(int) */ public int getStreamVolume(int streamType) { ensureValidStreamType(streamType); @@ -4534,6 +4595,13 @@ public class AudioService extends IAudioService.Stub { case MSG_DYN_POLICY_MIX_STATE_UPDATE: onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1); break; + + case MSG_PERSIST_MASTER_MONO: + Settings.System.putIntForUser(mContentResolver, + Settings.System.MASTER_MONO, + msg.arg1 /* value */, + msg.arg2 /* userHandle */); + break; } } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index 2bea278aad1a..5bd4f987073e 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -309,7 +309,7 @@ public class Vpn { PackageManager pm = mContext.getPackageManager(); int result; try { - result = pm.getPackageUid(app, userHandle); + result = pm.getPackageUidAsUser(app, userHandle); } catch (NameNotFoundException e) { result = -1; } diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index ee8aab6c6d3d..ee91b632d87c 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -70,7 +70,7 @@ import android.os.RemoteException; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; -import android.util.Log; +import android.text.TextUtils; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; @@ -97,9 +97,11 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import libcore.io.Streams; import libcore.util.Objects; @@ -720,40 +722,35 @@ public class InputManagerService extends IInputManager.Stub mTempInputDevicesChangedListenersToNotify.clear(); // Check for missing keyboard layouts. - if (mNotificationManager != null) { - final int numFullKeyboards = mTempFullKeyboards.size(); - boolean missingLayoutForExternalKeyboard = false; - boolean missingLayoutForExternalKeyboardAdded = false; - boolean multipleMissingLayoutsForExternalKeyboardsAdded = false; - InputDevice keyboardMissingLayout = null; - synchronized (mDataStore) { - for (int i = 0; i < numFullKeyboards; i++) { - final InputDevice inputDevice = mTempFullKeyboards.get(i); - final String layout = - getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier()); - if (layout == null) { - missingLayoutForExternalKeyboard = true; - if (i < numFullKeyboardsAdded) { - missingLayoutForExternalKeyboardAdded = true; - if (keyboardMissingLayout == null) { - keyboardMissingLayout = inputDevice; - } else { - multipleMissingLayoutsForExternalKeyboardsAdded = true; - } - } + List<InputDevice> keyboardsMissingLayout = new ArrayList<>(); + final int numFullKeyboards = mTempFullKeyboards.size(); + synchronized (mDataStore) { + for (int i = 0; i < numFullKeyboards; i++) { + final InputDevice inputDevice = mTempFullKeyboards.get(i); + String layout = + getCurrentKeyboardLayoutForInputDevice(inputDevice.getIdentifier()); + if (layout == null) { + layout = getDefaultKeyboardLayout(inputDevice); + if (layout != null) { + setCurrentKeyboardLayoutForInputDevice( + inputDevice.getIdentifier(), layout); } } + if (layout == null) { + keyboardsMissingLayout.add(inputDevice); + } } - if (missingLayoutForExternalKeyboard) { - if (missingLayoutForExternalKeyboardAdded) { - if (multipleMissingLayoutsForExternalKeyboardsAdded) { - // We have more than one keyboard missing a layout, so drop the - // user at the generic input methods page so they can pick which - // one to set. - showMissingKeyboardLayoutNotification(null); - } else { - showMissingKeyboardLayoutNotification(keyboardMissingLayout); - } + } + + if (mNotificationManager != null) { + if (!keyboardsMissingLayout.isEmpty()) { + if (keyboardsMissingLayout.size() > 1) { + // We have more than one keyboard missing a layout, so drop the + // user at the generic input methods page so they can pick which + // one to set. + showMissingKeyboardLayoutNotification(null); + } else { + showMissingKeyboardLayoutNotification(keyboardsMissingLayout.get(0)); } } else if (mKeyboardLayoutNotificationShown) { hideMissingKeyboardLayoutNotification(); @@ -762,6 +759,78 @@ public class InputManagerService extends IInputManager.Stub mTempFullKeyboards.clear(); } + private String getDefaultKeyboardLayout(final InputDevice d) { + final Locale systemLocale = mContext.getResources().getConfiguration().locale; + // If our locale doesn't have a language for some reason, then we don't really have a + // reasonable default. + if (TextUtils.isEmpty(systemLocale.getLanguage())) { + return null; + } + final List<KeyboardLayout> layouts = new ArrayList<>(); + visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { + @Override + public void visitKeyboardLayout(Resources resources, + int keyboardLayoutResId, KeyboardLayout layout) { + // Only select a default when we know the layout is appropriate. For now, this + // means its a custom layout for a specific keyboard. + if (layout.getVendorId() != d.getVendorId() + || layout.getProductId() != d.getProductId()) { + return; + } + for (Locale l : layout.getLocales()) { + if (isCompatibleLocale(systemLocale, l)) { + layouts.add(layout); + break; + } + } + } + }); + + if (layouts.isEmpty()) { + return null; + } + + // First sort so that ones with higher priority are listed at the top + Collections.sort(layouts); + // Next we want to try to find an exact match of language, country and variant. + final int N = layouts.size(); + for (int i = 0; i < N; i++) { + KeyboardLayout layout = layouts.get(i); + for (Locale l : layout.getLocales()) { + if (l.getCountry().equals(systemLocale.getCountry()) + && l.getVariant().equals(systemLocale.getVariant())) { + return layout.getDescriptor(); + } + } + } + // Then try an exact match of language and country + for (int i = 0; i < N; i++) { + KeyboardLayout layout = layouts.get(i); + for (Locale l : layout.getLocales()) { + if (l.getCountry().equals(systemLocale.getCountry())) { + return layout.getDescriptor(); + } + } + } + + // Give up and just use the highest priority layout with matching language + return layouts.get(0).getDescriptor(); + } + + private static boolean isCompatibleLocale(Locale systemLocale, Locale keyboardLocale) { + // Different languages are never compatible + if (!systemLocale.getLanguage().equals(keyboardLocale.getLanguage())) { + return false; + } + // If both the system and the keyboard layout have a country specifier, they must be equal. + if (!TextUtils.isEmpty(systemLocale.getCountry()) + && !TextUtils.isEmpty(keyboardLocale.getCountry()) + && !systemLocale.getCountry().equals(keyboardLocale.getCountry())) { + return false; + } + return true; + } + @Override // Binder call & native callback public TouchCalibration getTouchCalibrationForInputDevice(String inputDeviceDescriptor, int surfaceRotation) { @@ -911,9 +980,9 @@ public class InputManagerService extends IInputManager.Stub final HashSet<String> availableKeyboardLayouts = new HashSet<String>(); visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { @Override - public void visitKeyboardLayout(Resources resources, String descriptor, String label, - String collection, int keyboardLayoutResId, int priority) { - availableKeyboardLayouts.add(descriptor); + public void visitKeyboardLayout(Resources resources, + int keyboardLayoutResId, KeyboardLayout layout) { + availableKeyboardLayouts.add(layout.getDescriptor()); } }); synchronized (mDataStore) { @@ -945,15 +1014,64 @@ public class InputManagerService extends IInputManager.Stub final ArrayList<KeyboardLayout> list = new ArrayList<KeyboardLayout>(); visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { @Override - public void visitKeyboardLayout(Resources resources, String descriptor, String label, - String collection, int keyboardLayoutResId, int priority) { - list.add(new KeyboardLayout(descriptor, label, collection, priority)); + public void visitKeyboardLayout(Resources resources, + int keyboardLayoutResId, KeyboardLayout layout) { + list.add(layout); } }); return list.toArray(new KeyboardLayout[list.size()]); } @Override // Binder call + public KeyboardLayout[] getKeyboardLayoutsForInputDevice( + final InputDeviceIdentifier identifier) { + final String[] enabledLayoutDescriptors = + getEnabledKeyboardLayoutsForInputDevice(identifier); + final ArrayList<KeyboardLayout> enabledLayouts = + new ArrayList<KeyboardLayout>(enabledLayoutDescriptors.length); + final ArrayList<KeyboardLayout> potentialLayouts = new ArrayList<KeyboardLayout>(); + visitAllKeyboardLayouts(new KeyboardLayoutVisitor() { + boolean mHasSeenDeviceSpecificLayout; + + @Override + public void visitKeyboardLayout(Resources resources, + int keyboardLayoutResId, KeyboardLayout layout) { + // First check if it's enabled. If the keyboard layout is enabled then we always + // want to return it as a possible layout for the device. + for (String s : enabledLayoutDescriptors) { + if (s != null && s.equals(layout.getDescriptor())) { + enabledLayouts.add(layout); + return; + } + } + // Next find any potential layouts that aren't yet enabled for the device. For + // devices that have special layouts we assume there's a reason that the generic + // layouts don't work for them so we don't want to return them since it's likely + // to result in a poor user experience. + if (layout.getVendorId() == identifier.getVendorId() + && layout.getProductId() == identifier.getProductId()) { + if (!mHasSeenDeviceSpecificLayout) { + mHasSeenDeviceSpecificLayout = true; + potentialLayouts.clear(); + } + potentialLayouts.add(layout); + } else if (layout.getVendorId() == -1 && layout.getProductId() == -1 + && !mHasSeenDeviceSpecificLayout) { + potentialLayouts.add(layout); + } + } + }); + final int enabledLayoutSize = enabledLayouts.size(); + final int potentialLayoutSize = potentialLayouts.size(); + KeyboardLayout[] layouts = new KeyboardLayout[enabledLayoutSize + potentialLayoutSize]; + enabledLayouts.toArray(layouts); + for (int i = 0; i < potentialLayoutSize; i++) { + layouts[enabledLayoutSize + i] = potentialLayouts.get(i); + } + return layouts; + } + + @Override // Binder call public KeyboardLayout getKeyboardLayout(String keyboardLayoutDescriptor) { if (keyboardLayoutDescriptor == null) { throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null"); @@ -962,13 +1080,13 @@ public class InputManagerService extends IInputManager.Stub final KeyboardLayout[] result = new KeyboardLayout[1]; visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { @Override - public void visitKeyboardLayout(Resources resources, String descriptor, - String label, String collection, int keyboardLayoutResId, int priority) { - result[0] = new KeyboardLayout(descriptor, label, collection, priority); + public void visitKeyboardLayout(Resources resources, + int keyboardLayoutResId, KeyboardLayout layout) { + result[0] = layout; } }); if (result[0] == null) { - Log.w(TAG, "Could not get keyboard layout with descriptor '" + Slog.w(TAG, "Could not get keyboard layout with descriptor '" + keyboardLayoutDescriptor + "'."); } return result[0]; @@ -1010,7 +1128,7 @@ public class InputManagerService extends IInputManager.Stub int configResId = metaData.getInt(InputManager.META_DATA_KEYBOARD_LAYOUTS); if (configResId == 0) { - Log.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS + Slog.w(TAG, "Missing meta-data '" + InputManager.META_DATA_KEYBOARD_LAYOUTS + "' on receiver " + receiver.packageName + "/" + receiver.name); return; } @@ -1047,8 +1165,16 @@ public class InputManagerService extends IInputManager.Stub int keyboardLayoutResId = a.getResourceId( com.android.internal.R.styleable.KeyboardLayout_keyboardLayout, 0); + String languageTags = a.getString( + com.android.internal.R.styleable.KeyboardLayout_locale); + Locale[] locales = getLocalesFromLanguageTags(languageTags); + int vid = a.getInt( + com.android.internal.R.styleable.KeyboardLayout_vendorId, -1); + int pid = a.getInt( + com.android.internal.R.styleable.KeyboardLayout_productId, -1); + if (name == null || label == null || keyboardLayoutResId == 0) { - Log.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " + Slog.w(TAG, "Missing required 'name', 'label' or 'keyboardLayout' " + "attributes in keyboard layout " + "resource from receiver " + receiver.packageName + "/" + receiver.name); @@ -1056,15 +1182,18 @@ public class InputManagerService extends IInputManager.Stub String descriptor = KeyboardLayoutDescriptor.format( receiver.packageName, receiver.name, name); if (keyboardName == null || name.equals(keyboardName)) { - visitor.visitKeyboardLayout(resources, descriptor, - label, collection, keyboardLayoutResId, priority); + KeyboardLayout layout = new KeyboardLayout( + descriptor, label, collection, priority, + locales, vid, pid); + visitor.visitKeyboardLayout( + resources, keyboardLayoutResId, layout); } } } finally { a.recycle(); } } else { - Log.w(TAG, "Skipping unrecognized element '" + element + Slog.w(TAG, "Skipping unrecognized element '" + element + "' in keyboard layout resource from receiver " + receiver.packageName + "/" + receiver.name); } @@ -1073,11 +1202,23 @@ public class InputManagerService extends IInputManager.Stub parser.close(); } } catch (Exception ex) { - Log.w(TAG, "Could not parse keyboard layout resource from receiver " + Slog.w(TAG, "Could not parse keyboard layout resource from receiver " + receiver.packageName + "/" + receiver.name, ex); } } + private static Locale[] getLocalesFromLanguageTags(String languageTags) { + if (TextUtils.isEmpty(languageTags)) { + return new Locale[0]; + } + String[] tags = languageTags.split("\\|"); + Locale[] locales = new Locale[tags.length]; + for (int i = 0; i < tags.length; i++) { + locales[i] = Locale.forLanguageTag(tags[i]); + } + return locales; + } + /** * Builds a layout descriptor for the vendor/product. This returns the * descriptor for ids that aren't useful (such as the default 0, 0). @@ -1143,7 +1284,7 @@ public class InputManagerService extends IInputManager.Stub } @Override // Binder call - public String[] getKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { + public String[] getEnabledKeyboardLayoutsForInputDevice(InputDeviceIdentifier identifier) { String key = getLayoutDescriptor(identifier); synchronized (mDataStore) { String[] layouts = mDataStore.getKeyboardLayouts(key); @@ -1718,10 +1859,10 @@ public class InputManagerService extends IInputManager.Stub final String[] result = new String[2]; visitKeyboardLayout(keyboardLayoutDescriptor, new KeyboardLayoutVisitor() { @Override - public void visitKeyboardLayout(Resources resources, String descriptor, String label, - String collection, int keyboardLayoutResId, int priority) { + public void visitKeyboardLayout(Resources resources, + int keyboardLayoutResId, KeyboardLayout layout) { try { - result[0] = descriptor; + result[0] = layout.getDescriptor(); result[1] = Streams.readFully(new InputStreamReader( resources.openRawResource(keyboardLayoutResId))); } catch (IOException ex) { @@ -1730,7 +1871,7 @@ public class InputManagerService extends IInputManager.Stub } }); if (result[0] == null) { - Log.w(TAG, "Could not get keyboard layout with descriptor '" + Slog.w(TAG, "Could not get keyboard layout with descriptor '" + keyboardLayoutDescriptor + "'."); return null; } @@ -1883,8 +2024,8 @@ public class InputManagerService extends IInputManager.Stub } private interface KeyboardLayoutVisitor { - void visitKeyboardLayout(Resources resources, String descriptor, String label, - String collection, int keyboardLayoutResId, int priority); + void visitKeyboardLayout(Resources resources, + int keyboardLayoutResId, KeyboardLayout layout); } private final class InputDevicesChangedListenerRecord implements DeathRecipient { diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java index d5c31134a4eb..745f4763c1ea 100644 --- a/services/core/java/com/android/server/media/MediaSessionService.java +++ b/services/core/java/com/android/server/media/MediaSessionService.java @@ -767,7 +767,7 @@ public class MediaSessionService extends SystemService implements Monitor { synchronized (mLock) { // If we don't have a media button receiver to fall back on // include non-playing sessions for dispatching - UserRecord ur = mUserRecords.get(ActivityManager.getCurrentUser()); + UserRecord ur = mUserRecords.get(mCurrentUserId); boolean useNotPlayingSessions = (ur == null) || (ur.mLastMediaButtonReceiver == null && ur.mRestoredMediaButtonReceiver == null); @@ -949,8 +949,7 @@ public class MediaSessionService extends SystemService implements Monitor { mKeyEventReceiver); } else { // Launch the last PendingIntent we had with priority - int userId = ActivityManager.getCurrentUser(); - UserRecord user = mUserRecords.get(userId); + UserRecord user = mUserRecords.get(mCurrentUserId); if (user != null && (user.mLastMediaButtonReceiver != null || user.mRestoredMediaButtonReceiver != null)) { if (DEBUG) { @@ -967,11 +966,11 @@ public class MediaSessionService extends SystemService implements Monitor { if (user.mLastMediaButtonReceiver != null) { user.mLastMediaButtonReceiver.send(getContext(), needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1, - mediaButtonIntent, mKeyEventReceiver, null); + mediaButtonIntent, mKeyEventReceiver, mHandler); } else { mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver); getContext().sendBroadcastAsUser(mediaButtonIntent, - new UserHandle(userId)); + new UserHandle(mCurrentUserId)); } } catch (CanceledException e) { Log.i(TAG, "Error sending key event to media button receiver " diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index 1997e40e610e..4325efdb77f3 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -2333,7 +2333,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub { @Override public void onAppIdleStateChanged(String packageName, int userId, boolean idle) { try { - int uid = mContext.getPackageManager().getPackageUid(packageName, userId); + final int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, + PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); synchronized (mRulesLock) { updateRuleForAppIdleLocked(uid); } diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java index 09e66475c1be..f360dc2c4283 100644 --- a/services/core/java/com/android/server/notification/ManagedServices.java +++ b/services/core/java/com/android/server/notification/ManagedServices.java @@ -86,7 +86,7 @@ abstract public class ManagedServices { protected final ArrayList<ManagedServiceInfo> mServices = new ArrayList<ManagedServiceInfo>(); // things that will be put into mServices as soon as they're ready private final ArrayList<String> mServicesBinding = new ArrayList<String>(); - // lists the component names of all enabled (and therefore connected) + // lists the component names of all enabled (and therefore potentially connected) // app services for current profiles. private ArraySet<ComponentName> mEnabledServicesForCurrentProfiles = new ArraySet<ComponentName>(); @@ -97,6 +97,8 @@ abstract public class ManagedServices { private ArraySet<String> mRestoredPackages = new ArraySet<>(); // State of current service categories private ArrayMap<String, Boolean> mCategoryEnabled = new ArrayMap<>(); + // List of enabled packages that have nevertheless asked not to be run + private ArraySet<ComponentName> mSnoozingForCurrentProfiles = new ArraySet<>(); // Kept to de-dupe user change events (experienced after boot, when we receive a settings and a @@ -174,6 +176,12 @@ abstract public class ManagedServices { + (info.isSystem?" SYSTEM":"") + (info.isGuest(this)?" GUEST":"")); } + + pw.println(" Snoozed " + getCaption() + "s (" + + mSnoozingForCurrentProfiles.size() + "):"); + for (ComponentName name : mSnoozingForCurrentProfiles) { + pw.println(" " + name.flattenToShortString()); + } } // By convention, restored settings are replicated to another settings @@ -242,14 +250,25 @@ abstract public class ManagedServices { rebindServices(); } - public ManagedServiceInfo checkServiceTokenLocked(IInterface service) { - checkNotNull(service); + public ManagedServiceInfo getServiceFromTokenLocked(IInterface service) { + if (service == null) { + return null; + } final IBinder token = service.asBinder(); final int N = mServices.size(); for (int i = 0; i < N; i++) { final ManagedServiceInfo info = mServices.get(i); if (info.service.asBinder() == token) return info; } + return null; + } + + public ManagedServiceInfo checkServiceTokenLocked(IInterface service) { + checkNotNull(service); + ManagedServiceInfo info = getServiceFromTokenLocked(service); + if (info != null) { + return info; + } throw new SecurityException("Disallowed call from unknown " + getCaption() + ": " + service); } @@ -278,6 +297,35 @@ abstract public class ManagedServices { checkType(guest.service); if (registerServiceImpl(guest) != null) { onServiceAdded(guest); + onServiceAdded(guest); + } + } + + public void setComponentState(ComponentName component, boolean enabled) { + boolean previous = !mSnoozingForCurrentProfiles.contains(component); + if (previous == enabled) { + return; + } + + if (enabled) { + mSnoozingForCurrentProfiles.remove(component); + } else { + mSnoozingForCurrentProfiles.add(component); + } + + // State changed + if (DEBUG) { + Slog.d(TAG, ((enabled) ? "Enabling " : "Disabling ") + "component " + + component.flattenToShortString()); + } + + final int[] userIds = mUserProfiles.getCurrentProfileIds(); + for (int userId : userIds) { + if (enabled) { + registerServiceLocked(component, userId); + } else { + unregisterServiceLocked(component, userId); + } } } @@ -324,6 +372,7 @@ abstract public class ManagedServices { private void rebuildRestoredPackages() { mRestoredPackages.clear(); + mSnoozingForCurrentProfiles.clear(); String settingName = restoredSettingName(mConfig); int[] userIds = mUserProfiles.getCurrentProfileIds(); final int N = userIds.length; @@ -525,6 +574,7 @@ abstract public class ManagedServices { add.removeAll(c); } } + add.removeAll(mSnoozingForCurrentProfiles); toAdd.put(userIds[i], add); @@ -803,6 +853,10 @@ abstract public class ManagedServices { return ManagedServices.this != host; } + public ManagedServices getOwner() { + return ManagedServices.this; + } + @Override public String toString() { return new StringBuilder("ManagedServiceInfo[") @@ -846,6 +900,11 @@ abstract public class ManagedServices { } } + /** convenience method for looking in mEnabledServicesForCurrentProfiles */ + public boolean isComponentEnabledForCurrentProfiles(ComponentName component) { + return mEnabledServicesForCurrentProfiles.contains(component); + } + public static class UserProfiles { // Profiles of the current user. private final SparseArray<UserInfo> mCurrentProfiles = new SparseArray<UserInfo>(); diff --git a/services/core/java/com/android/server/notification/NotificationComparator.java b/services/core/java/com/android/server/notification/NotificationComparator.java index 32db000d2d29..5e4703d7d34b 100644 --- a/services/core/java/com/android/server/notification/NotificationComparator.java +++ b/services/core/java/com/android/server/notification/NotificationComparator.java @@ -18,20 +18,13 @@ package com.android.server.notification; import java.util.Comparator; /** - * Sorts notifications individually into attention-relelvant order. + * Sorts notifications individually into attention-relevant order. */ public class NotificationComparator implements Comparator<NotificationRecord> { @Override public int compare(NotificationRecord left, NotificationRecord right) { - final int leftPackagePriority = left.getPackagePriority(); - final int rightPackagePriority = right.getPackagePriority(); - if (leftPackagePriority != rightPackagePriority) { - // by priority, high to low - return -1 * Integer.compare(leftPackagePriority, rightPackagePriority); - } - final int leftImportance = left.getImportance(); final int rightImportance = right.getImportance(); if (leftImportance != rightImportance) { @@ -39,6 +32,13 @@ public class NotificationComparator return -1 * Integer.compare(leftImportance, rightImportance); } + final int leftPackagePriority = left.getPackagePriority(); + final int rightPackagePriority = right.getPackagePriority(); + if (leftPackagePriority != rightPackagePriority) { + // by priority, high to low + return -1 * Integer.compare(leftPackagePriority, rightPackagePriority); + } + final float leftPeople = left.getContactAffinity(); final float rightPeople = right.getContactAffinity(); if (leftPeople != rightPeople) { diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java index d4fadcf2b319..b57cc75ebf13 100644 --- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java +++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java @@ -18,6 +18,7 @@ package com.android.server.notification; import android.app.Notification; import android.content.Context; +import android.service.notification.NotificationListenerService; import android.util.Log; import android.util.Slog; @@ -44,11 +45,7 @@ public class NotificationIntrusivenessExtractor implements NotificationSignalExt } final Notification notification = record.getNotification(); - if ((notification.defaults & Notification.DEFAULT_VIBRATE) != 0 || - notification.vibrate != null || - (notification.defaults & Notification.DEFAULT_SOUND) != 0 || - notification.sound != null || - notification.fullScreenIntent != null) { + if (record.getImportance() > NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) { record.setRecentlyIntrusive(true); } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 86570496e095..e787eda171ea 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -1446,6 +1446,37 @@ public class NotificationManagerService extends SystemService { } } + /** + * Handle request from an approved listener to re-enable itself. + * + * @param component The componenet to be re-enabled, caller must match package. + */ + @Override + public void requestBindListener(ComponentName component) { + checkCallerIsSystemOrSameApp(component.getPackageName()); + long identity = Binder.clearCallingIdentity(); + try { + ManagedServices manager = mAssistant.isComponentEnabledForCurrentProfiles(component) + ? mAssistant + : mListeners; + manager.setComponentState(component, true); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override + public void requestUnbindListener(INotificationListener token) { + long identity = Binder.clearCallingIdentity(); + try { + // allow bound services to disable themselves + final ManagedServiceInfo info = mListeners.checkServiceTokenLocked(token); + info.getOwner().setComponentState(info.component, false); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + @Override public void setNotificationsShownFromListener(INotificationListener token, String[] keys) { long identity = Binder.clearCallingIdentity(); @@ -2106,12 +2137,12 @@ public class NotificationManagerService extends SystemService { for (UserInfo user : UserManager.get(getContext()).getUsers()) { final int userId = user.getUserHandle().getIdentifier(); final PackageManager packageManager = getContext().getPackageManager(); - List<PackageInfo> packages = packageManager.getInstalledPackages(0, userId); + List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId); final int packageCount = packages.size(); for (int p = 0; p < packageCount; p++) { final String packageName = packages.get(p).packageName; if (filter == null || filter.matches(packageName)) { - final int uid = packageManager.getPackageUid(packageName, userId); + final int uid = packageManager.getPackageUidAsUser(packageName, userId); if (!checkNotificationOp(packageName, uid)) { packageNames.add(packageName); } @@ -3294,7 +3325,6 @@ public class NotificationManagerService extends SystemService { * <p>Caller must hold a lock on mNotificationList.</p> */ private NotificationRankingUpdate makeRankingUpdateLocked(ManagedServiceInfo info) { - int speedBumpIndex = -1; final int N = mNotificationList.size(); ArrayList<String> keys = new ArrayList<String>(N); ArrayList<String> interceptedKeys = new ArrayList<String>(N); @@ -3322,18 +3352,6 @@ public class NotificationManagerService extends SystemService { != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) { visibilityOverrides.putInt(key, record.getPackageVisibilityOverride()); } - // Find first min-prio notification for speedbump placement. - if (speedBumpIndex == -1 && - // Intrusiveness trumps priority, hence ignore intrusives. - !record.isRecentlyIntrusive() && - // Currently, package priority is either PRIORITY_DEFAULT or PRIORITY_MAX, so - // scanning for PRIORITY_MIN within the package bucket PRIORITY_DEFAULT - // (or lower as a safeguard) is sufficient to find the speedbump index. - // We'll have to revisit this when more package priority buckets are introduced. - record.getPackagePriority() <= Notification.PRIORITY_DEFAULT && - record.sbn.getNotification().priority == Notification.PRIORITY_MIN) { - speedBumpIndex = keys.size() - 1; - } } final int M = keys.size(); String[] keysAr = keys.toArray(new String[M]); @@ -3343,7 +3361,7 @@ public class NotificationManagerService extends SystemService { importanceAr[i] = importance.get(i); } return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides, - speedBumpIndex, suppressedVisualEffects, importanceAr, explanation); + suppressedVisualEffects, importanceAr, explanation); } private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) { @@ -3439,6 +3457,7 @@ public class NotificationManagerService extends SystemService { } } + @Override protected void onServiceRemovedLocked(ManagedServiceInfo removed) { if (mListenersDisablingEffects.remove(removed)) { diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index a9f20a6238cd..0be2eddf06fa 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -142,7 +142,7 @@ public final class NotificationRecord { } // maybe only do this for target API < N? if (isNoisy) { - if (importance == IMPORTANCE_HIGH) { + if (importance >= IMPORTANCE_HIGH) { importance = IMPORTANCE_MAX; } else { importance = IMPORTANCE_HIGH; diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java index 0662e7a68cea..f1fd42c69101 100644 --- a/services/core/java/com/android/server/notification/RankingHelper.java +++ b/services/core/java/com/android/server/notification/RankingHelper.java @@ -148,7 +148,7 @@ public class RankingHelper implements RankingConfig { if (forRestore) { try { //TODO: http://b/22388012 - uid = pm.getPackageUid(name, UserHandle.USER_SYSTEM); + uid = pm.getPackageUidAsUser(name, UserHandle.USER_SYSTEM); } catch (NameNotFoundException e) { // noop } @@ -537,7 +537,7 @@ public class RankingHelper implements RankingConfig { if (r != null) { try { //TODO: http://b/22388012 - r.uid = pm.getPackageUid(r.pkg, UserHandle.USER_SYSTEM); + r.uid = pm.getPackageUidAsUser(r.pkg, UserHandle.USER_SYSTEM); mRestoredWithoutUids.remove(pkg); mRecords.put(recordKey(r.pkg, r.uid), r); updated = true; diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index 276c6babce24..f7043a601c9d 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -570,13 +570,13 @@ public class ZenModeHelper { ZenLog.traceConfig(reason, mConfig, config); final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig), getNotificationPolicy(config)); - mConfig = config; - if (config.equals(mConfig)) { + if (!config.equals(mConfig)) { dispatchOnConfigChanged(); } if (policyChanged) { dispatchOnPolicyChanged(); } + mConfig = config; final String val = Integer.toString(config.hashCode()); Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val); if (!evaluateZenMode(reason, setRingerMode)) { diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java index b254f29e0d5a..6c338c184e4a 100644 --- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java +++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java @@ -261,6 +261,7 @@ final class DefaultPermissionGrantPolicy { && doesPackageSupportRuntimePermissions(setupPackage)) { grantRuntimePermissionsLPw(setupPackage, PHONE_PERMISSIONS, userId); grantRuntimePermissionsLPw(setupPackage, CONTACTS_PERMISSIONS, userId); + grantRuntimePermissionsLPw(setupPackage, LOCATION_PERMISSIONS, userId); } // Camera diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 7e186a0da0ee..34523ceb2445 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -59,6 +59,10 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; import static android.content.pm.PackageManager.MATCH_ALL; +import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; +import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; +import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES; import static android.content.pm.PackageManager.MOVE_FAILED_DOESNT_EXIST; import static android.content.pm.PackageManager.MOVE_FAILED_INTERNAL_ERROR; import static android.content.pm.PackageManager.MOVE_FAILED_OPERATION_PENDING; @@ -88,6 +92,8 @@ import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCES import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED; import android.Manifest; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AppGlobals; @@ -596,7 +602,9 @@ public class PackageManagerService extends IPackageManager.Stub { boolean mResolverReplaced = false; - private final ComponentName mIntentFilterVerifierComponent; + private final @Nullable ComponentName mIntentFilterVerifierComponent; + private final @Nullable IntentFilterVerifier<ActivityIntentInfo> mIntentFilterVerifier; + private int mIntentFilterVerificationToken = 0; /** Component that knows whether or not an ephemeral application exists */ @@ -807,7 +815,7 @@ public class PackageManagerService extends IPackageManager.Stub { packageName); } if (DEBUG_DOMAIN_VERIFICATION) { - Slog.d(TAG, "Adding verification filter for " + packageName + " : " + filter); + Slog.d(TAG, "Adding verification filter for " + packageName + ": " + filter); } ivs.addFilter(filter); return true; @@ -832,8 +840,6 @@ public class PackageManagerService extends IPackageManager.Stub { filter.hasDataScheme(IntentFilter.SCHEME_HTTPS)); } - private IntentFilterVerifier mIntentFilterVerifier; - // Set of pending broadcasts for aggregating enable/disable of components. static class PendingPackageBroadcasts { // for each user id, a map of <package name -> components within that package> @@ -968,8 +974,8 @@ public class PackageManagerService extends IPackageManager.Stub { private static final String TAG_DEFAULT_APPS = "da"; private static final String TAG_INTENT_FILTER_VERIFICATION = "iv"; - final String mRequiredVerifierPackage; - final String mRequiredInstallerPackage; + final @Nullable String mRequiredVerifierPackage; + final @Nullable String mRequiredInstallerPackage; private final PackageUsage mPackageUsage = new PackageUsage(); @@ -2356,15 +2362,21 @@ public class PackageManagerService extends IPackageManager.Stub { EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_PMS_READY, SystemClock.uptimeMillis()); - mRequiredVerifierPackage = getRequiredVerifierLPr(); - mRequiredInstallerPackage = getRequiredInstallerLPr(); + if (!mOnlyCore) { + mRequiredVerifierPackage = getRequiredButNotReallyRequiredVerifierLPr(); + mRequiredInstallerPackage = getRequiredInstallerLPr(); + mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr(); + mIntentFilterVerifier = new IntentVerifierProxy(mContext, + mIntentFilterVerifierComponent); + } else { + mRequiredVerifierPackage = null; + mRequiredInstallerPackage = null; + mIntentFilterVerifierComponent = null; + mIntentFilterVerifier = null; + } mInstallerService = new PackageInstallerService(context, this); - mIntentFilterVerifierComponent = getIntentFilterVerifierComponentNameLPr(); - mIntentFilterVerifier = new IntentVerifierProxy(mContext, - mIntentFilterVerifierComponent); - final ComponentName ephemeralResolverComponent = getEphemeralResolverLPr(); final ComponentName ephemeralInstallerComponent = getEphemeralInstallerLPr(); // both the installer and resolver must be present to enable ephemeral @@ -2426,113 +2438,61 @@ public class PackageManagerService extends IPackageManager.Stub { return mIsUpgrade; } - private String getRequiredVerifierLPr() { - final Intent verification = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); - // We only care about verifier that's installed under system user. - final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, - PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM); - - String requiredVerifier = null; - - final int N = receivers.size(); - for (int i = 0; i < N; i++) { - final ResolveInfo info = receivers.get(i); - - if (info.activityInfo == null) { - continue; - } - - final String packageName = info.activityInfo.packageName; - - if (checkPermission(android.Manifest.permission.PACKAGE_VERIFICATION_AGENT, - packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) { - continue; - } + private @Nullable String getRequiredButNotReallyRequiredVerifierLPr() { + final Intent intent = new Intent(Intent.ACTION_PACKAGE_NEEDS_VERIFICATION); - if (requiredVerifier != null) { - throw new RuntimeException("There can be only one required verifier"); - } - - requiredVerifier = packageName; + final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE, + MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM); + if (matches.size() == 1) { + return matches.get(0).getComponentInfo().packageName; + } else { + Log.e(TAG, "There should probably be exactly one verifier; found " + matches); + return null; } - - return requiredVerifier; } - private String getRequiredInstallerLPr() { - Intent installerIntent = new Intent(Intent.ACTION_INSTALL_PACKAGE); - installerIntent.addCategory(Intent.CATEGORY_DEFAULT); - installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE); - - final List<ResolveInfo> installers = queryIntentActivities(installerIntent, - PACKAGE_MIME_TYPE, 0, UserHandle.USER_SYSTEM); - - String requiredInstaller = null; - - final int N = installers.size(); - for (int i = 0; i < N; i++) { - final ResolveInfo info = installers.get(i); - final String packageName = info.activityInfo.packageName; - - if (!info.activityInfo.applicationInfo.isSystemApp()) { - continue; - } - - if (requiredInstaller != null) { - throw new RuntimeException("There must be one required installer"); - } + private @NonNull String getRequiredInstallerLPr() { + final Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE); - requiredInstaller = packageName; - } - - if (requiredInstaller == null) { - throw new RuntimeException("There must be one required installer"); + final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE, + MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM); + if (matches.size() == 1) { + return matches.get(0).getComponentInfo().packageName; + } else { + throw new RuntimeException("There must be exactly one installer; found " + matches); } - - return requiredInstaller; } - private ComponentName getIntentFilterVerifierComponentNameLPr() { - final Intent verification = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION); - final List<ResolveInfo> receivers = queryIntentReceivers(verification, PACKAGE_MIME_TYPE, - PackageManager.GET_DISABLED_COMPONENTS, UserHandle.USER_SYSTEM); + private @NonNull ComponentName getIntentFilterVerifierComponentNameLPr() { + final Intent intent = new Intent(Intent.ACTION_INTENT_FILTER_NEEDS_VERIFICATION); - ComponentName verifierComponentName = null; - - int priority = -1000; - final int N = receivers.size(); + final List<ResolveInfo> matches = queryIntentReceivers(intent, PACKAGE_MIME_TYPE, + MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM); + ResolveInfo best = null; + final int N = matches.size(); for (int i = 0; i < N; i++) { - final ResolveInfo info = receivers.get(i); - - if (info.activityInfo == null) { - continue; - } - - final String packageName = info.activityInfo.packageName; - - final PackageSetting ps = mSettings.mPackages.get(packageName); - if (ps == null) { - continue; - } - + final ResolveInfo cur = matches.get(i); + final String packageName = cur.getComponentInfo().packageName; if (checkPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT, packageName, UserHandle.USER_SYSTEM) != PackageManager.PERMISSION_GRANTED) { continue; } - // Select the IntentFilterVerifier with the highest priority - if (priority < info.priority) { - priority = info.priority; - verifierComponentName = new ComponentName(packageName, info.activityInfo.name); - if (DEBUG_DOMAIN_VERIFICATION) Slog.d(TAG, "Selecting IntentFilterVerifier: " - + verifierComponentName + " with priority: " + info.priority); + if (best == null || cur.priority > best.priority) { + best = cur; } } - return verifierComponentName; + if (best != null) { + return best.getComponentInfo().getComponentName(); + } else { + throw new RuntimeException("There must be at least one intent filter verifier"); + } } - private ComponentName getEphemeralResolverLPr() { + private @Nullable ComponentName getEphemeralResolverLPr() { final String[] packageArray = mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage); if (packageArray.length == 0) { @@ -2542,9 +2502,9 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } - Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE); - final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent, - null /*resolvedType*/, 0 /*flags*/, UserHandle.USER_SYSTEM); + final Intent resolverIntent = new Intent(Intent.ACTION_RESOLVE_EPHEMERAL_PACKAGE); + final List<ResolveInfo> resolvers = queryIntentServices(resolverIntent, null, + MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM); final int N = resolvers.size(); if (N == 0) { @@ -2583,36 +2543,21 @@ public class PackageManagerService extends IPackageManager.Stub { return null; } - private ComponentName getEphemeralInstallerLPr() { - Intent installerIntent = new Intent(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE); - installerIntent.addCategory(Intent.CATEGORY_DEFAULT); - installerIntent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE); - final List<ResolveInfo> installers = queryIntentActivities(installerIntent, - PACKAGE_MIME_TYPE, 0 /*flags*/, 0 /*userId*/); + private @Nullable ComponentName getEphemeralInstallerLPr() { + final Intent intent = new Intent(Intent.ACTION_INSTALL_EPHEMERAL_PACKAGE); + intent.addCategory(Intent.CATEGORY_DEFAULT); + intent.setDataAndType(Uri.fromFile(new File("foo.apk")), PACKAGE_MIME_TYPE); - ComponentName ephemeralInstaller = null; - - final int N = installers.size(); - for (int i = 0; i < N; i++) { - final ResolveInfo info = installers.get(i); - final String packageName = info.activityInfo.packageName; - - if (!info.activityInfo.applicationInfo.isSystemApp()) { - if (DEBUG_EPHEMERAL) { - Slog.d(TAG, "Ephemeral installer is not system app;" - + " pkg: " + packageName + ", info:" + info); - } - continue; - } - - if (ephemeralInstaller != null) { - throw new RuntimeException("There must only be one ephemeral installer"); - } - - ephemeralInstaller = new ComponentName(packageName, info.activityInfo.name); + final List<ResolveInfo> matches = queryIntentActivities(intent, PACKAGE_MIME_TYPE, + MATCH_SYSTEM_ONLY | MATCH_ENCRYPTION_AWARE_AND_UNAWARE, UserHandle.USER_SYSTEM); + if (matches.size() == 0) { + return null; + } else if (matches.size() == 1) { + return matches.get(0).getComponentInfo().getComponentName(); + } else { + throw new RuntimeException( + "There must be at most one ephemeral installer; found " + matches); } - - return ephemeralInstaller; } private void primeDomainVerificationsLPw(int userId) { @@ -2659,7 +2604,7 @@ public class PackageManagerService extends IPackageManager.Stub { + "' does not handle web links"); } } else { - Slog.w(TAG, "Unknown package '" + packageName + "' in sysconfig <app-link>"); + Slog.w(TAG, "Unknown package " + packageName + " in sysconfig <app-link>"); } } @@ -2857,7 +2802,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (p != null) { return generatePackageInfo(p, flags, userId); } - if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) { return generatePackageInfoFromSettingsLPw(packageName, flags, userId); } } @@ -2904,12 +2849,12 @@ public class PackageManagerService extends IPackageManager.Stub { // reader synchronized (mPackages) { final PackageParser.Package p = mPackages.get(packageName); - if (p != null) { + if (p != null && p.isMatch(flags)) { return UserHandle.getUid(userId, p.applicationInfo.uid); } - if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); - if (ps != null) { + if (ps != null && ps.isMatch(flags)) { return UserHandle.getUid(userId, ps.appId); } } @@ -2933,13 +2878,13 @@ public class PackageManagerService extends IPackageManager.Stub { // reader synchronized (mPackages) { final PackageParser.Package p = mPackages.get(packageName); - if (p != null) { + if (p != null && p.isMatch(flags)) { PackageSetting ps = (PackageSetting) p.mExtras; return ps.getPermissionsState().computeGids(userId); } - if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) { final PackageSetting ps = mSettings.mPackages.get(packageName); - if (ps != null) { + if (ps != null && ps.isMatch(flags)) { return ps.getPermissionsState().computeGids(userId); } } @@ -3045,7 +2990,7 @@ public class PackageManagerService extends IPackageManager.Stub { if (ps != null) { PackageParser.Package pkg = ps.pkg; if (pkg == null) { - if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) == 0) { + if ((flags & MATCH_UNINSTALLED_PACKAGES) == 0) { return null; } // Only data remains, so we aren't worried about code paths @@ -3084,7 +3029,7 @@ public class PackageManagerService extends IPackageManager.Stub { if ("android".equals(packageName)||"system".equals(packageName)) { return mAndroidApplication; } - if ((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { + if ((flags & MATCH_UNINSTALLED_PACKAGES) != 0) { return generateApplicationInfoFromSettingsLPw(packageName, flags, userId); } } @@ -3205,8 +3150,8 @@ public class PackageManagerService extends IPackageManager.Stub { */ private int updateFlagsForPackage(int flags, int userId, Object cookie) { boolean triaged = true; - if ((flags & PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS - | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS) != 0) { + if ((flags & (PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS + | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS)) != 0) { // Caller is asking for component details, so they'd better be // asking for specific encryption matching behavior, or be triaged if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE @@ -3216,12 +3161,13 @@ public class PackageManagerService extends IPackageManager.Stub { } } if ((flags & (PackageManager.MATCH_UNINSTALLED_PACKAGES + | PackageManager.MATCH_SYSTEM_ONLY | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) { triaged = false; } if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) { - Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie, - new Throwable()); + Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie + + " with flags 0x" + Integer.toHexString(flags), new Throwable()); } return updateFlagsForEncryption(flags, userId); } @@ -3237,6 +3183,12 @@ public class PackageManagerService extends IPackageManager.Stub { * Update given flags when being used to request {@link ComponentInfo}. */ private int updateFlagsForComponent(int flags, int userId, Object cookie) { + if (cookie instanceof Intent) { + if ((((Intent) cookie).getFlags() & Intent.FLAG_DEBUG_TRIAGED_MISSING) != 0) { + flags |= PackageManager.MATCH_DEBUG_TRIAGED_MISSING; + } + } + boolean triaged = true; // Caller is asking for component details, so they'd better be // asking for specific encryption matching behavior, or be triaged @@ -3246,8 +3198,8 @@ public class PackageManagerService extends IPackageManager.Stub { triaged = false; } if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) { - Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie, - new Throwable()); + Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie + + " with flags 0x" + Integer.toHexString(flags), new Throwable()); } return updateFlagsForEncryption(flags, userId); } @@ -3773,8 +3725,8 @@ public class PackageManagerService extends IPackageManager.Stub { final int flags = permissionsState.getPermissionFlags(name, userId); if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { - throw new SecurityException("Cannot grant system fixed permission: " - + name + " for package: " + packageName); + throw new SecurityException("Cannot grant system fixed permission " + + name + " for package " + packageName); } if (bp.isDevelopment()) { @@ -3882,8 +3834,8 @@ public class PackageManagerService extends IPackageManager.Stub { final int flags = permissionsState.getPermissionFlags(name, userId); if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) != 0) { - throw new SecurityException("Cannot revoke system fixed permission: " - + name + " for package: " + packageName); + throw new SecurityException("Cannot revoke system fixed permission " + + name + " for package " + packageName); } if (bp.isDevelopment()) { @@ -4688,7 +4640,7 @@ public class PackageManagerService extends IPackageManager.Stub { ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " "); } final ActivityInfo ai = getActivityInfo(ppa.mComponent, - flags | PackageManager.GET_DISABLED_COMPONENTS, userId); + flags | MATCH_DISABLED_COMPONENTS, userId); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Found persistent preferred activity:"); if (ai != null) { @@ -4797,7 +4749,7 @@ public class PackageManagerService extends IPackageManager.Stub { continue; } final ActivityInfo ai = getActivityInfo(pa.mPref.mComponent, - flags | PackageManager.GET_DISABLED_COMPONENTS, userId); + flags | MATCH_DISABLED_COMPONENTS, userId); if (DEBUG_PREFERRED || debug) { Slog.v(TAG, "Found preferred activity:"); if (ai != null) { @@ -5713,7 +5665,7 @@ public class PackageManagerService extends IPackageManager.Stub { public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) { if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForPackage(flags, userId, null); - final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0; enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "get installed packages"); // writer @@ -5794,7 +5746,7 @@ public class PackageManagerService extends IPackageManager.Stub { String[] permissions, int flags, int userId) { if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForPackage(flags, userId, permissions); - final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0; // writer synchronized (mPackages) { @@ -5822,7 +5774,7 @@ public class PackageManagerService extends IPackageManager.Stub { public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) { if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList(); flags = updateFlagsForApplication(flags, userId, null); - final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0; // writer synchronized (mPackages) { @@ -6335,7 +6287,7 @@ public class PackageManagerService extends IPackageManager.Stub { + " ignored: updated version " + ps.versionCode + " better than this " + pkg.mVersionCode); if (!updatedPkg.codePath.equals(scanFile)) { - Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg : " + Slog.w(PackageManagerService.TAG, "Code path for hidden system pkg " + ps.name + " changing from " + updatedPkg.codePathString + " to " + scanFile); updatedPkg.codePath = scanFile; @@ -6460,7 +6412,7 @@ public class PackageManagerService extends IPackageManager.Stub { baseResourcePath = ps.resourcePathString; } else { // Should not happen at all. Just log an error. - Slog.e(TAG, "Resource path not set for pkg : " + pkg.packageName); + Slog.e(TAG, "Resource path not set for package " + pkg.packageName); } } else { resourcePath = pkg.codePath; @@ -6709,7 +6661,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { pkg = mPackages.get(packageName); if (pkg == null) { - throw new IllegalArgumentException("Missing package: " + packageName); + throw new IllegalArgumentException("Unknown package: " + packageName); } } @@ -7219,7 +7171,7 @@ public class PackageManagerService extends IPackageManager.Stub { pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) { throw new PackageManagerException( INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES, - "Signature mismatch for shared user : " + "Signature mismatch for shared user: " + pkgSetting.sharedUser); } } @@ -7471,7 +7423,7 @@ public class PackageManagerService extends IPackageManager.Stub { if ((scanFlags & SCAN_NO_DEX) == 0 && (scanFlags & SCAN_NEW_INSTALL) != 0) { if (cpuAbiOverride == null && pkgSetting.cpuAbiOverrideString != null) { Slog.w(TAG, "Ignoring persisted ABI override " + cpuAbiOverride + - " for package: " + pkg.packageName); + " for package " + pkg.packageName); } } @@ -8178,7 +8130,7 @@ public class PackageManagerService extends IPackageManager.Stub { ps.primaryCpuAbiString = adjustedAbi; if (ps.pkg != null && ps.pkg.applicationInfo != null) { ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi; - Slog.i(TAG, "Adjusting ABI for : " + ps.name + " to " + adjustedAbi); + Slog.i(TAG, "Adjusting ABI for " + ps.name + " to " + adjustedAbi); mInstaller.rmdex(ps.codePathString, getDexCodeInstructionSet(getPreferredInstructionSet())); } @@ -8416,7 +8368,7 @@ public class PackageManagerService extends IPackageManager.Stub { // 64 bit apps will see a 64 bit primary ABI, if ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) == 0) { - Slog.e(TAG, "Package: " + pkg + " has multiple bundled libs, but is not multiarch."); + Slog.e(TAG, "Package " + pkg + " has multiple bundled libs, but is not multiarch."); } if (VMRuntime.is64BitInstructionSet(getPreferredInstructionSet())) { @@ -10662,7 +10614,7 @@ public class PackageManagerService extends IPackageManager.Stub { throw new SecurityException("Bad object " + obj + " for uid " + uid); } } else { - throw new SecurityException("Unknown calling uid " + uid); + throw new SecurityException("Unknown calling UID: " + uid); } // Verify: can't set installerPackageName to a package that is @@ -11263,9 +11215,9 @@ public class PackageManagerService extends IPackageManager.Stub { PACKAGE_MIME_TYPE); verification.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + // Query all live verifiers based on current user state final List<ResolveInfo> receivers = queryIntentReceivers(verification, - PACKAGE_MIME_TYPE, PackageManager.GET_DISABLED_COMPONENTS, - verifierUser.getIdentifier()); + PACKAGE_MIME_TYPE, 0, verifierUser.getIdentifier()); if (DEBUG_VERIFY) { Slog.d(TAG, "Found " + receivers.size() + " verifiers for intent " @@ -11576,8 +11528,8 @@ public class PackageManagerService extends IPackageManager.Stub { for (String dexCodeInstructionSet : dexCodeInstructionSets) { int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet); if (retCode < 0) { - Slog.w(TAG, "Couldn't remove dex file for package: " - + " at location " + codePath + ", retcode=" + retCode); + Slog.w(TAG, "Couldn't remove dex file for package at location " + codePath + + ", retcode=" + retCode); // we don't consider this to be a failure of the core package deletion } } @@ -12611,7 +12563,7 @@ public class PackageManagerService extends IPackageManager.Stub { if((oldPkg == null) || (oldPkg.applicationInfo == null) || (oldPkgSetting == null)) { res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, - "Couldn't find package:" + packageName + " information"); + "Couldn't find package " + packageName + " information"); return; } } @@ -13696,7 +13648,7 @@ public class PackageManagerService extends IPackageManager.Stub { try { newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, SCAN_NO_PATHS, 0, null); } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to restore system package:" + newPs.name + ": " + e.getMessage()); + Slog.w(TAG, "Failed to restore system package " + newPs.name + ": " + e.getMessage()); return false; } @@ -13914,13 +13866,13 @@ public class PackageManagerService extends IPackageManager.Stub { boolean ret = false; if (isSystemApp(ps)) { - if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name); + if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name); // When an updated system application is deleted we delete the existing resources as well and // fall back to existing code in system partition ret = deleteSystemPackageLI(ps, allUserHandles, perUserInstalled, flags, outInfo, writeSettings); } else { - if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package:" + ps.name); + if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name); // Kill application pre-emptively especially for apps on sd. killApplication(packageName, ps.appId, "uninstall pkg"); ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, @@ -14069,7 +14021,7 @@ public class PackageManagerService extends IPackageManager.Stub { // resorting to a full data wipe. int retCode = mInstaller.clearUserData(pkg.volumeUuid, packageName, userId); if (retCode < 0) { - Slog.w(TAG, "Couldn't remove cache files for package: " + packageName); + Slog.w(TAG, "Couldn't remove cache files for package " + packageName); return false; } @@ -14299,7 +14251,7 @@ public class PackageManagerService extends IPackageManager.Stub { } int retCode = mInstaller.deleteCacheFiles(p.volumeUuid, packageName, userId); if (retCode < 0) { - Slog.w(TAG, "Couldn't remove cache files for package: " + Slog.w(TAG, "Couldn't remove cache files for package " + packageName + " u" + userId); return false; } @@ -14744,7 +14696,7 @@ public class PackageManagerService extends IPackageManager.Stub { } synchronized (mPackages) { Slog.i(TAG, "Adding persistent preferred activity " + activity + " for user " + userId + - " :"); + ":"); filter.dump(new LogPrinter(Log.INFO, TAG), " "); mSettings.editPersistentPreferredActivitiesLPw(userId).addFilter( new PersistentPreferredActivity(filter, activity)); @@ -15149,12 +15101,10 @@ public class PackageManagerService extends IPackageManager.Stub { pkgSetting = mSettings.mPackages.get(packageName); if (pkgSetting == null) { if (className == null) { - throw new IllegalArgumentException( - "Unknown package: " + packageName); + throw new IllegalArgumentException("Unknown package: " + packageName); } throw new IllegalArgumentException( - "Unknown component: " + packageName - + "/" + className); + "Unknown component: " + packageName + "/" + className); } // Allow root and verify that userId is not being specified by a different user if (!allowedByPermission && !UserHandle.isSameApp(uid, pkgSetting.appId)) { @@ -17196,7 +17146,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized(mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { - Slog.w(TAG, "KeySet requested for unknown package:" + packageName); + Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } KeySetManagerService ksms = mSettings.mKeySetManagerService; @@ -17212,7 +17162,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized(mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { - Slog.w(TAG, "KeySet requested for unknown package:" + packageName); + Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } if (pkg.applicationInfo.uid != Binder.getCallingUid() @@ -17232,7 +17182,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized(mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { - Slog.w(TAG, "KeySet requested for unknown package:" + packageName); + Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } IBinder ksh = ks.getToken(); @@ -17252,7 +17202,7 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized(mPackages) { final PackageParser.Package pkg = mPackages.get(packageName); if (pkg == null) { - Slog.w(TAG, "KeySet requested for unknown package:" + packageName); + Slog.w(TAG, "KeySet requested for unknown package: " + packageName); throw new IllegalArgumentException("Unknown package: " + packageName); } IBinder ksh = ks.getToken(); diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index e7c0ef765164..f106b62d768b 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -17,6 +17,7 @@ package com.android.server.pm; import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; import android.content.pm.PackageParser; import java.io.File; @@ -78,4 +79,11 @@ final class PackageSetting extends PackageSettingBase { public boolean isSharedUser() { return sharedUser != null; } + + public boolean isMatch(int flags) { + if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { + return isSystem(); + } + return true; + } } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index b33013995350..3f9ce7a64aae 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -16,23 +16,42 @@ package com.android.server.pm; +import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import static android.Manifest.permission.READ_EXTERNAL_STORAGE; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS; import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; -import static android.os.Process.SYSTEM_UID; +import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; +import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS; +import static android.content.pm.PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS; +import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE; +import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE; +import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY; import static android.os.Process.PACKAGE_INFO_GID; +import static android.os.Process.SYSTEM_UID; + import static com.android.server.pm.PackageManagerService.DEBUG_DOMAIN_VERIFICATION; import android.annotation.NonNull; +import android.content.ComponentName; +import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.ComponentInfo; import android.content.pm.IntentFilterVerificationInfo; +import android.content.pm.PackageCleanItem; +import android.content.pm.PackageManager; +import android.content.pm.PackageParser; +import android.content.pm.PackageUserState; +import android.content.pm.PermissionInfo; import android.content.pm.ResolveInfo; +import android.content.pm.Signature; +import android.content.pm.UserInfo; +import android.content.pm.VerifierDeviceIdentity; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -47,11 +66,18 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; -import android.util.AtomicFile; import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.ArraySet; +import android.util.AtomicFile; +import android.util.Log; import android.util.LogPrinter; +import android.util.Slog; +import android.util.SparseArray; import android.util.SparseBooleanArray; +import android.util.SparseIntArray; import android.util.SparseLongArray; +import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.os.BackgroundThread; @@ -65,58 +91,37 @@ import com.android.server.backup.PreferredActivityBackupHelper; import com.android.server.pm.PackageManagerService.DumpState; import com.android.server.pm.PermissionsState.PermissionState; -import java.io.BufferedInputStream; -import java.io.BufferedWriter; -import java.io.FileNotFoundException; -import java.io.InputStream; -import java.io.OutputStreamWriter; -import java.nio.charset.Charset; -import java.util.Collection; +import libcore.io.IoUtils; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; -import android.content.ComponentName; -import android.content.Intent; -import android.content.pm.ApplicationInfo; -import android.content.pm.ComponentInfo; -import android.content.pm.PackageCleanItem; -import android.content.pm.PackageManager; -import android.content.pm.PackageParser; -import android.content.pm.PermissionInfo; -import android.content.pm.Signature; -import android.content.pm.UserInfo; -import android.content.pm.PackageUserState; -import android.content.pm.VerifierDeviceIdentity; -import android.util.ArrayMap; -import android.util.ArraySet; -import android.util.Log; -import android.util.Slog; -import android.util.SparseArray; -import android.util.SparseIntArray; -import android.util.Xml; - +import java.io.BufferedInputStream; import java.io.BufferedOutputStream; +import java.io.BufferedWriter; import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStreamWriter; import java.io.PrintWriter; +import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; 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.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Objects; import java.util.Set; -import java.util.Map.Entry; - -import libcore.io.IoUtils; /** * Holds information about dynamic settings. @@ -426,7 +431,7 @@ final class Settings { boolean disableSystemPackageLPw(String name) { final PackageSetting p = mPackages.get(name); if(p == null) { - Log.w(PackageManagerService.TAG, "Package:"+name+" is not an installed package"); + Log.w(PackageManagerService.TAG, "Package " + name + " is not an installed package"); return false; } final PackageSetting dp = mDisabledSysPackages.get(name); @@ -451,7 +456,7 @@ final class Settings { PackageSetting enableSystemPackageLPw(String name) { PackageSetting p = mDisabledSysPackages.get(name); if(p == null) { - Log.w(PackageManagerService.TAG, "Package:"+name+" is not disabled"); + Log.w(PackageManagerService.TAG, "Package " + name + " is not disabled"); return null; } // Reset flag in ApplicationInfo object @@ -1338,7 +1343,7 @@ final class Settings { throws XmlPullParserException, IOException { IntentFilterVerificationInfo ivi = new IntentFilterVerificationInfo(parser); packageSetting.setIntentFilterVerificationInfo(ivi); - Log.d(TAG, "Read domain verification for package:" + ivi.getPackageName()); + Log.d(TAG, "Read domain verification for package: " + ivi.getPackageName()); } private void readRestoredIntentFilterVerifications(XmlPullParser parser) @@ -1472,7 +1477,7 @@ final class Settings { String name = parser.getAttributeValue(null, ATTR_NAME); ps = mPackages.get(name); if (ps == null) { - Slog.w(PackageManagerService.TAG, "No package known for stopped package: " + Slog.w(PackageManagerService.TAG, "No package known for stopped package " + name); XmlUtils.skipCurrentTag(parser); continue; @@ -2036,7 +2041,7 @@ final class Settings { } } else { Slog.w(PackageManagerService.TAG, - "No package known for stopped package: " + name); + "No package known for stopped package " + name); } XmlUtils.skipCurrentTag(parser); } else { @@ -2857,7 +2862,7 @@ final class Settings { for (int i=0; i<tmpPa.countCategories(); i++) { String cat = tmpPa.getCategory(i); if (cat.equals(Intent.CATEGORY_DEFAULT)) { - flags |= PackageManager.MATCH_DEFAULT_ONLY; + flags |= MATCH_DEFAULT_ONLY; } else { intent.addCategory(cat); } @@ -3007,7 +3012,7 @@ final class Settings { filter.addCategory(cat); } } - if ((flags&PackageManager.MATCH_DEFAULT_ONLY) != 0) { + if ((flags & MATCH_DEFAULT_ONLY) != 0) { filter.addCategory(Intent.CATEGORY_DEFAULT); } if (scheme != null) { @@ -3799,7 +3804,7 @@ final class Settings { } private boolean isEnabledLPr(ComponentInfo componentInfo, int flags, int userId) { - if ((flags&PackageManager.GET_DISABLED_COMPONENTS) != 0) { + if ((flags & MATCH_DISABLED_COMPONENTS) != 0) { return true; } final PackageSetting packageSettings = mPackages.get(componentInfo.packageName); @@ -3815,7 +3820,7 @@ final class Settings { return false; } PackageUserState ustate = packageSettings.readUserState(userId); - if ((flags&PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS) != 0) { + if ((flags & MATCH_DISABLED_UNTIL_USED_COMPONENTS) != 0) { if (ustate.enabled == COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) { return true; } @@ -3839,16 +3844,16 @@ final class Settings { } private boolean isMatchLPr(ComponentInfo componentInfo, int flags) { - if ((flags & PackageManager.MATCH_SYSTEM_ONLY) != 0) { + if ((flags & MATCH_SYSTEM_ONLY) != 0) { final PackageSetting ps = mPackages.get(componentInfo.packageName); if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) == 0) { return false; } } - final boolean matchesUnaware = ((flags & PackageManager.MATCH_ENCRYPTION_UNAWARE) != 0) + final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0) && !componentInfo.encryptionAware; - final boolean matchesAware = ((flags & PackageManager.MATCH_ENCRYPTION_AWARE) != 0) + final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0) && componentInfo.encryptionAware; return matchesUnaware || matchesAware; } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 13f48263b69e..3d614a35c13b 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -69,6 +69,7 @@ import android.util.Xml; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsService; +import com.android.internal.logging.MetricsLogger; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; @@ -166,6 +167,10 @@ public class UserManagerService extends IUserManager.Stub { private static final String XATTR_SERIAL = "user.serial"; + // Tron counters + private static final String TRON_GUEST_CREATED = "users_guest_created"; + private static final String TRON_USER_CREATED = "users_user_created"; + private final Context mContext; private final PackageManagerService mPm; private final Object mPackagesLock; @@ -1830,6 +1835,7 @@ public class UserManagerService extends IUserManager.Stub { addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId); mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL, android.Manifest.permission.MANAGE_USERS); + MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED : TRON_USER_CREATED, 1); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 9bbc3c10213c..f0ed7907770d 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -33,6 +33,8 @@ import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.telephony.SubscriptionInfo; +import android.telephony.SubscriptionManager; import android.util.Log; import org.xmlpull.v1.XmlPullParser; @@ -40,10 +42,11 @@ import org.xmlpull.v1.XmlSerializer; import java.io.IOException; import java.io.PrintWriter; +import java.util.List; import java.util.Set; /** - * Utility methods for uesr restrictions. + * Utility methods for user restrictions. * * <p>See {@link UserManagerService} for the method suffixes. */ @@ -88,7 +91,8 @@ public class UserRestrictionsUtils { UserManager.ALLOW_PARENT_PROFILE_APP_LINKING, UserManager.DISALLOW_RECORD_AUDIO, UserManager.DISALLOW_CAMERA, - UserManager.DISALLOW_RUN_IN_BACKGROUND + UserManager.DISALLOW_RUN_IN_BACKGROUND, + UserManager.DISALLOW_DATA_ROAMING ); /** @@ -113,7 +117,8 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_SMS, UserManager.DISALLOW_FUN, UserManager.DISALLOW_SAFE_BOOT, - UserManager.DISALLOW_CREATE_WINDOWS + UserManager.DISALLOW_CREATE_WINDOWS, + UserManager.DISALLOW_DATA_ROAMING ); /** @@ -315,6 +320,27 @@ public class UserRestrictionsUtils { .WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, userId); } break; + case UserManager.DISALLOW_DATA_ROAMING: + if (newValue) { + // DISALLOW_DATA_ROAMING user restriction is set. + + // Multi sim device. + SubscriptionManager subscriptionManager = new SubscriptionManager(context); + final List<SubscriptionInfo> subscriptionInfoList = + subscriptionManager.getActiveSubscriptionInfoList(); + if (subscriptionInfoList != null) { + for (SubscriptionInfo subInfo : subscriptionInfoList) { + android.provider.Settings.Global.putStringForUser(cr, + android.provider.Settings.Global.DATA_ROAMING + + subInfo.getSubscriptionId(), "0", userId); + } + } + + // Single sim device. + android.provider.Settings.Global.putStringForUser(cr, + android.provider.Settings.Global.DATA_ROAMING, "0", userId); + } + break; case UserManager.DISALLOW_SHARE_LOCATION: if (newValue) { android.provider.Settings.Secure.putIntForUser(cr, diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java index 3eae7fcb6fe5..a0f20aa0f5b1 100644 --- a/services/core/java/com/android/server/policy/GlobalActions.java +++ b/services/core/java/com/android/server/policy/GlobalActions.java @@ -388,7 +388,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac public void run() { try { // Take an "interactive" bugreport. - ActivityManagerNative.getDefault().requestBugReport(true); + ActivityManagerNative.getDefault().requestBugReport( + ActivityManager.BUGREPORT_OPTION_INTERACTIVE); } catch (RemoteException e) { } } @@ -404,7 +405,8 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac } try { // Take a "full" bugreport. - ActivityManagerNative.getDefault().requestBugReport(false); + ActivityManagerNative.getDefault().requestBugReport( + ActivityManager.BUGREPORT_OPTION_FULL); } catch (RemoteException e) { } return false; diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index 72611b7703e9..f13d964e1e1b 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -18,6 +18,8 @@ package com.android.server.policy; import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.content.res.Configuration.UI_MODE_TYPE_CAR; +import static android.content.res.Configuration.UI_MODE_TYPE_MASK; import static android.view.WindowManager.LayoutParams.*; import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT; import static android.view.WindowManagerPolicy.WindowManagerFuncs.LID_OPEN; @@ -313,8 +315,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { boolean mCanHideNavigationBar = false; boolean mNavigationBarCanMove = false; // can the navigation bar ever move to the side? boolean mNavigationBarOnBottom = true; // is the navigation bar on the bottom *right now*? - int[] mNavigationBarHeightForRotation = new int[4]; - int[] mNavigationBarWidthForRotation = new int[4]; + int[] mNavigationBarHeightForRotationDefault = new int[4]; + int[] mNavigationBarWidthForRotationDefault = new int[4]; + int[] mNavigationBarHeightForRotationInCarMode = new int[4]; + int[] mNavigationBarWidthForRotationInCarMode = new int[4]; // Whether to allow dock apps with METADATA_DOCK_HOME to temporarily take over the Home key. // This is for car dock and this is updated from resource. @@ -1674,20 +1678,37 @@ public class PhoneWindowManager implements WindowManagerPolicy { res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height); // Height of the navigation bar when presented horizontally at bottom - mNavigationBarHeightForRotation[mPortraitRotation] = - mNavigationBarHeightForRotation[mUpsideDownRotation] = + mNavigationBarHeightForRotationDefault[mPortraitRotation] = + mNavigationBarHeightForRotationDefault[mUpsideDownRotation] = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height); - mNavigationBarHeightForRotation[mLandscapeRotation] = - mNavigationBarHeightForRotation[mSeascapeRotation] = res.getDimensionPixelSize( + mNavigationBarHeightForRotationDefault[mLandscapeRotation] = + mNavigationBarHeightForRotationDefault[mSeascapeRotation] = res.getDimensionPixelSize( com.android.internal.R.dimen.navigation_bar_height_landscape); // Width of the navigation bar when presented vertically along one side - mNavigationBarWidthForRotation[mPortraitRotation] = - mNavigationBarWidthForRotation[mUpsideDownRotation] = - mNavigationBarWidthForRotation[mLandscapeRotation] = - mNavigationBarWidthForRotation[mSeascapeRotation] = + mNavigationBarWidthForRotationDefault[mPortraitRotation] = + mNavigationBarWidthForRotationDefault[mUpsideDownRotation] = + mNavigationBarWidthForRotationDefault[mLandscapeRotation] = + mNavigationBarWidthForRotationDefault[mSeascapeRotation] = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width); + // Height of the navigation bar when presented horizontally at bottom + mNavigationBarHeightForRotationInCarMode[mPortraitRotation] = + mNavigationBarHeightForRotationInCarMode[mUpsideDownRotation] = + res.getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height_car_mode); + mNavigationBarHeightForRotationInCarMode[mLandscapeRotation] = + mNavigationBarHeightForRotationInCarMode[mSeascapeRotation] = res.getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_height_landscape_car_mode); + + // Width of the navigation bar when presented vertically along one side + mNavigationBarWidthForRotationInCarMode[mPortraitRotation] = + mNavigationBarWidthForRotationInCarMode[mUpsideDownRotation] = + mNavigationBarWidthForRotationInCarMode[mLandscapeRotation] = + mNavigationBarWidthForRotationInCarMode[mSeascapeRotation] = + res.getDimensionPixelSize( + com.android.internal.R.dimen.navigation_bar_width_car_mode); + // SystemUI (status bar) layout policy int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / density; int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / density; @@ -2239,42 +2260,61 @@ public class PhoneWindowManager implements WindowManagerPolicy { return windowTypeToLayerLw(TYPE_STATUS_BAR); } + private int getNavigationBarWidth(int rotation, int uiMode) { + if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) { + return mNavigationBarWidthForRotationInCarMode[rotation]; + } else { + return mNavigationBarWidthForRotationDefault[rotation]; + } + } + @Override - public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation) { + public int getNonDecorDisplayWidth(int fullWidth, int fullHeight, int rotation, + int uiMode) { if (mHasNavigationBar) { // For a basic navigation bar, when we are in landscape mode we place // the navigation bar to the side. if (mNavigationBarCanMove && fullWidth > fullHeight) { - return fullWidth - mNavigationBarWidthForRotation[rotation]; + return fullWidth - getNavigationBarWidth(rotation, uiMode); } } return fullWidth; } + private int getNavigationBarHeight(int rotation, int uiMode) { + if ((uiMode & UI_MODE_TYPE_MASK) == UI_MODE_TYPE_CAR) { + return mNavigationBarHeightForRotationInCarMode[rotation]; + } else { + return mNavigationBarHeightForRotationDefault[rotation]; + } + } + @Override - public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation) { + public int getNonDecorDisplayHeight(int fullWidth, int fullHeight, int rotation, + int uiMode) { if (mHasNavigationBar) { // For a basic navigation bar, when we are in portrait mode we place // the navigation bar to the bottom. if (!mNavigationBarCanMove || fullWidth < fullHeight) { - return fullHeight - mNavigationBarHeightForRotation[rotation]; + return fullHeight - getNavigationBarHeight(rotation, uiMode); } } return fullHeight; } @Override - public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation) { - return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation); + public int getConfigDisplayWidth(int fullWidth, int fullHeight, int rotation, int uiMode) { + return getNonDecorDisplayWidth(fullWidth, fullHeight, rotation, uiMode); } @Override - public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation) { + public int getConfigDisplayHeight(int fullWidth, int fullHeight, int rotation, int uiMode) { // There is a separate status bar at the top of the display. We don't count that as part // of the fixed decor, since it can hide; however, for purposes of configurations, // we do want to exclude it since applications can't generally use that part // of the screen. - return getNonDecorDisplayHeight(fullWidth, fullHeight, rotation) - mStatusBarHeight; + return getNonDecorDisplayHeight( + fullWidth, fullHeight, rotation, uiMode) - mStatusBarHeight; } @Override @@ -2879,7 +2919,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else if (keyCode == KeyEvent.KEYCODE_SLASH && event.isMetaPressed()) { if (down) { if (repeatCount == 0) { - showKeyboardShortcutsMenu(); + toggleKeyboardShortcutsMenu(); } } } else if (keyCode == KeyEvent.KEYCODE_ASSIST) { @@ -3311,11 +3351,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } - private void showKeyboardShortcutsMenu() { + private void toggleKeyboardShortcutsMenu() { try { IStatusBarService statusbar = getStatusBarService(); if (statusbar != null) { - statusbar.showKeyboardShortcutsMenu(); + statusbar.toggleKeyboardShortcutsMenu(); } } catch (RemoteException e) { Slog.e(TAG, "RemoteException when showing keyboard shortcuts menu", e); @@ -3550,7 +3590,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { /** {@inheritDoc} */ @Override public void beginLayoutLw(boolean isDefaultDisplay, int displayWidth, int displayHeight, - int displayRotation) { + int displayRotation, int uiMode) { mDisplayRotation = displayRotation; final int overscanLeft, overscanTop, overscanRight, overscanBottom; if (isDefaultDisplay) { @@ -3661,7 +3701,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { navVisible |= !canHideNavigationBar(); boolean updateSysUiVisibility = layoutNavigationBar(displayWidth, displayHeight, - displayRotation, overscanRight, overscanBottom, dcf, navVisible, navTranslucent, + displayRotation, uiMode, overscanRight, overscanBottom, dcf, navVisible, navTranslucent, navAllowedHidden); if (DEBUG_LAYOUT) Slog.i(TAG, String.format("mDock rect: (%d,%d - %d,%d)", mDockLeft, mDockTop, mDockRight, mDockBottom)); @@ -3740,7 +3780,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } private boolean layoutNavigationBar(int displayWidth, int displayHeight, int displayRotation, - int overscanRight, int overscanBottom, Rect dcf, boolean navVisible, + int uiMode, int overscanRight, int overscanBottom, Rect dcf, boolean navVisible, boolean navTranslucent, boolean navAllowedHidden) { if (mNavigationBar != null) { boolean transientNavBarShowing = mNavigationBarController.isTransientShowing(); @@ -3752,7 +3792,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { if (mNavigationBarOnBottom) { // It's a system nav bar or a portrait screen; nav bar goes on bottom. int top = displayHeight - overscanBottom - - mNavigationBarHeightForRotation[displayRotation]; + - getNavigationBarHeight(displayRotation, uiMode); mTmpNavigationFrame.set(0, top, displayWidth, displayHeight - overscanBottom); mStableBottom = mStableFullscreenBottom = mTmpNavigationFrame.top; if (transientNavBarShowing) { @@ -3777,7 +3817,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { // Landscape screen; nav bar goes to the right. int left = displayWidth - overscanRight - - mNavigationBarWidthForRotation[displayRotation]; + - getNavigationBarWidth(displayRotation, uiMode); mTmpNavigationFrame.set(left, 0, displayWidth - overscanRight, displayHeight); mStableRight = mStableFullscreenRight = mTmpNavigationFrame.left; if (transientNavBarShowing) { diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 6498dd941a32..290019c73ba4 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -16,21 +16,8 @@ package com.android.server.power; -import android.app.ActivityManager; -import android.util.SparseIntArray; -import com.android.internal.app.IAppOpsService; -import com.android.internal.app.IBatteryStats; -import com.android.internal.os.BackgroundThread; -import com.android.server.EventLogTags; -import com.android.server.ServiceThread; -import com.android.server.SystemService; -import com.android.server.am.BatteryStatsService; -import com.android.server.lights.Light; -import com.android.server.lights.LightsManager; -import com.android.server.Watchdog; - import android.Manifest; -import android.app.AppOpsManager; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.ContentResolver; import android.content.Context; @@ -65,22 +52,32 @@ import android.provider.Settings; import android.service.dreams.DreamManagerInternal; import android.util.EventLog; import android.util.Slog; +import android.util.SparseIntArray; import android.util.TimeUtils; import android.view.Display; import android.view.WindowManagerPolicy; +import com.android.internal.app.IAppOpsService; +import com.android.internal.app.IBatteryStats; +import com.android.internal.os.BackgroundThread; +import com.android.server.EventLogTags; +import com.android.server.ServiceThread; +import com.android.server.SystemService; +import com.android.server.Watchdog; +import com.android.server.am.BatteryStatsService; +import com.android.server.lights.Light; +import com.android.server.lights.LightsManager; +import libcore.util.Objects; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; -import libcore.util.Objects; - import static android.os.PowerManagerInternal.POWER_HINT_INTERACTION; import static android.os.PowerManagerInternal.WAKEFULNESS_ASLEEP; import static android.os.PowerManagerInternal.WAKEFULNESS_AWAKE; -import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING; import static android.os.PowerManagerInternal.WAKEFULNESS_DOZING; +import static android.os.PowerManagerInternal.WAKEFULNESS_DREAMING; /** * The power manager service is responsible for coordinating power management @@ -771,6 +768,10 @@ public final class PowerManagerService extends SystemService intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); mContext.sendBroadcast(intent); + // Send internal version that requires signature permission. + mContext.sendBroadcastAsUser(new Intent( + PowerManager.ACTION_POWER_SAVE_MODE_CHANGED_INTERNAL), UserHandle.ALL, + Manifest.permission.DEVICE_POWER); } }); } diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index fc271704a1ec..2a1f46e25953 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -17,22 +17,20 @@ package com.android.server.statusbar; import android.app.StatusBarManager; +import android.content.Context; +import android.content.pm.PackageManager; import android.os.Binder; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; import android.os.UserHandle; -import android.content.Context; -import android.content.pm.PackageManager; -import android.content.res.Resources; +import android.util.ArrayMap; import android.util.Slog; - import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.IStatusBarService; import com.android.internal.statusbar.NotificationVisibility; import com.android.internal.statusbar.StatusBarIcon; -import com.android.internal.statusbar.StatusBarIconList; import com.android.server.LocalServices; import com.android.server.notification.NotificationDelegate; import com.android.server.wm.WindowManagerService; @@ -56,7 +54,7 @@ public class StatusBarManagerService extends IStatusBarService.Stub { private Handler mHandler = new Handler(); private NotificationDelegate mNotificationDelegate; private volatile IStatusBar mBar; - private StatusBarIconList mIcons = new StatusBarIconList(); + private ArrayMap<String, StatusBarIcon> mIcons = new ArrayMap<>(); // for disabling the status bar private final ArrayList<DisableRecord> mDisableRecords = new ArrayList<DisableRecord>(); @@ -96,9 +94,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub { mContext = context; mWindowManager = windowManager; - final Resources res = context.getResources(); - mIcons.defineSlots(res.getStringArray(com.android.internal.R.array.config_statusBarIcons)); - LocalServices.addService(StatusBarManagerInternal.class, mInternalService); } @@ -300,19 +295,14 @@ public class StatusBarManagerService extends IStatusBarService.Stub { enforceStatusBar(); synchronized (mIcons) { - int index = mIcons.getSlotIndex(slot); - if (index < 0) { - throw new SecurityException("invalid status bar icon slot: " + slot); - } - StatusBarIcon icon = new StatusBarIcon(iconPackage, UserHandle.SYSTEM, iconId, iconLevel, 0, contentDescription); //Slog.d(TAG, "setIcon slot=" + slot + " index=" + index + " icon=" + icon); - mIcons.setIcon(index, icon); + mIcons.put(slot, icon); if (mBar != null) { try { - mBar.setIcon(index, icon); + mBar.setIcon(slot, icon); } catch (RemoteException ex) { } } @@ -320,26 +310,20 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void setIconVisibility(String slot, boolean visible) { + public void setIconVisibility(String slot, boolean visibility) { enforceStatusBar(); synchronized (mIcons) { - int index = mIcons.getSlotIndex(slot); - if (index < 0) { - throw new SecurityException("invalid status bar icon slot: " + slot); - } - - StatusBarIcon icon = mIcons.getIcon(index); + StatusBarIcon icon = mIcons.get(slot); if (icon == null) { return; } - - if (icon.visible != visible) { - icon.visible = visible; + if (icon.visible != visibility) { + icon.visible = visibility; if (mBar != null) { try { - mBar.setIcon(index, icon); + mBar.setIcon(slot, icon); } catch (RemoteException ex) { } } @@ -352,16 +336,11 @@ public class StatusBarManagerService extends IStatusBarService.Stub { enforceStatusBar(); synchronized (mIcons) { - int index = mIcons.getSlotIndex(slot); - if (index < 0) { - throw new SecurityException("invalid status bar icon slot: " + slot); - } - - mIcons.removeIcon(index); + mIcons.remove(slot); if (mBar != null) { try { - mBar.removeIcon(index); + mBar.removeIcon(slot); } catch (RemoteException ex) { } } @@ -503,10 +482,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override - public void showKeyboardShortcutsMenu() { + public void toggleKeyboardShortcutsMenu() { if (mBar != null) { try { - mBar.showKeyboardShortcutsMenu(); + mBar.toggleKeyboardShortcutsMenu(); } catch (RemoteException ex) {} } } @@ -583,14 +562,17 @@ public class StatusBarManagerService extends IStatusBarService.Stub { // Callbacks from the status bar service. // ================================================================================ @Override - public void registerStatusBar(IStatusBar bar, StatusBarIconList iconList, - int switches[], List<IBinder> binders) { + public void registerStatusBar(IStatusBar bar, List<String> iconSlots, + List<StatusBarIcon> iconList, int switches[], List<IBinder> binders) { enforceStatusBarService(); Slog.i(TAG, "registerStatusBar bar=" + bar); mBar = bar; synchronized (mIcons) { - iconList.copyFrom(mIcons); + for (String slot : mIcons.keySet()) { + iconSlots.add(slot); + iconList.add(mIcons.get(slot)); + } } synchronized (mLock) { switches[0] = gatherDisableActionsLocked(mCurrentUserId, 1); @@ -812,10 +794,6 @@ public class StatusBarManagerService extends IStatusBarService.Stub { return; } - synchronized (mIcons) { - mIcons.dump(pw); - } - synchronized (mLock) { pw.println(" mDisabled1=0x" + Integer.toHexString(mDisabled1)); pw.println(" mDisabled2=0x" + Integer.toHexString(mDisabled2)); diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java index 573aaec034cf..751f8715a1e1 100644 --- a/services/core/java/com/android/server/wm/AppWindowToken.java +++ b/services/core/java/com/android/server/wm/AppWindowToken.java @@ -25,6 +25,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY; import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import static com.android.server.wm.WindowManagerService.WINDOW_REPLACEMENT_TIMEOUT_DURATION; import com.android.server.input.InputApplicationHandle; import com.android.server.wm.WindowManagerService.H; @@ -403,12 +404,28 @@ class AppWindowToken extends WindowToken { } } + void resetReplacingWindows() { + if (DEBUG_ADD_REMOVE) Slog.d(TAG_WM, "Resetting app token " + appWindowToken + + " of replacing window marks."); + + for (int i = allAppWindows.size() - 1; i >= 0; i--) { + final WindowState w = allAppWindows.get(i); + w.resetReplacing(); + } + } + void addWindow(WindowState w) { for (int i = allAppWindows.size() - 1; i >= 0; i--) { WindowState candidate = allAppWindows.get(i); if (candidate.mWillReplaceWindow && candidate.mReplacingWindow == null && candidate.getWindowTag().equals(w.getWindowTag().toString())) { candidate.mReplacingWindow = w; + + // if we got a replacement window, reset the timeout to give drawing more time + service.mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT); + service.mH.sendMessageDelayed( + service.mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, this), + WINDOW_REPLACEMENT_TIMEOUT_DURATION); } } allAppWindows.add(w); @@ -424,7 +441,7 @@ class AppWindowToken extends WindowToken { return false; } - void clearTimedoutReplaceesLocked() { + void clearTimedoutReplacesLocked() { for (int i = allAppWindows.size() - 1; i >= 0; // removeWindowLocked at bottom of loop may remove multiple entries from // allAppWindows if the window to be removed has child windows. It also may @@ -437,7 +454,11 @@ class AppWindowToken extends WindowToken { continue; } candidate.mWillReplaceWindow = false; - service.removeWindowLocked(candidate); + // Since the window already timed out, remove it immediately now. + // Use removeWindowInnerLocked() instead of removeWindowLocked(), as the latter + // delays removal on certain conditions, which will leave the stale window in the + // stack and marked mWillReplaceWindow=false, so the window will never be removed. + service.removeWindowInnerLocked(candidate); } } diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 59421984dc1f..51787b066859 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -570,38 +570,19 @@ class DisplayContent { pw.print("x"); pw.println(mDisplayInfo.largestNominalAppHeight); pw.print(subPrefix); pw.print("deferred="); pw.print(mDeferredRemoval); pw.print(" layoutNeeded="); pw.println(layoutNeeded); - for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { - final TaskStack stack = mStacks.get(stackNdx); - pw.print(prefix); pw.print("mStacks[" + stackNdx + "]"); pw.println(stack.mStackId); - stack.dump(prefix + " ", pw); - } + pw.println(); pw.println(" Application tokens in top down Z order:"); - int ndx = 0; for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { final TaskStack stack = mStacks.get(stackNdx); - pw.print(" mStackId="); pw.println(stack.mStackId); - ArrayList<Task> tasks = stack.getTasks(); - for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { - final Task task = tasks.get(taskNdx); - pw.print(" mTaskId="); pw.println(task.mTaskId); - AppTokenList tokens = task.mAppTokens; - for (int tokenNdx = tokens.size() - 1; tokenNdx >= 0; --tokenNdx, ++ndx) { - final AppWindowToken wtoken = tokens.get(tokenNdx); - pw.print(" Activity #"); pw.print(tokenNdx); - pw.print(' '); pw.print(wtoken); pw.println(":"); - wtoken.dump(pw, " "); - } - } - } - if (ndx == 0) { - pw.println(" None"); + stack.dump(prefix + " ", pw); } + pw.println(); if (!mExitingTokens.isEmpty()) { pw.println(); pw.println(" Exiting tokens:"); - for (int i=mExitingTokens.size()-1; i>=0; i--) { + for (int i = mExitingTokens.size() - 1; i >= 0; i--) { WindowToken token = mExitingTokens.get(i); pw.print(" Exiting #"); pw.print(i); pw.print(' '); pw.print(token); diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 223e03ad4cc4..b4ddebc7c346 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -157,8 +157,17 @@ class Task implements DimLayer.DimLayerUser { mDeferRemoval = false; } + private boolean hasAppTokensAlive() { + for (int i = mAppTokens.size() - 1; i >= 0; i--) { + if (!mAppTokens.get(i).appDied) { + return true; + } + } + return false; + } + void removeLocked() { - if (!mAppTokens.isEmpty() && mStack.isAnimating()) { + if (hasAppTokensAlive() && mStack.isAnimating()) { if (DEBUG_STACK) Slog.i(TAG_WM, "removeTask: deferring removing taskId=" + mTaskId); mDeferRemoval = true; return; @@ -603,12 +612,23 @@ class Task implements DimLayer.DimLayerUser { return "Task=" + mTaskId; } - public void printTo(String prefix, PrintWriter pw) { - pw.print(prefix); pw.print("taskId="); pw.println(mTaskId); - pw.print(prefix + prefix); pw.print("mFullscreen="); pw.println(mFullscreen); - pw.print(prefix + prefix); pw.print("mBounds="); pw.println(mBounds.toShortString()); - pw.print(prefix + prefix); pw.print("mdr="); pw.println(mDeferRemoval); - pw.print(prefix + prefix); pw.print("appTokens="); pw.println(mAppTokens); - pw.print(prefix + prefix); pw.print("mTempInsetBounds="); pw.println(mTempInsetBounds); + public void dump(String prefix, PrintWriter pw) { + final String doublePrefix = prefix + " "; + + pw.println(prefix + "taskId=" + mTaskId); + pw.println(doublePrefix + "mFullscreen=" + mFullscreen); + pw.println(doublePrefix + "mBounds=" + mBounds.toShortString()); + pw.println(doublePrefix + "mdr=" + mDeferRemoval); + pw.println(doublePrefix + "appTokens=" + mAppTokens); + pw.println(doublePrefix + "mTempInsetBounds=" + mTempInsetBounds.toShortString()); + + final String triplePrefix = doublePrefix + " "; + + for (int i = mAppTokens.size() - 1; i >= 0; i--) { + final AppWindowToken wtoken = mAppTokens.get(i); + pw.println(triplePrefix + "Activity #" + i + " " + wtoken); + wtoken.dump(pw, triplePrefix); + } + } } diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java index 67debe6e3773..fc6ad70513b1 100644 --- a/services/core/java/com/android/server/wm/TaskStack.java +++ b/services/core/java/com/android/server/wm/TaskStack.java @@ -619,16 +619,15 @@ public class TaskStack implements DimLayer.DimLayerUser { } public void dump(String prefix, PrintWriter pw) { - pw.print(prefix); pw.print("mStackId="); pw.println(mStackId); - pw.print(prefix); pw.print("mDeferDetach="); pw.println(mDeferDetach); - pw.print(prefix); pw.print("mFullscreen="); pw.println(mFullscreen); - pw.print(prefix); pw.print("mBounds="); pw.println(mBounds.toShortString()); - for (int taskNdx = 0; taskNdx < mTasks.size(); ++taskNdx) { - pw.print(prefix); - mTasks.get(taskNdx).printTo(prefix + " ", pw); + pw.println(prefix + "mStackId=" + mStackId); + pw.println(prefix + "mDeferDetach=" + mDeferDetach); + pw.println(prefix + "mFullscreen=" + mFullscreen); + pw.println(prefix + "mBounds=" + mBounds.toShortString()); + for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; taskNdx--) { + mTasks.get(taskNdx).dump(prefix + " ", pw); } if (mAnimationBackgroundSurface.isDimming()) { - pw.print(prefix); pw.println("mWindowAnimationBackgroundSurface:"); + pw.println(prefix + "mWindowAnimationBackgroundSurface:"); mAnimationBackgroundSurface.printTo(prefix + " ", pw); } if (!mExitingAppTokens.isEmpty()) { diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java index 845100d14eec..4c3a422731b3 100644 --- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java +++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java @@ -35,7 +35,7 @@ public class WindowManagerDebugConfig { static final boolean DEBUG_RESIZE = false; static final boolean DEBUG = false; - static final boolean DEBUG_ADD_REMOVE = false; + static final boolean DEBUG_ADD_REMOVE = true; static final boolean DEBUG_FOCUS = true; static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false; static final boolean DEBUG_ANIM = false; @@ -50,8 +50,8 @@ public class WindowManagerDebugConfig { static final boolean DEBUG_ORIENTATION = false; static final boolean DEBUG_APP_ORIENTATION = false; static final boolean DEBUG_CONFIGURATION = false; - static final boolean DEBUG_APP_TRANSITIONS = false; - static final boolean DEBUG_STARTING_WINDOW = false; + static final boolean DEBUG_APP_TRANSITIONS = true; + static final boolean DEBUG_STARTING_WINDOW = true; static final boolean DEBUG_WALLPAPER = false; static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER; static final boolean DEBUG_DRAG = false; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d722ec7a4803..2477acd15cd9 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -578,31 +578,23 @@ public class WindowManagerService extends IWindowManager.Stub final ArrayList<WindowState> mTmpWindows = new ArrayList<>(); boolean mHardKeyboardAvailable; - boolean mShowImeWithHardKeyboard; WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener; SettingsObserver mSettingsObserver; private final class SettingsObserver extends ContentObserver { - private final Uri mShowImeWithHardKeyboardUri = - Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); - private final Uri mDisplayInversionEnabledUri = Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED); public SettingsObserver() { super(new Handler()); ContentResolver resolver = mContext.getContentResolver(); - resolver.registerContentObserver(mShowImeWithHardKeyboardUri, false, this, - UserHandle.USER_ALL); resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this, UserHandle.USER_ALL); } @Override public void onChange(boolean selfChange, Uri uri) { - if (mShowImeWithHardKeyboardUri.equals(uri)) { - updateShowImeWithHardKeyboard(); - } else if (mDisplayInversionEnabledUri.equals(uri)) { + if (mDisplayInversionEnabledUri.equals(uri)) { updateCircularDisplayMaskIfNeeded(); } } @@ -946,7 +938,6 @@ public class WindowManagerService extends IWindowManager.Stub mContext.registerReceiver(mBroadcastReceiver, filter); mSettingsObserver = new SettingsObserver(); - updateShowImeWithHardKeyboard(); mHoldingScreenWakeLock = mPowerManager.newWakeLock( PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE, TAG_WM); @@ -2238,9 +2229,8 @@ public class WindowManagerService extends IWindowManager.Stub // trigger its removal. final boolean lastWinStartingNotAnimating = startingWindow && appToken!= null && appToken.allAppWindows.size() == 1 && !isAnimating; - if (!lastWinStartingNotAnimating && (win.mExiting || isAnimating)) { + if (!lastWinStartingNotAnimating && win.mExiting) { // The exit animation is running... wait for it! - win.mExiting = true; win.mRemoveOnExit = true; win.setDisplayLayoutNeeded(); final boolean focusChanged = updateFocusedWindowLocked( @@ -3478,6 +3468,7 @@ public class WindowManagerService extends IWindowManager.Stub // the value of the previous configuration. mTempConfiguration.setToDefaults(); mTempConfiguration.fontScale = currentConfig.fontScale; + mTempConfiguration.uiMode = currentConfig.uiMode; computeScreenConfigurationLocked(mTempConfiguration); if (currentConfig.diff(mTempConfiguration) != 0) { mWaitingForConfig = true; @@ -3888,7 +3879,7 @@ public class WindowManagerService extends IWindowManager.Stub return false; } WindowState startingWindow = ttoken.startingWindow; - if (startingWindow != null) { + if (startingWindow != null && ttoken.startingView != null) { // In this case, the starting icon has already been displayed, so start // letting windows get shown immediately without any more transitions. mSkipAppTransitionAnimation = true; @@ -6295,7 +6286,7 @@ public class WindowManagerService extends IWindowManager.Stub // the top of the method, the caller is obligated to call computeNewConfigurationLocked(). // By updating the Display info here it will be available to // computeScreenConfigurationLocked later. - updateDisplayAndOrientationLocked(); + updateDisplayAndOrientationLocked(mCurConfiguration.uiMode); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); if (!inTransaction) { @@ -6862,16 +6853,17 @@ public class WindowManagerService extends IWindowManager.Stub return config; } - private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int dw, int dh) { + private void adjustDisplaySizeRanges(DisplayInfo displayInfo, int rotation, int uiMode, + int dw, int dh) { // TODO: Multidisplay: for now only use with default display. - final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation); + final int width = mPolicy.getConfigDisplayWidth(dw, dh, rotation, uiMode); if (width < displayInfo.smallestNominalAppWidth) { displayInfo.smallestNominalAppWidth = width; } if (width > displayInfo.largestNominalAppWidth) { displayInfo.largestNominalAppWidth = width; } - final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation); + final int height = mPolicy.getConfigDisplayHeight(dw, dh, rotation, uiMode); if (height < displayInfo.smallestNominalAppHeight) { displayInfo.smallestNominalAppHeight = height; } @@ -6881,11 +6873,11 @@ public class WindowManagerService extends IWindowManager.Stub } private int reduceConfigLayout(int curLayout, int rotation, float density, - int dw, int dh) { + int dw, int dh, int uiMode) { // TODO: Multidisplay: for now only use with default display. // Get the app screen size at this rotation. - int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation); - int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation); + int w = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode); + int h = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode); // Compute the screen layout size class for this rotation. int longSize = w; @@ -6901,7 +6893,7 @@ public class WindowManagerService extends IWindowManager.Stub } private void computeSizeRangesAndScreenLayout(DisplayInfo displayInfo, boolean rotated, - int dw, int dh, float density, Configuration outConfig) { + int uiMode, int dw, int dh, float density, Configuration outConfig) { // TODO: Multidisplay: for now only use with default display. // We need to determine the smallest width that will occur under normal @@ -6920,24 +6912,24 @@ public class WindowManagerService extends IWindowManager.Stub displayInfo.smallestNominalAppHeight = 1<<30; displayInfo.largestNominalAppWidth = 0; displayInfo.largestNominalAppHeight = 0; - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, unrotDw, unrotDh); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, unrotDh, unrotDw); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, unrotDw, unrotDh); - adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, unrotDh, unrotDw); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_0, uiMode, unrotDw, unrotDh); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_90, uiMode, unrotDh, unrotDw); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_180, uiMode, unrotDw, unrotDh); + adjustDisplaySizeRanges(displayInfo, Surface.ROTATION_270, uiMode, unrotDh, unrotDw); int sl = Configuration.resetScreenLayout(outConfig.screenLayout); - sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh); - sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw); - sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh); - sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw); + sl = reduceConfigLayout(sl, Surface.ROTATION_0, density, unrotDw, unrotDh, uiMode); + sl = reduceConfigLayout(sl, Surface.ROTATION_90, density, unrotDh, unrotDw, uiMode); + sl = reduceConfigLayout(sl, Surface.ROTATION_180, density, unrotDw, unrotDh, uiMode); + sl = reduceConfigLayout(sl, Surface.ROTATION_270, density, unrotDh, unrotDw, uiMode); outConfig.smallestScreenWidthDp = (int)(displayInfo.smallestNominalAppWidth / density); outConfig.screenLayout = sl; } - private int reduceCompatConfigWidthSize(int curSize, int rotation, DisplayMetrics dm, - int dw, int dh) { + private int reduceCompatConfigWidthSize(int curSize, int rotation, int uiMode, + DisplayMetrics dm, int dw, int dh) { // TODO: Multidisplay: for now only use with default display. - dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation); - dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation); + dm.noncompatWidthPixels = mPolicy.getNonDecorDisplayWidth(dw, dh, rotation, uiMode); + dm.noncompatHeightPixels = mPolicy.getNonDecorDisplayHeight(dw, dh, rotation, uiMode); float scale = CompatibilityInfo.computeCompatibleScaling(dm, null); int size = (int)(((dm.noncompatWidthPixels / scale) / dm.density) + .5f); if (curSize == 0 || size < curSize) { @@ -6946,7 +6938,7 @@ public class WindowManagerService extends IWindowManager.Stub return curSize; } - private int computeCompatSmallestWidth(boolean rotated, DisplayMetrics dm, int dw, int dh) { + private int computeCompatSmallestWidth(boolean rotated, int uiMode, DisplayMetrics dm, int dw, int dh) { // TODO: Multidisplay: for now only use with default display. mTmpDisplayMetrics.setTo(dm); final DisplayMetrics tmpDm = mTmpDisplayMetrics; @@ -6958,15 +6950,15 @@ public class WindowManagerService extends IWindowManager.Stub unrotDw = dw; unrotDh = dh; } - int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, tmpDm, unrotDw, unrotDh); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, tmpDm, unrotDh, unrotDw); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, tmpDm, unrotDw, unrotDh); - sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, tmpDm, unrotDh, unrotDw); + int sw = reduceCompatConfigWidthSize(0, Surface.ROTATION_0, uiMode, tmpDm, unrotDw, unrotDh); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_90, uiMode, tmpDm, unrotDh, unrotDw); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_180, uiMode, tmpDm, unrotDw, unrotDh); + sw = reduceCompatConfigWidthSize(sw, Surface.ROTATION_270, uiMode, tmpDm, unrotDh, unrotDw); return sw; } /** Do not call if mDisplayReady == false */ - DisplayInfo updateDisplayAndOrientationLocked() { + DisplayInfo updateDisplayAndOrientationLocked(int uiMode) { // TODO(multidisplay): For now, apply Configuration to main screen only. final DisplayContent displayContent = getDefaultDisplayContentLocked(); @@ -6997,8 +6989,8 @@ public class WindowManagerService extends IWindowManager.Stub } // Update application display metrics. - final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation); - final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation); + final int appWidth = mPolicy.getNonDecorDisplayWidth(dw, dh, mRotation, uiMode); + final int appHeight = mPolicy.getNonDecorDisplayHeight(dw, dh, mRotation, uiMode); final DisplayInfo displayInfo = displayContent.getDisplayInfo(); displayInfo.rotation = mRotation; displayInfo.logicalWidth = dw; @@ -7030,20 +7022,24 @@ public class WindowManagerService extends IWindowManager.Stub /** Do not call if mDisplayReady == false */ void computeScreenConfigurationLocked(Configuration config) { - final DisplayInfo displayInfo = updateDisplayAndOrientationLocked(); + final DisplayInfo displayInfo = updateDisplayAndOrientationLocked( + config.uiMode); final int dw = displayInfo.logicalWidth; final int dh = displayInfo.logicalHeight; config.orientation = (dw <= dh) ? Configuration.ORIENTATION_PORTRAIT : Configuration.ORIENTATION_LANDSCAPE; config.screenWidthDp = - (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation) / mDisplayMetrics.density); + (int)(mPolicy.getConfigDisplayWidth(dw, dh, mRotation, config.uiMode) / + mDisplayMetrics.density); config.screenHeightDp = - (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation) / mDisplayMetrics.density); + (int)(mPolicy.getConfigDisplayHeight(dw, dh, mRotation, config.uiMode) / + mDisplayMetrics.density); final boolean rotated = (mRotation == Surface.ROTATION_90 || mRotation == Surface.ROTATION_270); - computeSizeRangesAndScreenLayout(displayInfo, rotated, dw, dh, mDisplayMetrics.density, - config); + + computeSizeRangesAndScreenLayout(displayInfo, rotated, config.uiMode, dw, dh, + mDisplayMetrics.density, config); config.screenLayout = (config.screenLayout & ~Configuration.SCREENLAYOUT_ROUND_MASK) | ((displayInfo.flags & Display.FLAG_ROUND) != 0 @@ -7052,7 +7048,7 @@ public class WindowManagerService extends IWindowManager.Stub config.compatScreenWidthDp = (int)(config.screenWidthDp / mCompatibleScreenScale); config.compatScreenHeightDp = (int)(config.screenHeightDp / mCompatibleScreenScale); - config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, + config.compatSmallestScreenWidthDp = computeCompatSmallestWidth(rotated, config.uiMode, mDisplayMetrics, dw, dh); config.densityDpi = displayInfo.logicalDensityDpi; @@ -7111,9 +7107,6 @@ public class WindowManagerService extends IWindowManager.Stub mH.removeMessages(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); mH.sendEmptyMessage(H.REPORT_HARD_KEYBOARD_STATUS_CHANGE); } - if (mShowImeWithHardKeyboard) { - config.keyboard = Configuration.KEYBOARD_NOKEYS; - } // Let the policy update hidden states. config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO; @@ -7122,18 +7115,6 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence); } - public void updateShowImeWithHardKeyboard() { - synchronized (mWindowMap) { - final boolean showImeWithHardKeyboard = Settings.Secure.getIntForUser( - mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0, - mCurrentUserId) == 1; - if (mShowImeWithHardKeyboard != showImeWithHardKeyboard) { - mShowImeWithHardKeyboard = showImeWithHardKeyboard; - mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION); - } - } - } - void notifyHardKeyboardStatusChange() { final boolean available; final WindowManagerInternal.OnHardKeyboardStatusChangeListener listener; @@ -8106,7 +8087,7 @@ public class WindowManagerService extends IWindowManager.Stub case WINDOW_REPLACEMENT_TIMEOUT: { final AppWindowToken token = (AppWindowToken) msg.obj; synchronized (mWindowMap) { - token.clearTimedoutReplaceesLocked(); + token.clearTimedoutReplacesLocked(); } } break; @@ -8471,6 +8452,7 @@ public class WindowManagerService extends IWindowManager.Stub boolean configChanged = updateOrientationFromAppTokensLocked(false); mTempConfiguration.setToDefaults(); mTempConfiguration.fontScale = mCurConfiguration.fontScale; + mTempConfiguration.uiMode = mCurConfiguration.uiMode; computeScreenConfigurationLocked(mTempConfiguration); configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0; @@ -9787,17 +9769,22 @@ public class WindowManagerService extends IWindowManager.Stub boolean dumpWindows(PrintWriter pw, String name, String[] args, int opti, boolean dumpAll) { WindowList windows = new WindowList(); - if ("visible".equals(name) || "visible-apps".equals(name)) { - final boolean appsOnly = "visible-apps".equals(name); + if ("apps".equals(name) || "visible".equals(name) || "visible-apps".equals(name)) { + final boolean appsOnly = name.contains("apps"); + final boolean visibleOnly = name.contains("visible"); synchronized(mWindowMap) { + if (appsOnly) { + dumpDisplayContentsLocked(pw, true); + } + final int numDisplays = mDisplayContents.size(); for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) { final WindowList windowList = mDisplayContents.valueAt(displayNdx).getWindowList(); for (int winNdx = windowList.size() - 1; winNdx >= 0; --winNdx) { final WindowState w = windowList.get(winNdx); - if (w.mWinAnimator.getShown() - && (!appsOnly || (appsOnly && w.mAppToken != null))) { + if ((!visibleOnly || w.mWinAnimator.getShown()) + && (!appsOnly || w.mAppToken != null)) { windows.add(w); } } @@ -10192,11 +10179,34 @@ public class WindowManagerService extends IWindowManager.Stub } appWindowToken.setReplacingWindows(animate); } + } - if (appWindowToken != null) { - mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT); - mH.sendMessageDelayed(mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken), - WINDOW_REPLACEMENT_TIMEOUT_DURATION); + /** + * If we're replacing the window, schedule a timer to clear the replaced window + * after a timeout, in case the replacing window is not coming. + * + * If we're not replacing the window, clear the replace window settings of the app. + * + * @param token Application token for the activity whose window might be replaced. + * @param replacing Whether the window is being replaced or not. + */ + public void scheduleClearReplacingWindowIfNeeded(IBinder token, boolean replacing) { + AppWindowToken appWindowToken = null; + synchronized (mWindowMap) { + appWindowToken = findAppWindowToken(token); + if (appWindowToken == null) { + Slog.w(TAG_WM, "Attempted to reset replacing window on non-existing app token " + + token); + return; + } + if (replacing) { + mH.removeMessages(H.WINDOW_REPLACEMENT_TIMEOUT); + mH.sendMessageDelayed( + mH.obtainMessage(H.WINDOW_REPLACEMENT_TIMEOUT, appWindowToken), + WINDOW_REPLACEMENT_TIMEOUT_DURATION); + } else { + appWindowToken.resetReplacingWindows(); + } } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 6e4e01f38212..b7fd60f1c201 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -2363,4 +2363,10 @@ final class WindowState implements WindowManagerPolicy.WindowState { mReplacingWindow = null; mAnimateReplacingWindow = animate; } + + void resetReplacing() { + mWillReplaceWindow = false; + mReplacingWindow = null; + mAnimateReplacingWindow = false; + } } diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java index feeab27e8fae..f77e5a6cab32 100644 --- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java +++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java @@ -859,7 +859,8 @@ class WindowSurfacePlacer { + displayContent.layoutNeeded + " dw=" + dw + " dh=" + dh); } - mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation); + mService.mPolicy.beginLayoutLw(isDefaultDisplay, dw, dh, mService.mRotation, + mService.mCurConfiguration.uiMode); if (isDefaultDisplay) { // Not needed on non-default displays. mService.mSystemDecorLayer = mService.mPolicy.getSystemDecorLayerLw(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index cf661ce0d166..dd58b3c4443e 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -129,6 +129,7 @@ import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo; +import com.android.server.pm.UserManagerService; import com.android.server.pm.UserRestrictionsUtils; import org.xmlpull.v1.XmlPullParser; @@ -424,6 +425,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final String TAG_PACKAGE_LIST_ITEM = "item"; private static final String TAG_KEEP_UNINSTALLED_PACKAGES = "keep-uninstalled-packages"; private static final String TAG_USER_RESTRICTIONS = "user-restrictions"; + private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message"; + private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message"; + private static final String TAG_PARENT_ADMIN = "parent-admin"; final DeviceAdminInfo info; @@ -476,6 +480,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { boolean disableScreenCapture = false; // Can only be set by a device/profile owner. boolean requireAutoTime = false; // Can only be set by a device owner. + ActiveAdmin parentAdmin; + final boolean isParent; + static class TrustAgentInfo { public PersistableBundle options; TrustAgentInfo(PersistableBundle bundle) { @@ -509,8 +516,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Bundle userRestrictions; - ActiveAdmin(DeviceAdminInfo _info) { + // Support text provided by the admin to display to the user. + String shortSupportMessage = null; + String longSupportMessage = null; + + ActiveAdmin(DeviceAdminInfo _info, boolean parent) { info = _info; + isParent = parent; + } + + ActiveAdmin getParentActiveAdmin() { + if (parentAdmin == null && !isParent) { + parentAdmin = new ActiveAdmin(info, /* parent */ true); + } + return parentAdmin; } int getUid() { return info.getActivityInfo().applicationInfo.uid; } @@ -688,6 +707,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { UserRestrictionsUtils.writeRestrictions( out, userRestrictions, TAG_USER_RESTRICTIONS); } + if (!TextUtils.isEmpty(shortSupportMessage)) { + out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE); + out.text(shortSupportMessage); + out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE); + } + if (!TextUtils.isEmpty(longSupportMessage)) { + out.startTag(null, TAG_LONG_SUPPORT_MESSAGE); + out.text(longSupportMessage); + out.endTag(null, TAG_LONG_SUPPORT_MESSAGE); + } + if (parentAdmin != null) { + out.startTag(null, TAG_PARENT_ADMIN); + parentAdmin.writeToXml(out); + out.endTag(null, TAG_PARENT_ADMIN); + } } void writePackageListToXml(XmlSerializer out, String outerTag, @@ -801,6 +835,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { keepUninstalledPackages = readPackageList(parser, tag); } else if (TAG_USER_RESTRICTIONS.equals(tag)) { UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions()); + } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + shortSupportMessage = parser.getText(); + } else { + Log.w(LOG_TAG, "Missing text when loading short support message"); + } + } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) { + type = parser.next(); + if (type == XmlPullParser.TEXT) { + longSupportMessage = parser.getText(); + } else { + Log.w(LOG_TAG, "Missing text when loading long support message"); + } + } else if (TAG_PARENT_ADMIN.equals(tag)) { + parentAdmin = new ActiveAdmin(info, /* parent */ true); + parentAdmin.readFromXml(parser); } else { Slog.w(LOG_TAG, "Unknown admin tag: " + tag); XmlUtils.skipCurrentTag(parser); @@ -1599,6 +1650,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + /** + * Find the admin for the component and userId bit of the uid, then check + * the admin's uid matches the uid. + */ + private ActiveAdmin getActiveAdminForUidLocked(ComponentName who, int uid) { + final int userId = UserHandle.getUserId(uid); + final DevicePolicyData policy = getUserData(userId); + ActiveAdmin admin = policy.mAdminMap.get(who); + if (admin == null) { + throw new SecurityException("No active admin " + who); + } + if (admin.getUid() != uid) { + throw new SecurityException("Admin " + who + " is not owned by uid " + uid); + } + return admin; + } + private ActiveAdmin getActiveAdminWithPolicyForUidLocked(ComponentName who, int reqPolicy, int uid) { // Try to find an admin which can use reqPolicy @@ -1610,8 +1678,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throw new SecurityException("No active admin " + who); } if (admin.getUid() != uid) { - throw new SecurityException("Admin " + who + " is not owned by uid " - + mInjector.binderGetCallingUid()); + throw new SecurityException("Admin " + who + " is not owned by uid " + uid); } if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) { return admin; @@ -1744,7 +1811,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { enforceCrossUserPermission(userHandle); Intent resolveIntent = new Intent(); resolveIntent.setComponent(adminName); - List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers( + List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceiversAsUser( resolveIntent, PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS, userHandle); @@ -1968,7 +2035,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + userHandle); } if (dai != null) { - ActiveAdmin ap = new ActiveAdmin(dai); + ActiveAdmin ap = new ActiveAdmin(dai, /* parent */ false); ap.readFromXml(parser); policy.mAdminMap.put(ap.info.getComponent(), ap); } @@ -2359,7 +2426,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) { throw new IllegalArgumentException("Admin is already added"); } - ActiveAdmin newAdmin = new ActiveAdmin(info); + ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false); policy.mAdminMap.put(adminReceiver, newAdmin); int replaceIndex = -1; final int N = policy.mAdminList.size(); @@ -2494,8 +2561,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + private boolean isAdminApiLevelPreN(@NonNull ComponentName who, int userHandle) { + DeviceAdminInfo adminInfo = findAdmin(who, userHandle, false); + return adminInfo.getActivityInfo().applicationInfo.targetSdkVersion + < Build.VERSION_CODES.N; + } + @Override - public void setPasswordQuality(ComponentName who, int quality) { + public void setPasswordQuality(ComponentName who, int quality, boolean parent) { if (!mHasFeature) { return; } @@ -2506,6 +2579,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + if (parent) { + ap = ap.getParentActiveAdmin(); + } if (ap.passwordQuality != quality) { ap.passwordQuality = quality; saveSettingsLocked(userHandle); @@ -2514,7 +2590,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public int getPasswordQuality(ComponentName who, int userHandle) { + public int getPasswordQuality(ComponentName who, int userHandle, boolean parent) { if (!mHasFeature) { return DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; } @@ -2524,20 +2600,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (who != null) { ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + if (parent && admin != null) { + admin = admin.getParentActiveAdmin(); + } return admin != null ? admin.passwordQuality : mode; } - // Return strictest policy for this user and profiles that are visible from this user. - List<UserInfo> profiles = mUserManager.getProfiles(userHandle); - for (UserInfo userInfo : profiles) { - DevicePolicyData policy = getUserDataUnchecked(userInfo.id); + if (LockPatternUtils.isSeparateWorkChallengeEnabled() && !parent) { + // If a Work Challenge is in use, only return its restrictions. + DevicePolicyData policy = getUserDataUnchecked(userHandle); final int N = policy.mAdminList.size(); - for (int i=0; i<N; i++) { + for (int i = 0; i < N; i++) { ActiveAdmin admin = policy.mAdminList.get(i); if (mode < admin.passwordQuality) { mode = admin.passwordQuality; } } + } else { + // Return strictest policy for this user and profiles that are visible from this + // user that do not use a separate work challenge. + // TODO: When there are separate parent restrictions the profile should just + // obey its own. + List<UserInfo> profiles = mUserManager.getProfiles(userHandle); + for (UserInfo userInfo : profiles) { + // Only aggregate data for the parent profile plus the non-work challenge + // enabled profiles. + if (!(userInfo.isManagedProfile() + && LockPatternUtils.isSeparateWorkChallengeEnabled())) { + DevicePolicyData policy = getUserDataUnchecked(userInfo.id); + final int N = policy.mAdminList.size(); + for (int i = 0; i < N; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); + if (mode < admin.passwordQuality) { + mode = admin.passwordQuality; + } + } + } + } } return mode; } @@ -3097,7 +3196,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public boolean isActivePasswordSufficient(int userHandle) { + public boolean isActivePasswordSufficient(int userHandle, boolean parent) { if (!mHasFeature) { return true; } @@ -3109,8 +3208,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); - if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle) + ActiveAdmin admin = + getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + ComponentName adminComponentName = admin.info.getComponent(); + // TODO: Include the Admin sdk level check in LockPatternUtils check. + ComponentName who = !isAdminApiLevelPreN(adminComponentName, userHandle) + && LockPatternUtils.isSeparateWorkChallengeEnabled() + ? adminComponentName : null; + if (policy.mActivePasswordQuality < getPasswordQuality(who, userHandle, parent) || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) { return false; } @@ -3275,7 +3380,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } } - quality = getPasswordQuality(null, userHandle); + quality = getPasswordQuality(null, userHandle, false); if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { int realQuality = LockPatternUtils.computePasswordQuality(password); if (realQuality < quality @@ -3572,7 +3677,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } try { - int uid = mContext.getPackageManager().getPackageUid( + int uid = mContext.getPackageManager().getPackageUidAsUser( policy.mDelegatedCertInstallerPackage, userHandle); return uid == callingUid; } catch (NameNotFoundException e) { @@ -4732,7 +4837,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Preconditions.checkNotNull(packageName, "packageName is null"); final int callingUid = mInjector.binderGetCallingUid(); try { - int uid = mContext.getPackageManager().getPackageUid(packageName, 0); + int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, 0); if (uid != callingUid) { throw new SecurityException("Invalid packageName"); } @@ -5241,7 +5346,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } try { - int uid = mContext.getPackageManager().getPackageUid( + int uid = mContext.getPackageManager().getPackageUidAsUser( policy.mApplicationRestrictionsManagingPackage, userHandle); return uid == callingUid; } catch (NameNotFoundException e) { @@ -7104,4 +7209,99 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public void setShortSupportMessage(@NonNull ComponentName who, String message) { + if (!mHasFeature) { + return; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = mInjector.userHandleGetCallingUserId(); + synchronized (this) { + ActiveAdmin admin = getActiveAdminForUidLocked(who, + mInjector.binderGetCallingUid()); + if (!TextUtils.equals(admin.shortSupportMessage, message)) { + admin.shortSupportMessage = message; + saveSettingsLocked(userHandle); + } + } + } + + @Override + public String getShortSupportMessage(@NonNull ComponentName who) { + if (!mHasFeature) { + return null; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + synchronized (this) { + ActiveAdmin admin = getActiveAdminForUidLocked(who, + mInjector.binderGetCallingUid()); + return admin.shortSupportMessage; + } + } + + @Override + public void setLongSupportMessage(@NonNull ComponentName who, String message) { + if (!mHasFeature) { + return; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = mInjector.userHandleGetCallingUserId(); + synchronized (this) { + ActiveAdmin admin = getActiveAdminForUidLocked(who, + mInjector.binderGetCallingUid()); + if (!TextUtils.equals(admin.longSupportMessage, message)) { + admin.longSupportMessage = message; + saveSettingsLocked(userHandle); + } + } + } + + @Override + public String getLongSupportMessage(@NonNull ComponentName who) { + if (!mHasFeature) { + return null; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + synchronized (this) { + ActiveAdmin admin = getActiveAdminForUidLocked(who, + mInjector.binderGetCallingUid()); + return admin.longSupportMessage; + } + } + + @Override + public String getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) { + if (!mHasFeature) { + return null; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) { + throw new SecurityException("Only the system can query support message for user"); + } + synchronized (this) { + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + if (admin != null) { + return admin.shortSupportMessage; + } + } + return null; + } + + @Override + public String getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) { + if (!mHasFeature) { + return null; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) { + throw new SecurityException("Only the system can query support message for user"); + } + synchronized (this) { + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); + if (admin != null) { + return admin.longSupportMessage; + } + } + return null; + } } diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java index d5f384d3bbfb..00e1acb4d267 100644 --- a/services/print/java/com/android/server/print/PrintManagerService.java +++ b/services/print/java/com/android/server/print/PrintManagerService.java @@ -24,7 +24,6 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.drawable.Icon; @@ -56,7 +55,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.Iterator; import java.util.List; -import java.util.Set; /** * SystemService wrapper for the PrintManager implementation. Publishes @@ -88,11 +86,6 @@ public final class PrintManagerService extends SystemService { } class PrintManagerImpl extends IPrintManager.Stub { - private static final char COMPONENT_NAME_SEPARATOR = ':'; - - private static final String EXTRA_PRINT_SERVICE_COMPONENT_NAME = - "EXTRA_PRINT_SERVICE_COMPONENT_NAME"; - private static final int BACKGROUND_USER_ID = -10; private final Object mLock = new Object(); @@ -487,7 +480,7 @@ public final class PrintManagerService extends SystemService { private void registerContentObservers() { final Uri enabledPrintServicesUri = Settings.Secure.getUriFor( - Settings.Secure.ENABLED_PRINT_SERVICES); + Settings.Secure.DISABLED_PRINT_SERVICES); ContentObserver observer = new ContentObserver(BackgroundThread.getHandler()) { @Override public void onChange(boolean selfChange, Uri uri, int userId) { @@ -511,8 +504,7 @@ public final class PrintManagerService extends SystemService { private void registerBroadcastReceivers() { PackageMonitor monitor = new PackageMonitor() { - @Override - public void onPackageModified(String packageName) { + private void updateServices(String packageName) { if (!mUserManager.isUserUnlocked(getChangingUserId())) return; synchronized (mLock) { // A background user/profile's print jobs are running but there is @@ -520,11 +512,15 @@ public final class PrintManagerService extends SystemService { // to handle it as the change may affect ongoing print jobs. boolean servicesChanged = false; UserState userState = getOrCreateUserStateLocked(getChangingUserId()); - Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); - while (iterator.hasNext()) { - ComponentName componentName = iterator.next(); - if (packageName.equals(componentName.getPackageName())) { + + List<PrintServiceInfo> installedServices = userState + .getInstalledPrintServices(); + final int numInstalledServices = installedServices.size(); + for (int i = 0; i < numInstalledServices; i++) { + if (installedServices.get(i).getResolveInfo().serviceInfo.packageName + .equals(packageName)) { servicesChanged = true; + break; } } if (servicesChanged) { @@ -534,30 +530,17 @@ public final class PrintManagerService extends SystemService { } @Override + public void onPackageModified(String packageName) { + if (!mUserManager.isUserUnlocked(getChangingUserId())) return; + updateServices(packageName); + getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices(); + } + + @Override public void onPackageRemoved(String packageName, int uid) { if (!mUserManager.isUserUnlocked(getChangingUserId())) return; - synchronized (mLock) { - // A background user/profile's print jobs are running but there is - // no UI shown. Hence, if the packages of such a user change we need - // to handle it as the change may affect ongoing print jobs. - boolean servicesRemoved = false; - UserState userState = getOrCreateUserStateLocked(getChangingUserId()); - Iterator<ComponentName> iterator = userState.getEnabledServices().iterator(); - while (iterator.hasNext()) { - ComponentName componentName = iterator.next(); - if (packageName.equals(componentName.getPackageName())) { - userState.removeApprovedPrintService(componentName); - iterator.remove(); - servicesRemoved = true; - } - } - if (servicesRemoved) { - persistComponentNamesToSettingLocked( - Settings.Secure.ENABLED_PRINT_SERVICES, - userState.getEnabledServices(), getChangingUserId()); - userState.updateIfNeededLocked(); - } - } + updateServices(packageName); + getOrCreateUserStateLocked(getChangingUserId()).prunePrintServices(); } @Override @@ -570,10 +553,10 @@ public final class PrintManagerService extends SystemService { // to handle it as the change may affect ongoing print jobs. UserState userState = getOrCreateUserStateLocked(getChangingUserId()); boolean stoppedSomePackages = false; - Iterator<ComponentName> iterator = userState.getEnabledServices() + Iterator<PrintServiceInfo> iterator = userState.getEnabledPrintServices() .iterator(); while (iterator.hasNext()) { - ComponentName componentName = iterator.next(); + ComponentName componentName = iterator.next().getComponentName(); String componentPackage = componentName.getPackageName(); for (String stoppedPackage : stoppedPackages) { if (componentPackage.equals(stoppedPackage)) { @@ -606,47 +589,10 @@ public final class PrintManagerService extends SystemService { .queryIntentServicesAsUser(intent, PackageManager.GET_SERVICES, getChangingUserId()); - if (installedServices == null) { - return; - } - - // Enable all added services by default - synchronized (mLock) { + if (installedServices != null) { UserState userState = getOrCreateUserStateLocked(getChangingUserId()); - - Set<ComponentName> enabledServices = userState.getEnabledServices(); - boolean servicesAdded = false; - - final int installedServiceCount = installedServices.size(); - for (int i = 0; i < installedServiceCount; i++) { - ServiceInfo serviceInfo = installedServices.get(i).serviceInfo; - ComponentName component = new ComponentName(serviceInfo.packageName, - serviceInfo.name); - - enabledServices.add(component); - servicesAdded = true; - } - - if (servicesAdded) { - persistComponentNamesToSettingLocked( - Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices, - getChangingUserId()); - userState.updateIfNeededLocked(); - } - } - } - - private void persistComponentNamesToSettingLocked(String settingName, - Set<ComponentName> componentNames, int userId) { - StringBuilder builder = new StringBuilder(); - for (ComponentName componentName : componentNames) { - if (builder.length() > 0) { - builder.append(COMPONENT_NAME_SEPARATOR); - } - builder.append(componentName.flattenToShortString()); + userState.updateIfNeededLocked(); } - Settings.Secure.putStringForUser(mContext.getContentResolver(), - settingName, builder.toString(), userId); } }; diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java index 40a888041d2d..d179b95548f4 100644 --- a/services/print/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java @@ -37,17 +37,18 @@ import android.print.IPrintSpoolerClient; import android.print.PrintJobId; import android.print.PrintJobInfo; import android.print.PrinterId; +import android.printservice.PrintService; import android.util.Slog; import android.util.TimedRemoteCaller; +import libcore.io.IoUtils; + import java.io.FileDescriptor; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.List; import java.util.concurrent.TimeoutException; -import libcore.io.IoUtils; - /** * This represents the remote print spooler as a local object to the * PrintManagerService. It is responsible to connecting to the remote @@ -439,26 +440,24 @@ final class RemotePrintSpooler { } /** - * Connect to the print spooler service and remove an approved print service. + * Remove all approved {@link PrintService print services} that are not in the given set. * - * @param serviceToRemove The {@link ComponentName} of the service to be removed. + * @param servicesToKeep The {@link ComponentName names } of the services to keep */ - public final void removeApprovedPrintService(ComponentName serviceToRemove) { + public final void pruneApprovedPrintServices(List<ComponentName> servicesToKeep) { throwIfCalledOnMainThread(); synchronized (mLock) { throwIfDestroyedLocked(); mCanUnbind = false; } try { - getRemoteInstanceLazy().removeApprovedPrintService(serviceToRemove); - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Error removing approved print service.", re); - } catch (TimeoutException te) { - Slog.e(LOG_TAG, "Error removing approved print service.", te); + getRemoteInstanceLazy().pruneApprovedPrintServices(servicesToKeep); + } catch (RemoteException|TimeoutException re) { + Slog.e(LOG_TAG, "Error pruning approved print services.", re); } finally { if (DEBUG) { Slog.i(LOG_TAG, "[user: " + mUserHandle.getIdentifier() - + "] removing approved print service()"); + + "] pruneApprovedPrintServices()"); } synchronized (mLock) { mCanUnbind = true; diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java index 63d330198488..dcc02a3638e8 100644 --- a/services/print/java/com/android/server/print/UserState.java +++ b/services/print/java/com/android/server/print/UserState.java @@ -21,11 +21,9 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentSender; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; -import android.content.pm.ServiceInfo; import android.graphics.drawable.Icon; import android.net.Uri; import android.os.AsyncTask; @@ -98,7 +96,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { private final List<PrintServiceInfo> mInstalledServices = new ArrayList<PrintServiceInfo>(); - private final Set<ComponentName> mEnabledServices = + private final Set<ComponentName> mDisabledServices = new ArraySet<ComponentName>(); private final PrintJobForAppCache mPrintJobForAppCache = @@ -126,8 +124,15 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { mLock = lock; mSpooler = new RemotePrintSpooler(context, userId, this); mHandler = new UserStateHandler(context.getMainLooper()); + synchronized (mLock) { - enableSystemPrintServicesLocked(); + readInstalledPrintServicesLocked(); + upgradePersistentStateIfNeeded(); + readDisabledPrintServicesLocked(); + + // Some print services might have gotten installed before the User State came up + prunePrintServices(); + onConfigurationChangedLocked(); } } @@ -320,15 +325,6 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { } } - /** - * Remove an approved print service. - * - * @param serviceToRemove The {@link ComponentName} of the service to be removed. - */ - public void removeApprovedPrintService(ComponentName serviceToRemove) { - mSpooler.removeApprovedPrintService(serviceToRemove); - } - public void restartPrintJob(PrintJobId printJobId, int appId) { PrintJobInfo printJobInfo = getPrintJobInfo(printJobId, appId); if (printJobInfo == null || printJobInfo.getState() != PrintJobInfo.STATE_FAILED) { @@ -597,13 +593,6 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { } } - public Set<ComponentName> getEnabledServices() { - synchronized(mLock) { - throwIfDestroyedLocked(); - return mEnabledServices; - } - } - public void destroyLocked() { throwIfDestroyedLocked(); mSpooler.destroy(); @@ -612,7 +601,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { } mActiveServices.clear(); mInstalledServices.clear(); - mEnabledServices.clear(); + mDisabledServices.clear(); if (mPrinterDiscoverySession != null) { mPrinterDiscoverySession.destroyLocked(); mPrinterDiscoverySession = null; @@ -646,12 +635,12 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { .append(installedService.getAdvancedOptionsActivityName()).println(); } - pw.append(prefix).append(tab).append("enabled services:").println(); - for (ComponentName enabledService : mEnabledServices) { - String enabledServicePrefix = prefix + tab + tab; - pw.append(enabledServicePrefix).append("service:").println(); - pw.append(enabledServicePrefix).append(tab).append("componentName=") - .append(enabledService.flattenToString()); + pw.append(prefix).append(tab).append("disabled services:").println(); + for (ComponentName disabledService : mDisabledServices) { + String disabledServicePrefix = prefix + tab + tab; + pw.append(disabledServicePrefix).append("service:").println(); + pw.append(disabledServicePrefix).append(tab).append("componentName=") + .append(disabledService.flattenToString()); pw.println(); } @@ -679,7 +668,7 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { private boolean readConfigurationLocked() { boolean somethingChanged = false; somethingChanged |= readInstalledPrintServicesLocked(); - somethingChanged |= readEnabledPrintServicesLocked(); + somethingChanged |= readDisabledPrintServicesLocked(); return somethingChanged; } @@ -742,13 +731,50 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { return false; } - private boolean readEnabledPrintServicesLocked() { - Set<ComponentName> tempEnabledServiceNameSet = new HashSet<ComponentName>(); - readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES, - tempEnabledServiceNameSet); - if (!tempEnabledServiceNameSet.equals(mEnabledServices)) { - mEnabledServices.clear(); - mEnabledServices.addAll(tempEnabledServiceNameSet); + /** + * Update persistent state from a previous version of Android. + */ + private void upgradePersistentStateIfNeeded() { + String enabledSettingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(), + Settings.Secure.ENABLED_PRINT_SERVICES, mUserId); + + // Pre N we store the enabled services, in N and later we store the disabled services. + // Hence if enabledSettingValue is still set, we need to upgrade. + if (enabledSettingValue != null) { + Set<ComponentName> enabledServiceNameSet = new HashSet<ComponentName>(); + readPrintServicesFromSettingLocked(Settings.Secure.ENABLED_PRINT_SERVICES, + enabledServiceNameSet); + + ArraySet<ComponentName> disabledServices = new ArraySet<>(); + final int numInstalledServices = mInstalledServices.size(); + for (int i = 0; i < numInstalledServices; i++) { + ComponentName serviceName = mInstalledServices.get(i).getComponentName(); + if (!enabledServiceNameSet.contains(serviceName)) { + disabledServices.add(serviceName); + } + } + + writeDisabledPrintServicesLocked(disabledServices); + + // We won't needed ENABLED_PRINT_SERVICES anymore, set to null to prevent upgrade to run + // again. + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.ENABLED_PRINT_SERVICES, null, mUserId); + } + } + + /** + * Read the set of disabled print services from the secure settings. + * + * @return true if the state changed. + */ + private boolean readDisabledPrintServicesLocked() { + Set<ComponentName> tempDisabledServiceNameSet = new HashSet<ComponentName>(); + readPrintServicesFromSettingLocked(Settings.Secure.DISABLED_PRINT_SERVICES, + tempDisabledServiceNameSet); + if (!tempDisabledServiceNameSet.equals(mDisabledServices)) { + mDisabledServices.clear(); + mDisabledServices.addAll(tempDisabledServiceNameSet); return true; } return false; @@ -774,70 +800,28 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { } } - private void enableSystemPrintServicesLocked() { - // Load enabled and installed services. - readEnabledPrintServicesLocked(); - readInstalledPrintServicesLocked(); - - // Load the system services once enabled on first boot. - Set<ComponentName> enabledOnFirstBoot = new HashSet<ComponentName>(); - readPrintServicesFromSettingLocked( - Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, - enabledOnFirstBoot); - + /** + * Persist the disabled print services to the secure settings. + */ + private void writeDisabledPrintServicesLocked(Set<ComponentName> disabledServices) { StringBuilder builder = new StringBuilder(); - - final int serviceCount = mInstalledServices.size(); - for (int i = 0; i < serviceCount; i++) { - ServiceInfo serviceInfo = mInstalledServices.get(i).getResolveInfo().serviceInfo; - // Enable system print services if we never did that and are not enabled. - if ((serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - ComponentName serviceName = new ComponentName( - serviceInfo.packageName, serviceInfo.name); - if (!mEnabledServices.contains(serviceName) - && !enabledOnFirstBoot.contains(serviceName)) { - if (builder.length() > 0) { - builder.append(":"); - } - builder.append(serviceName.flattenToString()); - } + for (ComponentName componentName : disabledServices) { + if (builder.length() > 0) { + builder.append(COMPONENT_NAME_SEPARATOR); } - } - - // Nothing to be enabled - done. - if (builder.length() <= 0) { - return; - } - - String servicesToEnable = builder.toString(); - - // Update the enabled services setting. - String enabledServices = Settings.Secure.getStringForUser( - mContext.getContentResolver(), Settings.Secure.ENABLED_PRINT_SERVICES, mUserId); - if (TextUtils.isEmpty(enabledServices)) { - enabledServices = servicesToEnable; - } else { - enabledServices = enabledServices + ":" + servicesToEnable; + builder.append(componentName.flattenToShortString()); } Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.ENABLED_PRINT_SERVICES, enabledServices, mUserId); - - // Update the enabled on first boot services setting. - String enabledOnFirstBootServices = Settings.Secure.getStringForUser( - mContext.getContentResolver(), - Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, mUserId); - if (TextUtils.isEmpty(enabledOnFirstBootServices)) { - enabledOnFirstBootServices = servicesToEnable; - } else { - enabledOnFirstBootServices = enabledOnFirstBootServices + ":" + enabledServices; - } - Settings.Secure.putStringForUser(mContext.getContentResolver(), - Settings.Secure.ENABLED_ON_FIRST_BOOT_SYSTEM_PRINT_SERVICES, - enabledOnFirstBootServices, mUserId); + Settings.Secure.DISABLED_PRINT_SERVICES, builder.toString(), mUserId); } - private void onConfigurationChangedLocked() { - Set<ComponentName> installedComponents = new ArraySet<ComponentName>(); + /** + * Get the {@link ComponentName names} of the installed print services + * + * @return The names of the installed print services + */ + private ArrayList<ComponentName> getInstalledComponents() { + ArrayList<ComponentName> installedComponents = new ArrayList<ComponentName>(); final int installedCount = mInstalledServices.size(); for (int i = 0; i < installedCount; i++) { @@ -846,8 +830,37 @@ final class UserState implements PrintSpoolerCallbacks, PrintServiceCallbacks { resolveInfo.serviceInfo.name); installedComponents.add(serviceName); + } + + return installedComponents; + } + + /** + * Prune persistent state if a print service was uninstalled + */ + public void prunePrintServices() { + synchronized (mLock) { + ArrayList<ComponentName> installedComponents = getInstalledComponents(); + + // Remove unnecessary entries from persistent state "disabled services" + boolean disabledServicesUninstalled = mDisabledServices.retainAll(installedComponents); + if (disabledServicesUninstalled) { + writeDisabledPrintServicesLocked(mDisabledServices); + } + + // Remove unnecessary entries from persistent state "approved services" + mSpooler.pruneApprovedPrintServices(installedComponents); + } + } + + private void onConfigurationChangedLocked() { + ArrayList<ComponentName> installedComponents = getInstalledComponents(); + + final int installedCount = installedComponents.size(); + for (int i = 0; i < installedCount; i++) { + ComponentName serviceName = installedComponents.get(i); - if (mEnabledServices.contains(serviceName)) { + if (!mDisabledServices.contains(serviceName)) { if (!mActiveServices.containsKey(serviceName)) { RemotePrintService service = new RemotePrintService( mContext, serviceName, mUserId, mSpooler, this); 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 568e1d543455..672058bca8d7 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -758,7 +758,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { when(mContext.userManager.getUserRestrictions()).thenReturn(new Bundle()); // Now call clear. - doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUid( + doReturn(DpmMockContext.CALLER_SYSTEM_USER_UID).when(mContext.packageManager).getPackageUidAsUser( eq(admin1.getPackageName()), anyInt()); dpm.clearDeviceOwnerApp(admin1.getPackageName()); @@ -797,7 +797,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.binder.callingUid = DpmMockContext.CALLER_UID; // Now call clear. - doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUid( + doReturn(DpmMockContext.CALLER_UID).when(mContext.packageManager).getPackageUidAsUser( eq(admin1.getPackageName()), anyInt()); try { @@ -951,7 +951,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { final int appRestrictionsManagerAppId = 20987; final int appRestrictionsManagerUid = UserHandle.getUid( DpmMockContext.CALLER_USER_HANDLE, appRestrictionsManagerAppId); - doReturn(appRestrictionsManagerUid).when(mContext.packageManager).getPackageUid( + doReturn(appRestrictionsManagerUid).when(mContext.packageManager).getPackageUidAsUser( eq(appRestrictionsManagerPackage), eq(DpmMockContext.CALLER_USER_HANDLE)); mContext.binder.callingUid = appRestrictionsManagerUid; @@ -1385,4 +1385,95 @@ public class DevicePolicyManagerTest extends DpmTestBase { dpm.reboot(admin1); } + + public void testSetGetSupportText() { + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + dpm.setActiveAdmin(admin1, true); + dpm.setActiveAdmin(admin2, true); + mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS); + + // Null default support messages. + { + assertNull(dpm.getLongSupportMessage(admin1)); + assertNull(dpm.getShortSupportMessage(admin1)); + mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + assertNull(dpm.getShortSupportMessageForUser(admin1, + DpmMockContext.CALLER_USER_HANDLE)); + assertNull(dpm.getLongSupportMessageForUser(admin1, + DpmMockContext.CALLER_USER_HANDLE)); + mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; + } + + // Only system can call the per user versions. + { + try { + dpm.getShortSupportMessageForUser(admin1, + DpmMockContext.CALLER_USER_HANDLE); + fail("Only system should be able to call getXXXForUser versions"); + } catch (SecurityException expected) { + MoreAsserts.assertContainsRegex("message for user", expected.getMessage()); + } + try { + dpm.getLongSupportMessageForUser(admin1, + DpmMockContext.CALLER_USER_HANDLE); + fail("Only system should be able to call getXXXForUser versions"); + } catch (SecurityException expected) { + MoreAsserts.assertContainsRegex("message for user", expected.getMessage()); + } + } + + // Can't set message for admin in another uid. + { + mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1; + try { + dpm.setShortSupportMessage(admin1, "Some text"); + fail("Admins should only be able to change their own support text."); + } catch (SecurityException expected) { + MoreAsserts.assertContainsRegex("is not owned by uid", expected.getMessage()); + } + mContext.binder.callingUid = DpmMockContext.CALLER_UID; + } + + // Set/Get short returns what it sets and other admins text isn't changed. + { + final String supportText = "Some text to test with."; + dpm.setShortSupportMessage(admin1, supportText); + assertEquals(supportText, dpm.getShortSupportMessage(admin1)); + assertNull(dpm.getLongSupportMessage(admin1)); + assertNull(dpm.getShortSupportMessage(admin2)); + + mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1, + DpmMockContext.CALLER_USER_HANDLE)); + assertNull(dpm.getShortSupportMessageForUser(admin2, + DpmMockContext.CALLER_USER_HANDLE)); + assertNull(dpm.getLongSupportMessageForUser(admin1, + DpmMockContext.CALLER_USER_HANDLE)); + mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; + + dpm.setShortSupportMessage(admin1, null); + assertNull(dpm.getShortSupportMessage(admin1)); + } + + // Set/Get long returns what it sets and other admins text isn't changed. + { + final String supportText = "Some text to test with.\nWith more text."; + dpm.setLongSupportMessage(admin1, supportText); + assertEquals(supportText, dpm.getLongSupportMessage(admin1)); + assertNull(dpm.getShortSupportMessage(admin1)); + assertNull(dpm.getLongSupportMessage(admin2)); + + mContext.binder.callingUid = DpmMockContext.SYSTEM_UID; + assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1, + DpmMockContext.CALLER_USER_HANDLE)); + assertNull(dpm.getLongSupportMessageForUser(admin2, + DpmMockContext.CALLER_USER_HANDLE)); + assertNull(dpm.getShortSupportMessageForUser(admin1, + DpmMockContext.CALLER_USER_HANDLE)); + mMockContext.binder.callingUid = DpmMockContext.CALLER_UID; + + dpm.setLongSupportMessage(admin1, null); + assertNull(dpm.getLongSupportMessage(admin1)); + } + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 5b33e4d4ca40..c557ab7e1e93 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -117,7 +117,7 @@ public abstract class DpmTestBase extends AndroidTestCase { // We need to rewrite the UID in the activity info. realResolveInfo.get(0).activityInfo.applicationInfo = ai; - doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers( + doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceiversAsUser( MockUtils.checkIntentComponent(admin), eq(PackageManager.GET_META_DATA | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 2b0919b7bfc0..98bccb06c99a 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -374,7 +374,7 @@ public class UsageStatsService extends SystemService implements for (int i = 0; i < userIds.length; i++) { final int userId = userIds[i]; List<PackageInfo> packages = - getContext().getPackageManager().getInstalledPackages( + getContext().getPackageManager().getInstalledPackagesAsUser( PackageManager.GET_DISABLED_COMPONENTS | PackageManager.GET_UNINSTALLED_PACKAGES, userId); @@ -614,9 +614,8 @@ public class UsageStatsService extends SystemService implements // the sync adapter is a system package. try { PackageInfo pi = AppGlobals.getPackageManager().getPackageInfo( - packageName, 0, userId); - if (pi == null || pi.applicationInfo == null - || !pi.applicationInfo.isSystemApp()) { + packageName, PackageManager.MATCH_SYSTEM_ONLY, userId); + if (pi == null || pi.applicationInfo == null) { continue; } if (!packageName.equals(providerPkgName)) { @@ -863,8 +862,8 @@ public class UsageStatsService extends SystemService implements List<ApplicationInfo> apps; try { - ParceledListSlice<ApplicationInfo> slice - = AppGlobals.getPackageManager().getInstalledApplications(0, userId); + ParceledListSlice<ApplicationInfo> slice = AppGlobals.getPackageManager() + .getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); if (slice == null) { return new int[0]; } @@ -1266,8 +1265,8 @@ public class UsageStatsService extends SystemService implements "No permission to change app idle state"); final long token = Binder.clearCallingIdentity(); try { - PackageInfo pi = AppGlobals.getPackageManager() - .getPackageInfo(packageName, 0, userId); + PackageInfo pi = AppGlobals.getPackageManager().getPackageInfo(packageName, + PackageManager.MATCH_UNINSTALLED_PACKAGES, userId); if (pi == null) return; UsageStatsService.this.setAppIdle(packageName, idle, userId); } catch (RemoteException re) { diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java index 5188e5fd1f7d..72621a422ce6 100644 --- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java @@ -148,7 +148,7 @@ class UserUsageStatsService { private void initializeDefaultsForApps(long currentTimeMillis, long deviceUsageTime, boolean firstUpdate) { PackageManager pm = mContext.getPackageManager(); - List<PackageInfo> packages = pm.getInstalledPackages(0, mUserId); + List<PackageInfo> packages = pm.getInstalledPackagesAsUser(0, mUserId); final int packageCount = packages.size(); for (int i = 0; i < packageCount; i++) { final PackageInfo pi = packages.get(i); diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java index c734fabe2624..35a04644c836 100644 --- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java +++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java @@ -858,7 +858,7 @@ public class UsbDeviceManager { .setOngoing(true) .setTicker(title) .setDefaults(0) // please be quiet - .setPriority(Notification.PRIORITY_LOW) + .setPriority(Notification.PRIORITY_DEFAULT) .setColor(mContext.getColor( com.android.internal.R.color.system_notification_accent_color)) .setContentTitle(title) diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 0b5aaa3b273b..913cb18c6ab7 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -24,6 +24,7 @@ import android.app.ActivityThread; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.os.Bundle; @@ -31,6 +32,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemProperties; import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; import android.util.Log; import com.android.internal.telecom.ITelecomService; @@ -4865,4 +4867,43 @@ public class TelephonyManager { } return null; } + + /** + * Returns the URI for the per-account voicemail ringtone set in Phone settings. + * + * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the + * voicemail ringtone. + * @return The URI for the ringtone to play when receiving a voicemail from a specific + * PhoneAccount. + */ + public Uri getVoicemailRingtoneUri(PhoneAccountHandle accountHandle) { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.getVoicemailRingtoneUri(accountHandle); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#getVoicemailRingtoneUri", e); + } + return null; + } + + /** + * Returns whether vibration is set for voicemail notification in Phone settings. + * + * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the + * voicemail vibration setting. + * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise. + */ + public boolean isVoicemailVibrationEnabled(PhoneAccountHandle accountHandle) { + try { + ITelephony service = getITelephony(); + if (service != null) { + return service.isVoicemailVibrationEnabled(accountHandle); + } + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#isVoicemailVibrationEnabled", e); + } + return false; + } } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 8172e94c9c90..d1badc9e7f33 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -18,7 +18,9 @@ package com.android.internal.telephony; import android.content.Intent; import android.os.Bundle; +import android.net.Uri; import android.telecom.PhoneAccount; +import android.telecom.PhoneAccountHandle; import android.telephony.CellInfo; import android.telephony.IccOpenLogicalChannelResponse; import android.telephony.ModemActivityInfo; @@ -966,7 +968,7 @@ interface ITelephony { * Returns the Status of Wi-Fi Calling */ boolean isWifiCallingAvailable(); - + /** * Returns the Status of Volte */ @@ -1014,4 +1016,23 @@ interface ITelephony { * @return Service state on specified subscription. */ ServiceState getServiceStateForSubscriber(int subId, String callingPackage); + + /** + * Returns the URI for the per-account voicemail ringtone set in Phone settings. + * + * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the + * voicemail ringtone. + * @return The URI for the ringtone to play when receiving a voicemail from a specific + * PhoneAccount. + */ + Uri getVoicemailRingtoneUri(in PhoneAccountHandle accountHandle); + + /** + * Returns whether vibration is set for voicemail notification in Phone settings. + * + * @param accountHandle The handle for the {@link PhoneAccount} for which to retrieve the + * voicemail vibration setting. + * @return {@code true} if the vibration is set for this PhoneAccount, {@code false} otherwise. + */ + boolean isVoicemailVibrationEnabled(in PhoneAccountHandle accountHandle); } diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index 2cef1b3273a9..5381e4ef6bf9 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -96,14 +96,30 @@ public class MockPackageManager extends PackageManager { } @Override - public int[] getPackageGids(String packageName) throws NameNotFoundException { throw new UnsupportedOperationException(); } + @Override + public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + + @Override + public int getPackageUid(String packageName, int flags) throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + /** @hide */ @Override - public int getPackageUid(String packageName, int userHandle) + public int getPackageUidAsUser(String packageName, int flags, int userHandle) + throws NameNotFoundException { + throw new UnsupportedOperationException(); + } + + /** @hide */ + @Override + public int getPackageUidAsUser(String packageName, int userHandle) throws NameNotFoundException { throw new UnsupportedOperationException(); } @@ -174,7 +190,7 @@ public class MockPackageManager extends PackageManager { /** @hide */ @Override - public List<PackageInfo> getInstalledPackages(int flags, int userId) { + public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) { throw new UnsupportedOperationException(); } @@ -355,7 +371,7 @@ public class MockPackageManager extends PackageManager { /** @hide */ @Override - public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) { + public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) { throw new UnsupportedOperationException(); } @@ -746,7 +762,7 @@ public class MockPackageManager extends PackageManager { * @hide - to match hiding in superclass */ @Override - public void getPackageSizeInfo(String packageName, int userHandle, + public void getPackageSizeInfoAsUser(String packageName, int userHandle, IPackageStatsObserver observer) { throw new UnsupportedOperationException(); } @@ -890,7 +906,7 @@ public class MockPackageManager extends PackageManager { * @hide */ @Override - public int getIntentVerificationStatus(String packageName, int userId) { + public int getIntentVerificationStatusAsUser(String packageName, int userId) { throw new UnsupportedOperationException(); } @@ -898,7 +914,7 @@ public class MockPackageManager extends PackageManager { * @hide */ @Override - public boolean updateIntentVerificationStatus(String packageName, int status, int userId) { + public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) { throw new UnsupportedOperationException(); } @@ -915,16 +931,30 @@ public class MockPackageManager extends PackageManager { throw new UnsupportedOperationException(); } - @Override + /** {@removed} */ + @Deprecated public String getDefaultBrowserPackageName(int userId) { throw new UnsupportedOperationException(); } + /** {@hide} */ @Override + public String getDefaultBrowserPackageNameAsUser(int userId) { + throw new UnsupportedOperationException(); + } + + /** {@removed} */ + @Deprecated public boolean setDefaultBrowserPackageName(String packageName, int userId) { throw new UnsupportedOperationException(); } + /** {@hide} */ + @Override + public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) { + throw new UnsupportedOperationException(); + } + /** * @hide */ diff --git a/tests/RenderScriptTests/Android.mk b/tests/RenderScriptTests/Android.mk deleted file mode 100644 index 5053e7d64389..000000000000 --- a/tests/RenderScriptTests/Android.mk +++ /dev/null @@ -1 +0,0 @@ -include $(call all-subdir-makefiles) diff --git a/tests/RenderScriptTests/FBOTest/Android.mk b/tests/RenderScriptTests/FBOTest/Android.mk deleted file mode 100644 index 7a578d9e4be8..000000000000 --- a/tests/RenderScriptTests/FBOTest/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2008 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_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - -LOCAL_PACKAGE_NAME := FBOTest - -LOCAL_SDK_VERSION := 17 - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/FBOTest/AndroidManifest.xml b/tests/RenderScriptTests/FBOTest/AndroidManifest.xml deleted file mode 100644 index 788e8560b65a..000000000000 --- a/tests/RenderScriptTests/FBOTest/AndroidManifest.xml +++ /dev/null @@ -1,22 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.fbotest"> - <application android:label="_FBOTest"> - <activity android:name="FBOTest" - android:label="FBO Base Test" - android:theme="@android:style/Theme.Black.NoTitleBar"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - <activity android:name="FBOSync" - android:label="FBO Sync Test" - android:theme="@android:style/Theme.Black.NoTitleBar"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/FBOTest/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/FBOTest/res/drawable-nodpi/robot.png Binary files differdeleted file mode 100644 index f7353fd61c5b..000000000000 --- a/tests/RenderScriptTests/FBOTest/res/drawable-nodpi/robot.png +++ /dev/null diff --git a/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d b/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d Binary files differdeleted file mode 100644 index f48895cd8451..000000000000 --- a/tests/RenderScriptTests/FBOTest/res/raw/robot.a3d +++ /dev/null diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java deleted file mode 100644 index d30ad7e7c8eb..000000000000 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSync.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2011 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.fbotest; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.content.res.Configuration; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings.System; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.MenuInflater; -import android.view.Window; -import android.widget.Button; -import android.widget.ListView; -import android.net.Uri; - -import java.lang.Runtime; - -public class FBOSync extends Activity { - - private FBOSyncView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new FBOSyncView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onPause(); - mView.pause(); - } -} - diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java deleted file mode 100644 index 57a117cc9ccd..000000000000 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncRS.java +++ /dev/null @@ -1,213 +0,0 @@ -/* - * Copyright (C) 2011 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.fbotest; - -import java.io.Writer; - -import android.content.res.Resources; -import android.renderscript.*; -import android.renderscript.Element.DataType; -import android.renderscript.Element.DataKind; -import android.renderscript.ProgramStore.DepthFunc; -import android.renderscript.Type.Builder; -import android.util.Log; - - -public class FBOSyncRS { - - public FBOSyncRS() { - } - - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initRS(); - } - - public void surfaceChanged() { - mRS.getWidth(); - mRS.getHeight(); - } - - private Resources mRes; - private RenderScriptGL mRS; - private Sampler mSampler; - private ProgramStore mPSBackground; - private ProgramFragment mPFBackground; - private ProgramVertex mPVBackground; - private ProgramVertexFixedFunction.Constants mPVA; - - private Allocation mGridImage; - private Allocation mOffscreen; - private Allocation mOffscreenDepth; - private Allocation mAllocPV; - private Allocation mReadBackTest; - - private Font mItalic; - private Allocation mTextAlloc; - - private ScriptField_MeshInfo mMeshes; - private ScriptC_fbosync mScript; - - - public void onActionDown(float x, float y) { - mScript.invoke_onActionDown(x, y); - } - - public void onActionScale(float scale) { - mScript.invoke_onActionScale(scale); - } - - public void onActionMove(float x, float y) { - mScript.invoke_onActionMove(x, y); - } - - private void initPFS() { - ProgramStore.Builder b = new ProgramStore.Builder(mRS); - - b.setDepthFunc(ProgramStore.DepthFunc.LESS); - b.setDitherEnabled(false); - b.setDepthMaskEnabled(true); - mPSBackground = b.create(); - - mScript.set_gPFSBackground(mPSBackground); - } - - private void initPF() { - Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMinification(Sampler.Value.LINEAR); - bs.setMagnification(Sampler.Value.LINEAR); - bs.setWrapS(Sampler.Value.CLAMP); - bs.setWrapT(Sampler.Value.CLAMP); - mSampler = bs.create(); - - ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); - b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mPFBackground = b.create(); - mPFBackground.bindSampler(mSampler, 0); - - mScript.set_gPFBackground(mPFBackground); - } - - private void initPV() { - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - mPVBackground = pvb.create(); - - mPVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA); - - mScript.set_gPVBackground(mPVBackground); - } - - private void loadImage() { - mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - mScript.set_gTGrid(mGridImage); - } - - private void initTextAllocation(String fileName) { - String allocString = "Displaying file: " + fileName; - mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT); - mScript.set_gTextAlloc(mTextAlloc); - } - - private void initMeshes(FileA3D model) { - int numEntries = model.getIndexEntryCount(); - int numMeshes = 0; - for (int i = 0; i < numEntries; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - numMeshes ++; - } - } - - if (numMeshes > 0) { - mMeshes = new ScriptField_MeshInfo(mRS, numMeshes); - - for (int i = 0; i < numEntries; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - Mesh mesh = entry.getMesh(); - mMeshes.set_mMesh(i, mesh, false); - mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false); - } - } - mMeshes.copyAll(); - } else { - throw new RSRuntimeException("No valid meshes in file"); - } - - mScript.bind_gMeshes(mMeshes); - mScript.invoke_updateMeshInfo(); - } - - public void loadA3DFile(String path) { - FileA3D model = FileA3D.createFromFile(mRS, path); - initMeshes(model); - initTextAllocation(path); - } - - private void initRS() { - - mScript = new ScriptC_fbosync(mRS, mRes, R.raw.fbosync); - - initPFS(); - initPF(); - initPV(); - - loadImage(); - - Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS)); - b.setX(512).setY(512); - mOffscreen = Allocation.createTyped(mRS, - b.create(), - Allocation.USAGE_SCRIPT | - Allocation.USAGE_GRAPHICS_TEXTURE | - Allocation.USAGE_GRAPHICS_RENDER_TARGET); - mScript.set_gOffscreen(mOffscreen); - - mReadBackTest = Allocation.createTyped(mRS, - b.create(), - Allocation.USAGE_SCRIPT | - Allocation.USAGE_GRAPHICS_TEXTURE); - mScript.set_gReadBackTest(mReadBackTest); - - b = new Type.Builder(mRS, - Element.createPixel(mRS, DataType.UNSIGNED_16, - DataKind.PIXEL_DEPTH)); - b.setX(512).setY(512); - mOffscreenDepth = Allocation.createTyped(mRS, - b.create(), - Allocation.USAGE_GRAPHICS_RENDER_TARGET); - mScript.set_gOffscreenDepth(mOffscreenDepth); - - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); - initMeshes(model); - - mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); - mScript.set_gItalic(mItalic); - - initTextAllocation("R.raw.robot"); - - mRS.bindRootScript(mScript); - } -} - - - diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java deleted file mode 100644 index 6a856284cbec..000000000000 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOSyncView.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2011 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.fbotest; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.view.MotionEvent; -import android.view.SurfaceHolder; -import android.view.ScaleGestureDetector; -import android.util.Log; - -public class FBOSyncView extends RSSurfaceView { - - private RenderScriptGL mRS; - private FBOSyncRS mRender; - - private ScaleGestureDetector mScaleDetector; - - private static final int INVALID_POINTER_ID = -1; - private int mActivePointerId = INVALID_POINTER_ID; - - public FBOSyncView(Context context) { - super(context); - ensureRenderScript(); - mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); - } - - private void ensureRenderScript() { - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - mRS = createRenderScriptGL(sc); - mRender = new FBOSyncRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ensureRenderScript(); - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - mRender.surfaceChanged(); - } - - @Override - protected void onDetachedFromWindow() { - mRender = null; - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - public void loadA3DFile(String path) { - mRender.loadA3DFile(path); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - mScaleDetector.onTouchEvent(ev); - - boolean ret = false; - float x = ev.getX(); - float y = ev.getY(); - - final int action = ev.getAction(); - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(0); - ret = true; - break; - } - case MotionEvent.ACTION_MOVE: { - if (!mScaleDetector.isInProgress()) { - mRender.onActionMove(x, y); - } - mRender.onActionDown(x, y); - ret = true; - break; - } - - case MotionEvent.ACTION_UP: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_CANCEL: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_POINTER_UP: { - final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - final int pointerId = ev.getPointerId(pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - x = ev.getX(newPointerIndex); - y = ev.getY(newPointerIndex); - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(newPointerIndex); - } - break; - } - } - - return ret; - } - - private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - @Override - public boolean onScale(ScaleGestureDetector detector) { - mRender.onActionScale(detector.getScaleFactor()); - return true; - } - } -} - - diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java deleted file mode 100644 index 72aa3eaed5ae..000000000000 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTest.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2008 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.fbotest; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.content.res.Configuration; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings.System; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.MenuInflater; -import android.view.Window; -import android.widget.Button; -import android.widget.ListView; -import android.net.Uri; - -import java.lang.Runtime; - -public class FBOTest extends Activity { - - private FBOTestView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new FBOTestView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onPause(); - mView.pause(); - } -} - diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java deleted file mode 100644 index 9e30c4b561ca..000000000000 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestRS.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2011 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.fbotest; - -import java.io.Writer; - -import android.content.res.Resources; -import android.renderscript.*; -import android.renderscript.Element.DataType; -import android.renderscript.Element.DataKind; -import android.renderscript.ProgramStore.DepthFunc; -import android.renderscript.Type.Builder; -import android.util.Log; - - -public class FBOTestRS { - - public FBOTestRS() { - } - - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initRS(); - } - - public void surfaceChanged() { - mRS.getWidth(); - mRS.getHeight(); - } - - private Resources mRes; - private RenderScriptGL mRS; - private Sampler mSampler; - private ProgramStore mPSBackground; - private ProgramFragment mPFBackground; - private ProgramVertex mPVBackground; - private ProgramVertexFixedFunction.Constants mPVA; - - private Allocation mGridImage; - private Allocation mOffscreen; - private Allocation mOffscreenDepth; - private Allocation mAllocPV; - - private Font mItalic; - private Allocation mTextAlloc; - - private ScriptField_MeshInfo mMeshes; - private ScriptC_fbotest mScript; - - - public void onActionDown(float x, float y) { - mScript.invoke_onActionDown(x, y); - } - - public void onActionScale(float scale) { - mScript.invoke_onActionScale(scale); - } - - public void onActionMove(float x, float y) { - mScript.invoke_onActionMove(x, y); - } - - private void initPFS() { - ProgramStore.Builder b = new ProgramStore.Builder(mRS); - - b.setDepthFunc(ProgramStore.DepthFunc.LESS); - b.setDitherEnabled(false); - b.setDepthMaskEnabled(true); - mPSBackground = b.create(); - - mScript.set_gPFSBackground(mPSBackground); - } - - private void initPF() { - Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMinification(Sampler.Value.LINEAR); - bs.setMagnification(Sampler.Value.LINEAR); - bs.setWrapS(Sampler.Value.CLAMP); - bs.setWrapT(Sampler.Value.CLAMP); - mSampler = bs.create(); - - ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); - b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mPFBackground = b.create(); - mPFBackground.bindSampler(mSampler, 0); - - mScript.set_gPFBackground(mPFBackground); - } - - private void initPV() { - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - mPVBackground = pvb.create(); - - mPVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA); - - mScript.set_gPVBackground(mPVBackground); - } - - private void loadImage() { - mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - mScript.set_gTGrid(mGridImage); - } - - private void initTextAllocation(String fileName) { - String allocString = "Displaying file: " + fileName; - mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT); - mScript.set_gTextAlloc(mTextAlloc); - } - - private void initMeshes(FileA3D model) { - int numEntries = model.getIndexEntryCount(); - int numMeshes = 0; - for (int i = 0; i < numEntries; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - numMeshes ++; - } - } - - if (numMeshes > 0) { - mMeshes = new ScriptField_MeshInfo(mRS, numMeshes); - - for (int i = 0; i < numEntries; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - Mesh mesh = entry.getMesh(); - mMeshes.set_mMesh(i, mesh, false); - mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false); - } - } - mMeshes.copyAll(); - } else { - throw new RSRuntimeException("No valid meshes in file"); - } - - mScript.bind_gMeshes(mMeshes); - mScript.invoke_updateMeshInfo(); - } - - public void loadA3DFile(String path) { - FileA3D model = FileA3D.createFromFile(mRS, path); - initMeshes(model); - initTextAllocation(path); - } - - private void initRS() { - - mScript = new ScriptC_fbotest(mRS, mRes, R.raw.fbotest); - - initPFS(); - initPF(); - initPV(); - - loadImage(); - - Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS)); - b.setX(512).setY(512); - mOffscreen = Allocation.createTyped(mRS, - b.create(), - Allocation.USAGE_GRAPHICS_TEXTURE | - Allocation.USAGE_GRAPHICS_RENDER_TARGET); - mScript.set_gOffscreen(mOffscreen); - - b = new Type.Builder(mRS, - Element.createPixel(mRS, DataType.UNSIGNED_16, - DataKind.PIXEL_DEPTH)); - b.setX(512).setY(512); - mOffscreenDepth = Allocation.createTyped(mRS, - b.create(), - Allocation.USAGE_GRAPHICS_RENDER_TARGET); - mScript.set_gOffscreenDepth(mOffscreenDepth); - - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); - initMeshes(model); - - mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); - mScript.set_gItalic(mItalic); - - initTextAllocation("R.raw.robot"); - - mRS.bindRootScript(mScript); - } -} - - - diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java deleted file mode 100644 index c9598ee864c0..000000000000 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/FBOTestView.java +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Copyright (C) 2011 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.fbotest; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.view.MotionEvent; -import android.view.SurfaceHolder; -import android.view.ScaleGestureDetector; -import android.util.Log; - -public class FBOTestView extends RSSurfaceView { - - private RenderScriptGL mRS; - private FBOTestRS mRender; - - private ScaleGestureDetector mScaleDetector; - - private static final int INVALID_POINTER_ID = -1; - private int mActivePointerId = INVALID_POINTER_ID; - - public FBOTestView(Context context) { - super(context); - ensureRenderScript(); - mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); - } - - private void ensureRenderScript() { - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - mRS = createRenderScriptGL(sc); - mRender = new FBOTestRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ensureRenderScript(); - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - mRender.surfaceChanged(); - } - - @Override - protected void onDetachedFromWindow() { - mRender = null; - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - public void loadA3DFile(String path) { - mRender.loadA3DFile(path); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - mScaleDetector.onTouchEvent(ev); - - boolean ret = false; - float x = ev.getX(); - float y = ev.getY(); - - final int action = ev.getAction(); - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(0); - ret = true; - break; - } - case MotionEvent.ACTION_MOVE: { - if (!mScaleDetector.isInProgress()) { - mRender.onActionMove(x, y); - } - mRender.onActionDown(x, y); - ret = true; - break; - } - - case MotionEvent.ACTION_UP: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_CANCEL: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_POINTER_UP: { - final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - final int pointerId = ev.getPointerId(pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - x = ev.getX(newPointerIndex); - y = ev.getY(newPointerIndex); - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(newPointerIndex); - } - break; - } - } - - return ret; - } - - private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - @Override - public boolean onScale(ScaleGestureDetector detector) { - mRender.onActionScale(detector.getScaleFactor()); - return true; - } - } -} - - diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs deleted file mode 100644 index 0c177efd06bd..000000000000 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbosync.rs +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.fbotest) - -#include "rs_graphics.rsh" - -rs_program_vertex gPVBackground; -rs_program_fragment gPFBackground; - -rs_allocation gTGrid; - -rs_program_store gPFSBackground; - -rs_font gItalic; -rs_allocation gTextAlloc; - -rs_allocation gOffscreen; -rs_allocation gOffscreenDepth; -rs_allocation gReadBackTest; - -typedef struct MeshInfo { - rs_mesh mMesh; - int mNumIndexSets; - float3 bBoxMin; - float3 bBoxMax; -} MeshInfo_t; - -MeshInfo_t *gMeshes; - -static float3 gLookAt; - -static float gRotateX; -static float gRotateY; -static float gZoom; - -static float gLastX; -static float gLastY; - -void onActionDown(float x, float y) { - gLastX = x; - gLastY = y; -} - -void onActionScale(float scale) { - - gZoom *= 1.0f / scale; - gZoom = max(0.1f, min(gZoom, 500.0f)); -} - -void onActionMove(float x, float y) { - float dx = gLastX - x; - float dy = gLastY - y; - - if (fabs(dy) <= 2.0f) { - dy = 0.0f; - } - if (fabs(dx) <= 2.0f) { - dx = 0.0f; - } - - gRotateY -= dx; - if (gRotateY > 360) { - gRotateY -= 360; - } - if (gRotateY < 0) { - gRotateY += 360; - } - - gRotateX -= dy; - gRotateX = min(gRotateX, 80.0f); - gRotateX = max(gRotateX, -80.0f); - - gLastX = x; - gLastY = y; -} - -void init() { - gRotateX = 0.0f; - gRotateY = 0.0f; - gZoom = 50.0f; - gLookAt = 0.0f; -} - -void updateMeshInfo() { - rs_allocation allMeshes = rsGetAllocation(gMeshes); - int size = rsAllocationGetDimX(allMeshes); - gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; - for (int i = 0; i < size; i++) { - MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); - rsgMeshComputeBoundingBox(info->mMesh, - &minX, &minY, &minZ, - &maxX, &maxY, &maxZ); - info->bBoxMin = (float3){minX, minY, minZ}; - info->bBoxMax = (float3){maxX, maxY, maxZ}; - gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f; - } - gLookAt = gLookAt / (float)size; -} - -static void renderAllMeshes() { - rs_allocation allMeshes = rsGetAllocation(gMeshes); - int size = rsAllocationGetDimX(allMeshes); - gLookAt = 0.0f; - for (int i = 0; i < size; i++) { - MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); - rsgDrawMesh(info->mMesh); - } -} - -static void drawDescription() { - uint height = rsgGetHeight(); - int left = 0, right = 0, top = 0, bottom = 0; - - rsgBindFont(gItalic); - - rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom); - rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom); -} - -static void renderOffscreen(bool useDepth) { - - rsgBindColorTarget(gOffscreen, 0); - if (useDepth) { - rsgBindDepthTarget(gOffscreenDepth); - rsgClearDepth(1.0f); - } else { - rsgClearDepthTarget(); - } - rsgClearColor(0.8f, 0.0f, 0.0f, 1.0f); - - rsgBindProgramVertex(gPVBackground); - rs_matrix4x4 proj; - float aspect = (float)rsAllocationGetDimX(gOffscreen) / (float)rsAllocationGetDimY(gOffscreen); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rsgBindProgramFragment(gPFBackground); - rsgBindProgramStore(gPFSBackground); - rsgBindTexture(gPFBackground, 0, gTGrid); - - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - // Position our models on the screen - rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom); - rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - rsgProgramVertexLoadModelMatrix(&matrix); - - renderAllMeshes(); - - // Render into the frambuffer - rsgClearAllRenderTargets(); -} - -static void drawOffscreenResult(int posX, int posY, rs_allocation texture) { - // display the result - rs_matrix4x4 proj, matrix; - rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500); - rsgProgramVertexLoadProjectionMatrix(&proj); - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - rsgBindTexture(gPFBackground, 0, texture); - float startX = posX, startY = posY; - float width = 256, height = 256; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 1, - startX, startY + height, 0, 0, 0, - startX + width, startY + height, 0, 1, 0, - startX + width, startY, 0, 1, 1); -} - -int root(void) { - - rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgClearDepth(1.0f); - - renderOffscreen(true); - drawOffscreenResult(0, 0, gOffscreen); - - - uint32_t w = rsAllocationGetDimX(gOffscreen); - uint32_t h = rsAllocationGetDimY(gOffscreen); - - rsgAllocationSyncAll(gOffscreen, RS_ALLOCATION_USAGE_GRAPHICS_RENDER_TARGET); - - rsAllocationCopy2DRange(gReadBackTest, 0, 0, 0, - RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X, w, h, - gOffscreen, 0, 0, 0, RS_ALLOCATION_CUBEMAP_FACE_POSITIVE_X); - - rsgAllocationSyncAll(gReadBackTest); - drawOffscreenResult(0, 300, gReadBackTest); - - rsgBindProgramVertex(gPVBackground); - rs_matrix4x4 proj; - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rsgBindProgramFragment(gPFBackground); - rsgBindProgramStore(gPFSBackground); - rsgBindTexture(gPFBackground, 0, gTGrid); - - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - // Position our models on the screen - rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom); - rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - rsgProgramVertexLoadModelMatrix(&matrix); - - renderAllMeshes(); - - drawDescription(); - - return 0; -} diff --git a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs b/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs deleted file mode 100644 index 13a3c85a381d..000000000000 --- a/tests/RenderScriptTests/FBOTest/src/com/android/fbotest/fbotest.rs +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.fbotest) - -#include "rs_graphics.rsh" - -rs_program_vertex gPVBackground; -rs_program_fragment gPFBackground; - -rs_allocation gTGrid; - -rs_program_store gPFSBackground; - -rs_font gItalic; -rs_allocation gTextAlloc; - -rs_allocation gOffscreen; -rs_allocation gOffscreenDepth; - -typedef struct MeshInfo { - rs_mesh mMesh; - int mNumIndexSets; - float3 bBoxMin; - float3 bBoxMax; -} MeshInfo_t; - -MeshInfo_t *gMeshes; - -static float3 gLookAt; - -static float gRotateX; -static float gRotateY; -static float gZoom; - -static float gLastX; -static float gLastY; - -void onActionDown(float x, float y) { - gLastX = x; - gLastY = y; -} - -void onActionScale(float scale) { - - gZoom *= 1.0f / scale; - gZoom = max(0.1f, min(gZoom, 500.0f)); -} - -void onActionMove(float x, float y) { - float dx = gLastX - x; - float dy = gLastY - y; - - if (fabs(dy) <= 2.0f) { - dy = 0.0f; - } - if (fabs(dx) <= 2.0f) { - dx = 0.0f; - } - - gRotateY -= dx; - if (gRotateY > 360) { - gRotateY -= 360; - } - if (gRotateY < 0) { - gRotateY += 360; - } - - gRotateX -= dy; - gRotateX = min(gRotateX, 80.0f); - gRotateX = max(gRotateX, -80.0f); - - gLastX = x; - gLastY = y; -} - -void init() { - gRotateX = 0.0f; - gRotateY = 0.0f; - gZoom = 50.0f; - gLookAt = 0.0f; -} - -void updateMeshInfo() { - rs_allocation allMeshes = rsGetAllocation(gMeshes); - int size = rsAllocationGetDimX(allMeshes); - gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; - for (int i = 0; i < size; i++) { - MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); - rsgMeshComputeBoundingBox(info->mMesh, - &minX, &minY, &minZ, - &maxX, &maxY, &maxZ); - info->bBoxMin = (float3){minX, minY, minZ}; - info->bBoxMax = (float3){maxX, maxY, maxZ}; - gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f; - } - gLookAt = gLookAt / (float)size; -} - -static void renderAllMeshes() { - rs_allocation allMeshes = rsGetAllocation(gMeshes); - int size = rsAllocationGetDimX(allMeshes); - gLookAt = 0.0f; - for (int i = 0; i < size; i++) { - MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); - rsgDrawMesh(info->mMesh); - } -} - -static void drawDescription() { - uint height = rsgGetHeight(); - int left = 0, right = 0, top = 0, bottom = 0; - - rsgBindFont(gItalic); - - rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom); - rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom); -} - -static void renderOffscreen(bool useDepth) { - - rsgBindColorTarget(gOffscreen, 0); - if (useDepth) { - rsgBindDepthTarget(gOffscreenDepth); - rsgClearDepth(1.0f); - } else { - rsgClearDepthTarget(); - } - rsgClearColor(0.8f, 0.8f, 0.8f, 1.0f); - - rsgBindProgramVertex(gPVBackground); - rs_matrix4x4 proj; - float aspect = (float)rsAllocationGetDimX(gOffscreen) / (float)rsAllocationGetDimY(gOffscreen); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rsgBindProgramFragment(gPFBackground); - rsgBindProgramStore(gPFSBackground); - rsgBindTexture(gPFBackground, 0, gTGrid); - - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - // Position our models on the screen - rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom); - rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - rsgProgramVertexLoadModelMatrix(&matrix); - - renderAllMeshes(); - - // Render into the frambuffer - rsgClearAllRenderTargets(); -} - -static void drawOffscreenResult(int posX, int posY) { - // display the result - rs_matrix4x4 proj, matrix; - rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500); - rsgProgramVertexLoadProjectionMatrix(&proj); - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - rsgBindTexture(gPFBackground, 0, gOffscreen); - float startX = posX, startY = posY; - float width = 256, height = 256; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 1, - startX, startY + height, 0, 0, 0, - startX + width, startY + height, 0, 1, 0, - startX + width, startY, 0, 1, 1); -} - -int root(void) { - - rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgClearDepth(1.0f); - - renderOffscreen(true); - drawOffscreenResult(0, 0); - - renderOffscreen(false); - drawOffscreenResult(0, 256); - - rsgBindProgramVertex(gPVBackground); - rs_matrix4x4 proj; - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rsgBindProgramFragment(gPFBackground); - rsgBindProgramStore(gPFSBackground); - rsgBindTexture(gPFBackground, 0, gTGrid); - - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - // Position our models on the screen - rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom); - rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - rsgProgramVertexLoadModelMatrix(&matrix); - - renderAllMeshes(); - - drawDescription(); - - return 0; -} diff --git a/tests/RenderScriptTests/HelloWorld/Android.mk b/tests/RenderScriptTests/HelloWorld/Android.mk deleted file mode 100644 index c1c08ec18f33..000000000000 --- a/tests/RenderScriptTests/HelloWorld/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2011 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_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - -LOCAL_PACKAGE_NAME := RsHelloWorld - -LOCAL_SDK_VERSION := 17 - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml b/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml deleted file mode 100644 index 1d37dc980ccf..000000000000 --- a/tests/RenderScriptTests/HelloWorld/AndroidManifest.xml +++ /dev/null @@ -1,31 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.android.rs.helloworld"> - <uses-sdk android:minSdkVersion="11" /> - <application android:label="RsHelloWorld" - android:icon="@drawable/test_pattern"> - <activity android:name="HelloWorld" - android:label="RsHelloWorld" - android:theme="@android:style/Theme.Black.NoTitleBar"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/HelloWorld/_index.html b/tests/RenderScriptTests/HelloWorld/_index.html deleted file mode 100644 index 4cab73817684..000000000000 --- a/tests/RenderScriptTests/HelloWorld/_index.html +++ /dev/null @@ -1 +0,0 @@ -<p>A Renderscript graphics application that draws the text "Hello, World!" where the user touches.</p>
\ No newline at end of file diff --git a/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png b/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png Binary files differdeleted file mode 100644 index e7d145554c00..000000000000 --- a/tests/RenderScriptTests/HelloWorld/res/drawable/test_pattern.png +++ /dev/null diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java deleted file mode 100644 index 9b1697b2cf27..000000000000 --- a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorld.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2011 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.example.android.rs.helloworld; - -import android.app.Activity; -import android.os.Bundle; - -// Renderscript activity -public class HelloWorld extends Activity { - - // Custom view to use with RenderScript - private HelloWorldView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our view and set it as the content of our Activity - mView = new HelloWorldView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - // Ideally an app should implement onResume() and onPause() - // to take appropriate action when the activity loses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally an app should implement onResume() and onPause() - // to take appropriate action when the activity loses focus - super.onPause(); - mView.pause(); - } - -} - diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java deleted file mode 100644 index 431641173b0c..000000000000 --- a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldRS.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (C) 2011 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.example.android.rs.helloworld; - -import android.content.res.Resources; -import android.renderscript.*; - -// This is the renderer for the HelloWorldView -public class HelloWorldRS { - private Resources mRes; - private RenderScriptGL mRS; - - private ScriptC_helloworld mScript; - - public HelloWorldRS() { - } - - // This provides us with the renderscript context and resources that - // allow us to create the script that does rendering - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initRS(); - } - - public void onActionDown(int x, int y) { - mScript.set_gTouchX(x); - mScript.set_gTouchY(y); - } - - private void initRS() { - mScript = new ScriptC_helloworld(mRS, mRes, R.raw.helloworld); - mRS.bindRootScript(mScript); - } -} - - - diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java deleted file mode 100644 index 557ebc5a418f..000000000000 --- a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/HelloWorldView.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2011 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.example.android.rs.helloworld; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.view.MotionEvent; - -public class HelloWorldView extends RSSurfaceView { - // Renderscipt context - private RenderScriptGL mRS; - // Script that does the rendering - private HelloWorldRS mRender; - - public HelloWorldView(Context context) { - super(context); - ensureRenderScript(); - } - - private void ensureRenderScript() { - if (mRS == null) { - // Initialize renderscript with desired surface characteristics. - // In this case, just use the defaults - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - mRS = createRenderScriptGL(sc); - // Create an instance of the script that does the rendering - mRender = new HelloWorldRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ensureRenderScript(); - } - - @Override - protected void onDetachedFromWindow() { - // Handle the system event and clean up - mRender = null; - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - // Pass touch events from the system to the rendering script - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mRender.onActionDown((int)ev.getX(), (int)ev.getY()); - return true; - } - - return false; - } -} - - diff --git a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs b/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs deleted file mode 100644 index bcf624e20055..000000000000 --- a/tests/RenderScriptTests/HelloWorld/src/com/example/android/rs/helloworld/helloworld.rs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -// Tell which java package name the reflected files should belong to -#pragma rs java_package_name(com.example.android.rs.helloworld) - -// Built-in header with graphics API's -#include "rs_graphics.rsh" - -// gTouchX and gTouchY are variables that will be reflected for use -// by the java API. We can use them to notify the script of touch events. -int gTouchX; -int gTouchY; - -// This is invoked automatically when the script is created -void init() { - gTouchX = 50.0f; - gTouchY = 50.0f; -} - -int root(void) { - - // Clear the background color - rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f); - // Tell the runtime what the font color should be - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - // Introuduce ourselves to the world by drawing a greeting - // at the position user touched on the screen - rsgDrawText("Hello World!", gTouchX, gTouchY); - - // Return value tells RS roughly how often to redraw - // in this case 20 ms - return 20; -} diff --git a/tests/RenderScriptTests/MiscSamples/Android.mk b/tests/RenderScriptTests/MiscSamples/Android.mk deleted file mode 100644 index ee3567bf1651..000000000000 --- a/tests/RenderScriptTests/MiscSamples/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2008 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_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - -LOCAL_PACKAGE_NAME := RsMiscSamples - -LOCAL_SDK_VERSION := 17 - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml b/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml deleted file mode 100644 index 08a3976afebe..000000000000 --- a/tests/RenderScriptTests/MiscSamples/AndroidManifest.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.example.android.rs.miscsamples"> - <uses-sdk android:minSdkVersion="11" /> - <application android:label="RsMiscSamples" - android:icon="@drawable/test_pattern"> - <activity android:name="RsList" - android:label="RsList" - android:theme="@android:style/Theme.Black.NoTitleBar"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - - <activity android:name="RsRenderStates" - android:label="RsStates" - android:theme="@android:style/Theme.Black.NoTitleBar"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/MiscSamples/_index.html b/tests/RenderScriptTests/MiscSamples/_index.html deleted file mode 100644 index 5872431420e6..000000000000 --- a/tests/RenderScriptTests/MiscSamples/_index.html +++ /dev/null @@ -1 +0,0 @@ -<p>A set of samples that demonstrate how to use various features of the Renderscript APIs.</p>
\ No newline at end of file diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png Binary files differdeleted file mode 100644 index b631e1ee4ba6..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/checker.png +++ /dev/null diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png Binary files differdeleted file mode 100644 index baf35d0acbe9..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/cubemap_test.png +++ /dev/null diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png Binary files differdeleted file mode 100644 index 8e347146e331..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/data.png +++ /dev/null diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png Binary files differdeleted file mode 100644 index 3cd37755f549..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/leaf.png +++ /dev/null diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png Binary files differdeleted file mode 100644 index e7d145554c00..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/test_pattern.png +++ /dev/null diff --git a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png b/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png Binary files differdeleted file mode 100644 index 1e08f3b9ac3e..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/drawable-nodpi/torusmap.png +++ /dev/null diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl deleted file mode 100644 index e492a477ff5b..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/multitexf.glsl +++ /dev/null @@ -1,13 +0,0 @@ -varying vec2 varTex0; - -void main() { - vec2 t0 = varTex0.xy; - lowp vec4 col0 = texture2D(UNI_Tex0, t0).rgba; - lowp vec4 col1 = texture2D(UNI_Tex1, t0*4.0).rgba; - lowp vec4 col2 = texture2D(UNI_Tex2, t0).rgba; - col0.xyz = col0.xyz*col1.xyz*1.5; - col0.xyz = mix(col0.xyz, col2.xyz, col2.w); - col0.w = 0.5; - gl_FragColor = col0; -} - diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl deleted file mode 100644 index 5fc05f14a812..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shader2f.glsl +++ /dev/null @@ -1,29 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -void main() { - - vec3 V = normalize(-varWorldPos.xyz); - vec3 worldNorm = normalize(varWorldNormal); - - vec3 light0Vec = normalize(UNI_light0_Posision.xyz - varWorldPos); - vec3 light0R = -reflect(light0Vec, worldNorm); - float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse; - float light0Spec = clamp(dot(light0R, V), 0.001, 1.0); - float light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular; - - vec3 light1Vec = normalize(UNI_light1_Posision.xyz - varWorldPos); - vec3 light1R = reflect(light1Vec, worldNorm); - float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse; - float light1Spec = clamp(dot(light1R, V), 0.001, 1.0); - float light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular; - - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; - col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz); - col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz; - col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz; - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl deleted file mode 100644 index a2c807e838cc..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shader2movev.glsl +++ /dev/null @@ -1,21 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -// This is where actual shader code begins -void main() { - vec4 objPos = ATTRIB_position; - vec3 oldPos = objPos.xyz; - objPos.xyz += 0.1*sin(objPos.xyz*2.0 + UNI_time); - objPos.xyz += 0.05*sin(objPos.xyz*4.0 + UNI_time*0.5); - objPos.xyz += 0.02*sin(objPos.xyz*7.0 + UNI_time*0.75); - vec4 worldPos = UNI_model * objPos; - gl_Position = UNI_proj * worldPos; - - mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); - vec3 worldNorm = model3 * (ATTRIB_normal + oldPos - objPos.xyz); - - varWorldPos = worldPos.xyz; - varWorldNormal = worldNorm; - varTex0 = ATTRIB_texture0; -} diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl deleted file mode 100644 index e6885a38aca0..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shader2v.glsl +++ /dev/null @@ -1,17 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -// This is where actual shader code begins -void main() { - vec4 objPos = ATTRIB_position; - vec4 worldPos = UNI_model * objPos; - gl_Position = UNI_proj * worldPos; - - mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); - vec3 worldNorm = model3 * ATTRIB_normal; - - varWorldPos = worldPos.xyz; - varWorldNormal = worldNorm; - varTex0 = ATTRIB_texture0; -} diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl deleted file mode 100644 index 238ecad56cf1..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayf.glsl +++ /dev/null @@ -1,16 +0,0 @@ - -varying lowp float light0_Diffuse; -varying lowp float light0_Specular; -varying lowp float light1_Diffuse; -varying lowp float light1_Specular; -varying vec2 varTex0; - -void main() { - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; - col.xyz = col.xyz * (light0_Diffuse * UNI_light_DiffuseColor[0].xyz + light1_Diffuse * UNI_light_DiffuseColor[1].xyz); - col.xyz += light0_Specular * UNI_light_SpecularColor[0].xyz; - col.xyz += light1_Specular * UNI_light_SpecularColor[1].xyz; - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl deleted file mode 100644 index 7a1310ac1ef4..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shaderarrayv.glsl +++ /dev/null @@ -1,32 +0,0 @@ -varying float light0_Diffuse; -varying float light0_Specular; -varying float light1_Diffuse; -varying float light1_Specular; -varying vec2 varTex0; - -// This is where actual shader code begins -void main() { - vec4 worldPos = UNI_model[0] * ATTRIB_position; - worldPos = UNI_model[1] * worldPos; - gl_Position = UNI_proj * worldPos; - - mat4 model0 = UNI_model[0]; - mat3 model3 = mat3(model0[0].xyz, model0[1].xyz, model0[2].xyz); - vec3 worldNorm = model3 * ATTRIB_normal; - vec3 V = normalize(-worldPos.xyz); - - vec3 light0Vec = normalize(UNI_light_Posision[0].xyz - worldPos.xyz); - vec3 light0R = -reflect(light0Vec, worldNorm); - light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light_Diffuse[0]; - float light0Spec = clamp(dot(light0R, V), 0.001, 1.0); - light0_Specular = pow(light0Spec, UNI_light_CosinePower[0]) * UNI_light_Specular[0]; - - vec3 light1Vec = normalize(UNI_light_Posision[1].xyz - worldPos.xyz); - vec3 light1R = reflect(light1Vec, worldNorm); - light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light_Diffuse[1]; - float light1Spec = clamp(dot(light1R, V), 0.001, 1.0); - light1_Specular = pow(light1Spec, UNI_light_CosinePower[1]) * UNI_light_Specular[1]; - - gl_PointSize = 1.0; - varTex0 = ATTRIB_texture0; -} diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl deleted file mode 100644 index 15696a4723d5..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubef.glsl +++ /dev/null @@ -1,8 +0,0 @@ - -varying vec3 worldNormal; - -void main() { - lowp vec4 col = textureCube(UNI_Tex0, worldNormal); - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl deleted file mode 100644 index 70f5cd64e371..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shadercubev.glsl +++ /dev/null @@ -1,10 +0,0 @@ -varying vec3 worldNormal; - -// This is where actual shader code begins -void main() { - vec4 worldPos = UNI_model * ATTRIB_position; - gl_Position = UNI_proj * worldPos; - - mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); - worldNormal = model3 * ATTRIB_normal; -} diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl deleted file mode 100644 index d56e203496c3..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shaderf.glsl +++ /dev/null @@ -1,16 +0,0 @@ - -varying lowp float light0_Diffuse; -varying lowp float light0_Specular; -varying lowp float light1_Diffuse; -varying lowp float light1_Specular; -varying vec2 varTex0; - -void main() { - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; - col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz); - col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz; - col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz; - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl b/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl deleted file mode 100644 index f7d01de384cb..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/shaderv.glsl +++ /dev/null @@ -1,30 +0,0 @@ -varying float light0_Diffuse; -varying float light0_Specular; -varying float light1_Diffuse; -varying float light1_Specular; -varying vec2 varTex0; - -// This is where actual shader code begins -void main() { - vec4 worldPos = UNI_model * ATTRIB_position; - gl_Position = UNI_proj * worldPos; - - mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); - vec3 worldNorm = model3 * ATTRIB_normal; - vec3 V = normalize(-worldPos.xyz); - - vec3 light0Vec = normalize(UNI_light0_Posision.xyz - worldPos.xyz); - vec3 light0R = -reflect(light0Vec, worldNorm); - light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse; - float light0Spec = clamp(dot(light0R, V), 0.001, 1.0); - light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular; - - vec3 light1Vec = normalize(UNI_light1_Posision.xyz - worldPos.xyz); - vec3 light1R = reflect(light1Vec, worldNorm); - light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse; - float light1Spec = clamp(dot(light1R, V), 0.001, 1.0); - light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular; - - gl_PointSize = 1.0; - varTex0 = ATTRIB_texture0; -} diff --git a/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d b/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d Binary files differdeleted file mode 100644 index 0322b01be8a8..000000000000 --- a/tests/RenderScriptTests/MiscSamples/res/raw/torus.a3d +++ /dev/null diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java deleted file mode 100644 index dade3b3cb449..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsList.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2008 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.example.android.rs.miscsamples; - -import android.app.Activity; -import android.os.Bundle; - -public class RsList extends Activity { - - private RsListView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new RsListView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity loses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity loses focus - super.onPause(); - mView.pause(); - } - -} - diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java deleted file mode 100644 index eeb2480cc720..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListRS.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (C) 2008 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.example.android.rs.miscsamples; - -import java.io.Writer; -import java.util.Vector; - -import android.content.res.Resources; -import android.renderscript.*; -import android.renderscript.ProgramStore.DepthFunc; -import android.util.Log; - - -public class RsListRS { - - private final int STATE_LAST_FOCUS = 1; - - private static final String[] DATA_LIST = { - "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra", - "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina", - "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan", - "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium", - "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia", - "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", - "British Indian Ocean Territory", "British Virgin Islands", "Brunei", "Bulgaria", - "Burkina Faso", "Burundi", "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde", - "Cayman Islands", "Central African Republic", "Chad", "Chile", "China", - "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo", - "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic", - "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic", - "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea", - "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland", - "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia", - "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar", - "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau", - "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary", - "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica", - "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos", - "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg", - "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands", - "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova", - "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia", - "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand", - "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas", - "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru", - "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar", - "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena", - "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon", - "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal", - "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands", - "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea", - "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden", - "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas", - "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey", - "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda", - "Ukraine", "United Arab Emirates", "United Kingdom", - "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan", - "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara", - "Yemen", "Yugoslavia", "Zambia", "Zimbabwe" - }; - - public RsListRS() { - } - - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initRS(); - } - - private Resources mRes; - private RenderScriptGL mRS; - private Font mItalic; - - ScriptField_ListAllocs_s mListAllocs; - - private ScriptC_rslist mScript; - - int mLastX; - int mLastY; - - public void onActionDown(int x, int y) { - mScript.set_gDY(0.0f); - - mLastX = x; - mLastY = y; - } - - public void onActionMove(int x, int y) { - int dx = mLastX - x; - int dy = mLastY - y; - - if (Math.abs(dy) <= 2) { - dy = 0; - } - - mScript.set_gDY(dy); - - mLastX = x; - mLastY = y; - } - - private void initRS() { - - mScript = new ScriptC_rslist(mRS, mRes, R.raw.rslist); - - mListAllocs = new ScriptField_ListAllocs_s(mRS, DATA_LIST.length); - for (int i = 0; i < DATA_LIST.length; i ++) { - ScriptField_ListAllocs_s.Item listElem = new ScriptField_ListAllocs_s.Item(); - listElem.text = Allocation.createFromString(mRS, DATA_LIST[i], Allocation.USAGE_SCRIPT); - mListAllocs.set(listElem, i, false); - } - - mListAllocs.copyAll(); - - mScript.bind_gList(mListAllocs); - - mItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); - mScript.set_gItalic(mItalic); - - mRS.bindRootScript(mScript); - } -} - - - diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java deleted file mode 100644 index db6e6c516a3a..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsListView.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2008 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.example.android.rs.miscsamples; -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.view.MotionEvent; - -public class RsListView extends RSSurfaceView { - - public RsListView(Context context) { - super(context); - ensureRenderScript(); - } - - private RenderScriptGL mRS; - private RsListRS mRender; - - private void ensureRenderScript() { - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - mRS = createRenderScriptGL(sc); - mRender = new RsListRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ensureRenderScript(); - } - - @Override - protected void onDetachedFromWindow() { - mRender = null; - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent ev) - { - boolean ret = false; - int act = ev.getAction(); - if (act == MotionEvent.ACTION_DOWN) { - mRender.onActionDown((int)ev.getX(), (int)ev.getY()); - ret = true; - } else if (act == MotionEvent.ACTION_MOVE) { - mRender.onActionMove((int)ev.getX(), (int)ev.getY()); - ret = true; - } - - return ret; - } -} - - diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java deleted file mode 100644 index f4ea76ef6f35..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStates.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2008 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.example.android.rs.miscsamples; - -import android.app.Activity; -import android.os.Bundle; - -public class RsRenderStates extends Activity { - - private RsRenderStatesView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new RsRenderStatesView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onPause(); - mView.pause(); - } - -} - diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java deleted file mode 100644 index 0e319fe9052c..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesRS.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2008 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.example.android.rs.miscsamples; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.renderscript.*; -import android.renderscript.Font.Style; -import android.renderscript.Program.TextureType; -import android.renderscript.ProgramStore.DepthFunc; -import android.renderscript.ProgramStore.BlendSrcFunc; -import android.renderscript.ProgramStore.BlendDstFunc; -import android.renderscript.Sampler.Value; -import android.util.Log; - - -public class RsRenderStatesRS { - - int mWidth; - int mHeight; - - public RsRenderStatesRS() { - } - - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mWidth = mRS.getWidth(); - mHeight = mRS.getHeight(); - mRes = res; - mOptionsARGB.inScaled = false; - mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; - mMode = 0; - mMaxModes = 0; - initRS(); - } - - public void surfaceChanged() { - mWidth = mRS.getWidth(); - mHeight = mRS.getHeight(); - - Matrix4f proj = new Matrix4f(); - proj.loadOrthoWindow(mWidth, mHeight); - mPVA.setProjection(proj); - } - - private Resources mRes; - private RenderScriptGL mRS; - - private Sampler mLinearClamp; - private Sampler mLinearWrap; - private Sampler mMipLinearWrap; - private Sampler mNearestClamp; - private Sampler mMipLinearAniso8; - private Sampler mMipLinearAniso15; - - private ProgramStore mProgStoreBlendNoneDepth; - private ProgramStore mProgStoreBlendNone; - private ProgramStore mProgStoreBlendAlpha; - private ProgramStore mProgStoreBlendAdd; - - private ProgramFragment mProgFragmentTexture; - private ProgramFragment mProgFragmentColor; - - private ProgramVertex mProgVertex; - private ProgramVertexFixedFunction.Constants mPVA; - - // Custom shaders - private ProgramVertex mProgVertexCustom; - private ProgramFragment mProgFragmentCustom; - private ProgramFragment mProgFragmentMultitex; - private ScriptField_VertexShaderConstants_s mVSConst; - private ScriptField_VertexShaderConstants2_s mVSConst2; - private ScriptField_FragentShaderConstants_s mFSConst; - private ScriptField_FragentShaderConstants2_s mFSConst2; - - private ProgramVertex mProgVertexCustom2; - private ProgramFragment mProgFragmentCustom2; - - private ProgramVertex mProgVertexCube; - private ProgramFragment mProgFragmentCube; - - private ProgramRaster mCullBack; - private ProgramRaster mCullFront; - private ProgramRaster mCullNone; - - private Allocation mTexTorus; - private Allocation mTexOpaque; - private Allocation mTexTransparent; - private Allocation mTexChecker; - private Allocation mTexCube; - - private Mesh mMbyNMesh; - private Mesh mTorus; - - Font mFontSans; - Font mFontSerif; - Font mFontSerifBold; - Font mFontSerifItalic; - Font mFontSerifBoldItalic; - Font mFontMono; - private Allocation mTextAlloc; - - private ScriptC_rsrenderstates mScript; - - private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); - - int mMode; - int mMaxModes; - - public void onActionDown(int x, int y) { - mMode ++; - mMode = mMode % mMaxModes; - mScript.set_gDisplayMode(mMode); - } - - ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) { - ProgramStore.Builder builder = new ProgramStore.Builder(rs); - builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); - builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); - builder.setDitherEnabled(false); - builder.setDepthMaskEnabled(false); - return builder.create(); - } - - private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) { - - Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, - 2, Mesh.TriangleMeshBuilder.TEXTURE_0); - - for (int y = 0; y <= hResolution; y++) { - final float normalizedY = (float)y / hResolution; - final float yOffset = (normalizedY - 0.5f) * height; - for (int x = 0; x <= wResolution; x++) { - float normalizedX = (float)x / wResolution; - float xOffset = (normalizedX - 0.5f) * width; - tmb.setTexture(normalizedX, normalizedY); - tmb.addVertex(xOffset, yOffset); - } - } - - for (int y = 0; y < hResolution; y++) { - final int curY = y * (wResolution + 1); - final int belowY = (y + 1) * (wResolution + 1); - for (int x = 0; x < wResolution; x++) { - int curV = curY + x; - int belowV = belowY + x; - tmb.addTriangle(curV, belowV, curV + 1); - tmb.addTriangle(belowV, belowV + 1, curV + 1); - } - } - - return tmb.create(true); - } - - private void initProgramStore() { - // Use stock the stock program store object - mProgStoreBlendNoneDepth = ProgramStore.BLEND_NONE_DEPTH_TEST(mRS); - mProgStoreBlendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(mRS); - - // Create a custom program store - ProgramStore.Builder builder = new ProgramStore.Builder(mRS); - builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); - builder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA, - ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA); - builder.setDitherEnabled(false); - builder.setDepthMaskEnabled(false); - mProgStoreBlendAlpha = builder.create(); - - mProgStoreBlendAdd = BLEND_ADD_DEPTH_NONE(mRS); - - mScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth); - mScript.set_gProgStoreBlendNone(mProgStoreBlendNone); - mScript.set_gProgStoreBlendAlpha(mProgStoreBlendAlpha); - mScript.set_gProgStoreBlendAdd(mProgStoreBlendAdd); - } - - private void initProgramFragment() { - - ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mProgFragmentTexture = texBuilder.create(); - mProgFragmentTexture.bindSampler(mLinearClamp, 0); - - ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - colBuilder.setVaryingColor(false); - mProgFragmentColor = colBuilder.create(); - - mScript.set_gProgFragmentColor(mProgFragmentColor); - mScript.set_gProgFragmentTexture(mProgFragmentTexture); - } - - private void initProgramVertex() { - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - mProgVertex = pvb.create(); - - mPVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA); - Matrix4f proj = new Matrix4f(); - proj.loadOrthoWindow(mWidth, mHeight); - mPVA.setProjection(proj); - - mScript.set_gProgVertex(mProgVertex); - } - - private void initCustomShaders() { - mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1); - mVSConst2 = new ScriptField_VertexShaderConstants2_s(mRS, 1); - mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1); - mFSConst2 = new ScriptField_FragentShaderConstants2_s(mRS, 1); - - mScript.bind_gVSConstants(mVSConst); - mScript.bind_gVSConstants2(mVSConst2); - mScript.bind_gFSConstants(mFSConst); - mScript.bind_gFSConstants2(mFSConst2); - - // Initialize the shader builder - ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS); - // Specify the resource that contains the shader string - pvbCustom.setShader(mRes, R.raw.shaderv); - // Use a script field to spcify the input layout - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - // Define the constant input layout - pvbCustom.addConstant(mVSConst.getAllocation().getType()); - mProgVertexCustom = pvbCustom.create(); - // Bind the source of constant data - mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0); - - ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS); - // Specify the resource that contains the shader string - pfbCustom.setShader(mRes, R.raw.shaderf); - //Tell the builder how many textures we have - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - // Define the constant input layout - pfbCustom.addConstant(mFSConst.getAllocation().getType()); - mProgFragmentCustom = pfbCustom.create(); - // Bind the source of constant data - mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0); - - pvbCustom = new ProgramVertex.Builder(mRS); - pvbCustom.setShader(mRes, R.raw.shaderarrayv); - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - pvbCustom.addConstant(mVSConst2.getAllocation().getType()); - mProgVertexCustom2 = pvbCustom.create(); - mProgVertexCustom2.bindConstants(mVSConst2.getAllocation(), 0); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.shaderarrayf); - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - pfbCustom.addConstant(mFSConst2.getAllocation().getType()); - mProgFragmentCustom2 = pfbCustom.create(); - mProgFragmentCustom2.bindConstants(mFSConst2.getAllocation(), 0); - - // Cubemap test shaders - pvbCustom = new ProgramVertex.Builder(mRS); - pvbCustom.setShader(mRes, R.raw.shadercubev); - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - pvbCustom.addConstant(mVSConst.getAllocation().getType()); - mProgVertexCube = pvbCustom.create(); - mProgVertexCube.bindConstants(mVSConst.getAllocation(), 0); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.shadercubef); - pfbCustom.addTexture(Program.TextureType.TEXTURE_CUBE); - mProgFragmentCube = pfbCustom.create(); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.multitexf); - for (int texCount = 0; texCount < 3; texCount ++) { - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - } - mProgFragmentMultitex = pfbCustom.create(); - - mScript.set_gProgVertexCustom(mProgVertexCustom); - mScript.set_gProgFragmentCustom(mProgFragmentCustom); - mScript.set_gProgVertexCustom2(mProgVertexCustom2); - mScript.set_gProgFragmentCustom2(mProgFragmentCustom2); - mScript.set_gProgVertexCube(mProgVertexCube); - mScript.set_gProgFragmentCube(mProgFragmentCube); - mScript.set_gProgFragmentMultitex(mProgFragmentMultitex); - } - - private Allocation loadTextureRGB(int id) { - return Allocation.createFromBitmapResource(mRS, mRes, id, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - private Allocation loadTextureARGB(int id) { - Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB); - return Allocation.createFromBitmap(mRS, b, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - private void loadImages() { - mTexTorus = loadTextureRGB(R.drawable.torusmap); - mTexOpaque = loadTextureRGB(R.drawable.data); - mTexTransparent = loadTextureARGB(R.drawable.leaf); - mTexChecker = loadTextureRGB(R.drawable.checker); - Bitmap b = BitmapFactory.decodeResource(mRes, R.drawable.cubemap_test); - mTexCube = Allocation.createCubemapFromBitmap(mRS, b); - - mScript.set_gTexTorus(mTexTorus); - mScript.set_gTexOpaque(mTexOpaque); - mScript.set_gTexTransparent(mTexTransparent); - mScript.set_gTexChecker(mTexChecker); - mScript.set_gTexCube(mTexCube); - } - - private void initFonts() { - // Sans font by family name - mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8); - mFontSerif = Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8); - // Create fonts by family and style - mFontSerifBold = Font.create(mRS, mRes, "serif", Font.Style.BOLD, 8); - mFontSerifItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); - mFontSerifBoldItalic = Font.create(mRS, mRes, "serif", Font.Style.BOLD_ITALIC, 8); - mFontMono = Font.create(mRS, mRes, "mono", Font.Style.NORMAL, 8); - - mTextAlloc = Allocation.createFromString(mRS, "String from allocation", Allocation.USAGE_SCRIPT); - - mScript.set_gFontSans(mFontSans); - mScript.set_gFontSerif(mFontSerif); - mScript.set_gFontSerifBold(mFontSerifBold); - mScript.set_gFontSerifItalic(mFontSerifItalic); - mScript.set_gFontSerifBoldItalic(mFontSerifBoldItalic); - mScript.set_gFontMono(mFontMono); - mScript.set_gTextAlloc(mTextAlloc); - } - - private void initMesh() { - mMbyNMesh = getMbyNMesh(256, 256, 10, 10); - mScript.set_gMbyNMesh(mMbyNMesh); - - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus); - FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { - Log.e("rs", "could not load model"); - } else { - mTorus = (Mesh)entry.getObject(); - mScript.set_gTorusMesh(mTorus); - } - } - - private void initSamplers() { - Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMinification(Sampler.Value.LINEAR); - bs.setMagnification(Sampler.Value.LINEAR); - bs.setWrapS(Sampler.Value.WRAP); - bs.setWrapT(Sampler.Value.WRAP); - mLinearWrap = bs.create(); - - mLinearClamp = Sampler.CLAMP_LINEAR(mRS); - mNearestClamp = Sampler.CLAMP_NEAREST(mRS); - mMipLinearWrap = Sampler.WRAP_LINEAR_MIP_LINEAR(mRS); - - bs = new Sampler.Builder(mRS); - bs.setMinification(Sampler.Value.LINEAR_MIP_LINEAR); - bs.setMagnification(Sampler.Value.LINEAR); - bs.setWrapS(Sampler.Value.WRAP); - bs.setWrapT(Sampler.Value.WRAP); - bs.setAnisotropy(8.0f); - mMipLinearAniso8 = bs.create(); - bs.setAnisotropy(15.0f); - mMipLinearAniso15 = bs.create(); - - mScript.set_gLinearClamp(mLinearClamp); - mScript.set_gLinearWrap(mLinearWrap); - mScript.set_gMipLinearWrap(mMipLinearWrap); - mScript.set_gMipLinearAniso8(mMipLinearAniso8); - mScript.set_gMipLinearAniso15(mMipLinearAniso15); - mScript.set_gNearestClamp(mNearestClamp); - } - - private void initProgramRaster() { - mCullBack = ProgramRaster.CULL_BACK(mRS); - mCullFront = ProgramRaster.CULL_FRONT(mRS); - mCullNone = ProgramRaster.CULL_NONE(mRS); - - mScript.set_gCullBack(mCullBack); - mScript.set_gCullFront(mCullFront); - mScript.set_gCullNone(mCullNone); - } - - private void initRS() { - - mScript = new ScriptC_rsrenderstates(mRS, mRes, R.raw.rsrenderstates); - - mMaxModes = mScript.get_gMaxModes(); - - initSamplers(); - initProgramStore(); - initProgramFragment(); - initProgramVertex(); - initFonts(); - loadImages(); - initMesh(); - initProgramRaster(); - initCustomShaders(); - - mRS.bindRootScript(mScript); - } -} - - - diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java deleted file mode 100644 index a15e38f8b9fd..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/RsRenderStatesView.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2008 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.example.android.rs.miscsamples; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.view.MotionEvent; -import android.view.SurfaceHolder; - -public class RsRenderStatesView extends RSSurfaceView { - - public RsRenderStatesView(Context context) { - super(context); - ensureRenderScript(); - } - - private RenderScriptGL mRS; - private RsRenderStatesRS mRender; - - private void ensureRenderScript() { - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - mRS = createRenderScriptGL(sc); - mRender = new RsRenderStatesRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ensureRenderScript(); - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - mRender.surfaceChanged(); - } - - @Override - protected void onDetachedFromWindow() { - mRender = null; - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mRender.onActionDown((int)ev.getX(), (int)ev.getY()); - return true; - } - - return false; - } -} - - diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs deleted file mode 100644 index d9d450dc4f62..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rslist.rs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (C) 2009 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 version(1) - -#pragma rs java_package_name(com.example.android.rs.miscsamples) - -#include "rs_graphics.rsh" - -float gDY; - -rs_font gItalic; - -typedef struct ListAllocs_s { - rs_allocation text; -} ListAllocs; - -ListAllocs *gList; - -void init() { - gDY = 0.0f; -} - -int textPos = 0; - -int root(void) { - - rsgClearColor(0.0f, 0.0f, 0.0f, 0.0f); - - textPos -= (int)gDY*2; - gDY *= 0.95; - - rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); - rsgBindFont(gItalic); - - rs_allocation listAlloc; - listAlloc = rsGetAllocation(gList); - int allocSize = rsAllocationGetDimX(listAlloc); - - int width = rsgGetWidth(); - int height = rsgGetHeight(); - - int itemHeight = 80; - int currentYPos = itemHeight + textPos; - - for (int i = 0; i < allocSize; i ++) { - if (currentYPos - itemHeight > height) { - break; - } - - if (currentYPos > 0) { - rsgDrawRect(0, currentYPos - 1, width, currentYPos, 0); - rsgDrawText(gList[i].text, 30, currentYPos - 32); - } - currentYPos += itemHeight; - } - - return 10; -} diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs deleted file mode 100644 index 5dabd00bc133..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/rsrenderstates.rs +++ /dev/null @@ -1,680 +0,0 @@ -// Copyright (C) 2009 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 version(1) - -#pragma rs java_package_name(com.example.android.rs.miscsamples) - -#include "rs_graphics.rsh" -#include "shader_def.rsh" - -const int gMaxModes = 11; - -rs_program_vertex gProgVertex; -rs_program_fragment gProgFragmentColor; -rs_program_fragment gProgFragmentTexture; - -rs_program_store gProgStoreBlendNoneDepth; -rs_program_store gProgStoreBlendNone; -rs_program_store gProgStoreBlendAlpha; -rs_program_store gProgStoreBlendAdd; - -rs_allocation gTexOpaque; -rs_allocation gTexTorus; -rs_allocation gTexTransparent; -rs_allocation gTexChecker; -rs_allocation gTexCube; - -rs_mesh gMbyNMesh; -rs_mesh gTorusMesh; - -rs_font gFontSans; -rs_font gFontSerif; -rs_font gFontSerifBold; -rs_font gFontSerifItalic; -rs_font gFontSerifBoldItalic; -rs_font gFontMono; -rs_allocation gTextAlloc; - -int gDisplayMode; - -rs_sampler gLinearClamp; -rs_sampler gLinearWrap; -rs_sampler gMipLinearWrap; -rs_sampler gMipLinearAniso8; -rs_sampler gMipLinearAniso15; -rs_sampler gNearestClamp; - -rs_program_raster gCullBack; -rs_program_raster gCullFront; -rs_program_raster gCullNone; - -// Custom vertex shader compunents -VertexShaderConstants *gVSConstants; -VertexShaderConstants2 *gVSConstants2; -FragentShaderConstants *gFSConstants; -FragentShaderConstants2 *gFSConstants2; -// Export these out to easily set the inputs to shader -VertexShaderInputs *gVSInputs; -// Custom shaders we use for lighting -rs_program_vertex gProgVertexCustom; -rs_program_fragment gProgFragmentCustom; -rs_program_vertex gProgVertexCustom2; -rs_program_fragment gProgFragmentCustom2; -rs_program_vertex gProgVertexCube; -rs_program_fragment gProgFragmentCube; -rs_program_fragment gProgFragmentMultitex; - -float gDt = 0; - -void init() { -} - -static void displayFontSamples() { - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - int yPos = 100; - rsgBindFont(gFontSans); - rsgDrawText("Sans font sample", 30, yPos); - yPos += 30; - rsgFontColor(0.5f, 0.9f, 0.5f, 1.0f); - rsgBindFont(gFontSerif); - rsgDrawText("Serif font sample", 30, yPos); - yPos += 30; - rsgFontColor(0.7f, 0.7f, 0.7f, 1.0f); - rsgBindFont(gFontSerifBold); - rsgDrawText("Serif Bold font sample", 30, yPos); - yPos += 30; - rsgFontColor(0.5f, 0.5f, 0.9f, 1.0f); - rsgBindFont(gFontSerifItalic); - rsgDrawText("Serif Italic font sample", 30, yPos); - yPos += 30; - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontSerifBoldItalic); - rsgDrawText("Serif Bold Italic font sample", 30, yPos); - yPos += 30; - rsgBindFont(gFontMono); - rsgDrawText("Monospace font sample", 30, yPos); - yPos += 50; - - // Now use text metrics to center the text - uint width = rsgGetWidth(); - uint height = rsgGetHeight(); - int left = 0, right = 0, top = 0, bottom = 0; - - rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); - rsgBindFont(gFontSerifBoldItalic); - - rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom); - int centeredPos = width / 2 - (right - left) / 2; - rsgDrawText(gTextAlloc, centeredPos, yPos); - yPos += 30; - - const char* text = "Centered Text Sample"; - rsgMeasureText(text, &left, &right, &top, &bottom); - centeredPos = width / 2 - (right - left) / 2; - rsgDrawText(text, centeredPos, yPos); - yPos += 30; - - rsgBindFont(gFontSans); - text = "More Centered Text Samples"; - rsgMeasureText(text, &left, &right, &top, &bottom); - centeredPos = width / 2 - (right - left) / 2; - rsgDrawText(text, centeredPos, yPos); - yPos += 30; - - // Now draw bottom and top right aligned text - text = "Top-right aligned text"; - rsgMeasureText(text, &left, &right, &top, &bottom); - rsgDrawText(text, width - right, top); - - text = "Top-left"; - rsgMeasureText(text, &left, &right, &top, &bottom); - rsgDrawText(text, -left, top); - - text = "Bottom-right aligned text"; - rsgMeasureText(text, &left, &right, &top, &bottom); - rsgDrawText(text, width - right, height + bottom); - -} - -static void bindProgramVertexOrtho() { - // Default vertex sahder - rsgBindProgramVertex(gProgVertex); - // Setup the projectioni matrix - rs_matrix4x4 proj; - rsMatrixLoadOrtho(&proj, 0, rsgGetWidth(), rsgGetHeight(), 0, -500, 500); - rsgProgramVertexLoadProjectionMatrix(&proj); -} - -static void displayShaderSamples() { - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNone); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); - - float startX = 0, startY = 0; - float width = 256, height = 256; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1, - startX + width, startY + height, 0, 1, 1, - startX + width, startY, 0, 1, 0); - - startX = 200; startY = 0; - width = 128; height = 128; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1, - startX + width, startY + height, 0, 1, 1, - startX + width, startY, 0, 1, 0); - - rsgBindProgramStore(gProgStoreBlendAlpha); - rsgBindTexture(gProgFragmentTexture, 0, gTexTransparent); - startX = 0; startY = 200; - width = 128; height = 128; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1, - startX + width, startY + height, 0, 1, 1, - startX + width, startY, 0, 1, 0); - - // Fragment program with simple color - rsgBindProgramFragment(gProgFragmentColor); - rsgProgramFragmentConstantColor(gProgFragmentColor, 0.9, 0.3, 0.3, 1); - rsgDrawRect(200, 300, 350, 450, 0); - rsgProgramFragmentConstantColor(gProgFragmentColor, 0.3, 0.9, 0.3, 1); - rsgDrawRect(50, 400, 400, 600, 0); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("Texture shader", 10, 50); - rsgDrawText("Alpha-blended texture shader", 10, 280); - rsgDrawText("Flat color shader", 100, 450); -} - -static void displayBlendingSamples() { - int i; - - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - rsgBindProgramFragment(gProgFragmentColor); - - rsgBindProgramStore(gProgStoreBlendNone); - for (i = 0; i < 3; i ++) { - float iPlusOne = (float)(i + 1); - rsgProgramFragmentConstantColor(gProgFragmentColor, - 0.1f*iPlusOne, 0.2f*iPlusOne, 0.3f*iPlusOne, 1); - float yPos = 150 * (float)i; - rsgDrawRect(0, yPos, 200, yPos + 200, 0); - } - - rsgBindProgramStore(gProgStoreBlendAlpha); - for (i = 0; i < 3; i ++) { - float iPlusOne = (float)(i + 1); - rsgProgramFragmentConstantColor(gProgFragmentColor, - 0.2f*iPlusOne, 0.3f*iPlusOne, 0.1f*iPlusOne, 0.5); - float yPos = 150 * (float)i; - rsgDrawRect(150, yPos, 350, yPos + 200, 0); - } - - rsgBindProgramStore(gProgStoreBlendAdd); - for (i = 0; i < 3; i ++) { - float iPlusOne = (float)(i + 1); - rsgProgramFragmentConstantColor(gProgFragmentColor, - 0.3f*iPlusOne, 0.1f*iPlusOne, 0.2f*iPlusOne, 0.5); - float yPos = 150 * (float)i; - rsgDrawRect(300, yPos, 500, yPos + 200, 0); - } - - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("No Blending", 10, 50); - rsgDrawText("Alpha Blending", 160, 150); - rsgDrawText("Additive Blending", 320, 250); - -} - -static void displayMeshSamples() { - - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadTranslate(&matrix, 128, 128, 0); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNone); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); - - rsgDrawMesh(gMbyNMesh); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("User gen 10 by 10 grid mesh", 10, 250); -} - -static void displayTextureSamplers() { - - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNone); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); - - // Linear clamp - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - float startX = 0, startY = 0; - float width = 300, height = 300; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1.1, - startX + width, startY + height, 0, 1.1, 1.1, - startX + width, startY, 0, 1.1, 0); - - // Linear Wrap - rsgBindSampler(gProgFragmentTexture, 0, gLinearWrap); - startX = 0; startY = 300; - width = 300; height = 300; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1.1, - startX + width, startY + height, 0, 1.1, 1.1, - startX + width, startY, 0, 1.1, 0); - - // Nearest - rsgBindSampler(gProgFragmentTexture, 0, gNearestClamp); - startX = 300; startY = 0; - width = 300; height = 300; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1.1, - startX + width, startY + height, 0, 1.1, 1.1, - startX + width, startY, 0, 1.1, 0); - - rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap); - startX = 300; startY = 300; - width = 300; height = 300; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1.5, - startX + width, startY + height, 0, 1.5, 1.5, - startX + width, startY, 0, 1.5, 0); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("Filtering: linear clamp", 10, 290); - rsgDrawText("Filtering: linear wrap", 10, 590); - rsgDrawText("Filtering: nearest clamp", 310, 290); - rsgDrawText("Filtering: miplinear wrap", 310, 590); -} - -static float gTorusRotation = 0; - -static void displayCullingSamples() { - rsgBindProgramVertex(gProgVertex); - // Setup the projectioni matrix with 60 degree field of view - rs_matrix4x4 proj; - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNoneDepth); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexTorus); - - // Aplly a rotation to our mesh - gTorusRotation += 50.0f * gDt; - if (gTorusRotation > 360.0f) { - gTorusRotation -= 360.0f; - } - - rs_matrix4x4 matrix; - // Position our model on the screen - rsMatrixLoadTranslate(&matrix, -2.0f, 0.0f, -10.0f); - rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f); - rsgProgramVertexLoadModelMatrix(&matrix); - // Use front face culling - rsgBindProgramRaster(gCullFront); - rsgDrawMesh(gTorusMesh); - - rsMatrixLoadTranslate(&matrix, 2.0f, 0.0f, -10.0f); - rsMatrixRotate(&matrix, gTorusRotation, 1.0f, 0.0f, 0.0f); - rsgProgramVertexLoadModelMatrix(&matrix); - // Use back face culling - rsgBindProgramRaster(gCullBack); - rsgDrawMesh(gTorusMesh); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("Displaying mesh front/back face culling", 10, rsgGetHeight() - 10); -} - -static float gLight0Rotation = 0; -static float gLight1Rotation = 0; - -static void setupCustomShaderLights() { - float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f}; - float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f}; - float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f}; - float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f}; - float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f}; - float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f}; - - gLight0Rotation += 50.0f * gDt; - if (gLight0Rotation > 360.0f) { - gLight0Rotation -= 360.0f; - } - gLight1Rotation -= 50.0f * gDt; - if (gLight1Rotation > 360.0f) { - gLight1Rotation -= 360.0f; - } - - rs_matrix4x4 l0Mat; - rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f); - light0Pos = rsMatrixMultiply(&l0Mat, light0Pos); - rs_matrix4x4 l1Mat; - rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f); - light1Pos = rsMatrixMultiply(&l1Mat, light1Pos); - - // Set light 0 properties - gVSConstants->light0_Posision = light0Pos; - gVSConstants->light0_Diffuse = 1.0f; - gVSConstants->light0_Specular = 0.5f; - gVSConstants->light0_CosinePower = 10.0f; - // Set light 1 properties - gVSConstants->light1_Posision = light1Pos; - gVSConstants->light1_Diffuse = 1.0f; - gVSConstants->light1_Specular = 0.7f; - gVSConstants->light1_CosinePower = 25.0f; - rsgAllocationSyncAll(rsGetAllocation(gVSConstants)); - - gVSConstants2->light_Posision[0] = light0Pos; - gVSConstants2->light_Diffuse[0] = 1.0f; - gVSConstants2->light_Specular[0] = 0.5f; - gVSConstants2->light_CosinePower[0] = 10.0f; - gVSConstants2->light_Posision[1] = light1Pos; - gVSConstants2->light_Diffuse[1] = 1.0f; - gVSConstants2->light_Specular[1] = 0.7f; - gVSConstants2->light_CosinePower[1] = 25.0f; - rsgAllocationSyncAll(rsGetAllocation(gVSConstants2)); - - // Update fragmetn shader constants - // Set light 0 colors - gFSConstants->light0_DiffuseColor = light0DiffCol; - gFSConstants->light0_SpecularColor = light0SpecCol; - // Set light 1 colors - gFSConstants->light1_DiffuseColor = light1DiffCol; - gFSConstants->light1_SpecularColor = light1SpecCol; - rsgAllocationSyncAll(rsGetAllocation(gFSConstants)); - - gFSConstants2->light_DiffuseColor[0] = light0DiffCol; - gFSConstants2->light_SpecularColor[0] = light0SpecCol; - // Set light 1 colors - gFSConstants2->light_DiffuseColor[1] = light1DiffCol; - gFSConstants2->light_SpecularColor[1] = light1SpecCol; - rsgAllocationSyncAll(rsGetAllocation(gFSConstants2)); -} - -static void displayCustomShaderSamples() { - - // Update vertex shader constants - // Load model matrix - // Aplly a rotation to our mesh - gTorusRotation += 50.0f * gDt; - if (gTorusRotation > 360.0f) { - gTorusRotation -= 360.0f; - } - - // Position our model on the screen - rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f); - rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f); - // Setup the projectioni matrix - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f); - setupCustomShaderLights(); - - rsgBindProgramVertex(gProgVertexCustom); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNoneDepth); - rsgBindProgramFragment(gProgFragmentCustom); - rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp); - rsgBindTexture(gProgFragmentCustom, 0, gTexTorus); - - // Use back face culling - rsgBindProgramRaster(gCullBack); - rsgDrawMesh(gTorusMesh); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("Custom shader sample", 10, rsgGetHeight() - 10); -} - -static void displayCustomShaderSamples2() { - - // Update vertex shader constants - // Load model matrix - // Aplly a rotation to our mesh - gTorusRotation += 50.0f * gDt; - if (gTorusRotation > 360.0f) { - gTorusRotation -= 360.0f; - } - - // Position our model on the screen - rsMatrixLoadTranslate(&gVSConstants2->model[1], 0.0f, 0.0f, -10.0f); - rsMatrixLoadIdentity(&gVSConstants2->model[0]); - rsMatrixRotate(&gVSConstants2->model[0], gTorusRotation, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&gVSConstants2->model[0], gTorusRotation, 0.0f, 0.0f, 1.0f); - // Setup the projectioni matrix - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&gVSConstants2->proj, 30.0f, aspect, 0.1f, 100.0f); - setupCustomShaderLights(); - - rsgBindProgramVertex(gProgVertexCustom2); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNoneDepth); - rsgBindProgramFragment(gProgFragmentCustom2); - rsgBindSampler(gProgFragmentCustom2, 0, gLinearClamp); - rsgBindTexture(gProgFragmentCustom2, 0, gTexTorus); - - // Use back face culling - rsgBindProgramRaster(gCullBack); - rsgDrawMesh(gTorusMesh); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("Custom shader sample with array uniforms", 10, rsgGetHeight() - 10); -} - -static void displayCubemapShaderSample() { - // Update vertex shader constants - // Load model matrix - // Aplly a rotation to our mesh - gTorusRotation += 50.0f * gDt; - if (gTorusRotation > 360.0f) { - gTorusRotation -= 360.0f; - } - - // Position our model on the screen - // Position our model on the screen - rsMatrixLoadTranslate(&gVSConstants->model, 0.0f, 0.0f, -10.0f); - rsMatrixRotate(&gVSConstants->model, gTorusRotation, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&gVSConstants->model, gTorusRotation, 0.0f, 0.0f, 1.0f); - // Setup the projectioni matrix - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f); - rsgAllocationSyncAll(rsGetAllocation(gFSConstants)); - - rsgBindProgramVertex(gProgVertexCube); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNoneDepth); - rsgBindProgramFragment(gProgFragmentCube); - rsgBindSampler(gProgFragmentCube, 0, gLinearClamp); - rsgBindTexture(gProgFragmentCube, 0, gTexCube); - - // Use back face culling - rsgBindProgramRaster(gCullBack); - rsgDrawMesh(gTorusMesh); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("Cubemap shader sample", 10, rsgGetHeight() - 10); -} - -static void displayMultitextureSample() { - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNone); - rsgBindProgramFragment(gProgFragmentMultitex); - rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp); - rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap); - rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp); - rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker); - rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus); - rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent); - - float startX = 0, startY = 0; - float width = 256, height = 256; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1, - startX + width, startY + height, 0, 1, 1, - startX + width, startY, 0, 1, 0); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - rsgDrawText("Custom shader with multitexturing", 10, 280); -} - -static float gAnisoTime = 0.0f; -static uint anisoMode = 0; -static void displayAnisoSample() { - - gAnisoTime += gDt; - - rsgBindProgramVertex(gProgVertex); - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rs_matrix4x4 proj; - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rs_matrix4x4 matrix; - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNone); - rsgBindProgramFragment(gProgFragmentTexture); - rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, -10.0f); - rsMatrixRotate(&matrix, -80, 1.0f, 0.0f, 0.0f); - rsgProgramVertexLoadModelMatrix(&matrix); - - rsgBindProgramRaster(gCullNone); - - rsgBindTexture(gProgFragmentTexture, 0, gTexChecker); - - if (gAnisoTime >= 5.0f) { - gAnisoTime = 0.0f; - anisoMode ++; - anisoMode = anisoMode % 3; - } - - if (anisoMode == 0) { - rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso8); - } else if (anisoMode == 1) { - rsgBindSampler(gProgFragmentTexture, 0, gMipLinearAniso15); - } else { - rsgBindSampler(gProgFragmentTexture, 0, gMipLinearWrap); - } - - float startX = -15; - float startY = -15; - float width = 30; - float height = 30; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 10, - startX + width, startY + height, 0, 10, 10, - startX + width, startY, 0, 10, 0); - - rsgBindProgramRaster(gCullBack); - - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgBindFont(gFontMono); - if (anisoMode == 0) { - rsgDrawText("Anisotropic filtering 8", 10, 40); - } else if (anisoMode == 1) { - rsgDrawText("Anisotropic filtering 15", 10, 40); - } else { - rsgDrawText("Miplinear filtering", 10, 40); - } -} - -int root(void) { - - gDt = rsGetDt(); - - rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f); - rsgClearDepth(1.0f); - - switch (gDisplayMode) { - case 0: - displayFontSamples(); - break; - case 1: - displayShaderSamples(); - break; - case 2: - displayBlendingSamples(); - break; - case 3: - displayMeshSamples(); - break; - case 4: - displayTextureSamplers(); - break; - case 5: - displayCullingSamples(); - break; - case 6: - displayCustomShaderSamples(); - break; - case 7: - displayMultitextureSample(); - break; - case 8: - displayAnisoSample(); - break; - case 9: - displayCustomShaderSamples2(); - break; - case 10: - displayCubemapShaderSample(); - break; - } - - return 10; -} diff --git a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh b/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh deleted file mode 100644 index 08cf361e8fe5..000000000000 --- a/tests/RenderScriptTests/MiscSamples/src/com/example/android/rs/miscsamples/shader_def.rsh +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (C) 2009 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 version(1) - -#pragma rs java_package_name(com.example.android.rs.miscsamples) - -typedef struct VertexShaderConstants_s { - rs_matrix4x4 model; - rs_matrix4x4 proj; - float4 light0_Posision; - float light0_Diffuse; - float light0_Specular; - float light0_CosinePower; - - float4 light1_Posision; - float light1_Diffuse; - float light1_Specular; - float light1_CosinePower; -} VertexShaderConstants; - -typedef struct VertexShaderConstants2_s { - rs_matrix4x4 model[2]; - rs_matrix4x4 proj; - float4 light_Posision[2]; - float light_Diffuse[2]; - float light_Specular[2]; - float light_CosinePower[2]; -} VertexShaderConstants2; - -typedef struct VertexShaderConstants3_s { - rs_matrix4x4 model; - rs_matrix4x4 proj; - float time; -} VertexShaderConstants3; - - -typedef struct FragentShaderConstants_s { - float4 light0_DiffuseColor; - float4 light0_SpecularColor; - - float4 light1_DiffuseColor; - float4 light1_SpecularColor; -} FragentShaderConstants; - -typedef struct FragentShaderConstants2_s { - float4 light_DiffuseColor[2]; - float4 light_SpecularColor[2]; -} FragentShaderConstants2; - -typedef struct FragentShaderConstants3_s { - float4 light0_DiffuseColor; - float4 light0_SpecularColor; - float4 light0_Posision; - float light0_Diffuse; - float light0_Specular; - float light0_CosinePower; - - float4 light1_DiffuseColor; - float4 light1_SpecularColor; - float4 light1_Posision; - float light1_Diffuse; - float light1_Specular; - float light1_CosinePower; -} FragentShaderConstants3; - -typedef struct VertexShaderInputs_s { - float4 position; - float3 normal; - float2 texture0; -} VertexShaderInputs; - diff --git a/tests/RenderScriptTests/ModelViewer/Android.mk b/tests/RenderScriptTests/ModelViewer/Android.mk deleted file mode 100644 index 86724cfc3bde..000000000000 --- a/tests/RenderScriptTests/ModelViewer/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -# -# Copyright (C) 2008 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_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) -#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript - -LOCAL_SDK_VERSION := 17 - -LOCAL_PACKAGE_NAME := ModelViewer - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/ModelViewer/AndroidManifest.xml b/tests/RenderScriptTests/ModelViewer/AndroidManifest.xml deleted file mode 100644 index 57ec4fe74d39..000000000000 --- a/tests/RenderScriptTests/ModelViewer/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.modelviewer"> - <application android:label="ModelViewer"> - <activity android:name="SimpleModel" - android:label="SimpleModel" - android:screenOrientation="nosensor"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - <activity android:name="A3DSelector" - android:label="A3DSelector" - android:hardwareAccelerated="true"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - <activity android:name="SceneGraph" - android:label="SceneGraph" - android:theme="@android:style/Theme.Black.NoTitleBar"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/ModelViewer/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/ModelViewer/res/drawable-nodpi/robot.png Binary files differdeleted file mode 100644 index f7353fd61c5b..000000000000 --- a/tests/RenderScriptTests/ModelViewer/res/drawable-nodpi/robot.png +++ /dev/null diff --git a/tests/RenderScriptTests/ModelViewer/res/menu/loader_menu.xml b/tests/RenderScriptTests/ModelViewer/res/menu/loader_menu.xml deleted file mode 100644 index 2a8759c9d083..000000000000 --- a/tests/RenderScriptTests/ModelViewer/res/menu/loader_menu.xml +++ /dev/null @@ -1,27 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -* Copyright (C) 2011 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. -*/ ---> - -<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/load_model" - android:title="@string/load_model" /> - <item android:id="@+id/display_options" - android:title="@string/display_options" /> - <item android:id="@+id/sensor" - android:title="@string/sensor" /> -</menu> diff --git a/tests/RenderScriptTests/ModelViewer/res/raw/robot.a3d b/tests/RenderScriptTests/ModelViewer/res/raw/robot.a3d Binary files differdeleted file mode 100644 index f48895cd8451..000000000000 --- a/tests/RenderScriptTests/ModelViewer/res/raw/robot.a3d +++ /dev/null diff --git a/tests/RenderScriptTests/ModelViewer/res/values/strings.xml b/tests/RenderScriptTests/ModelViewer/res/values/strings.xml deleted file mode 100644 index a5c8f22e90ad..000000000000 --- a/tests/RenderScriptTests/ModelViewer/res/values/strings.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ ---> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <skip /> - <string name="load_model">Load Model</string> - <string name="display_options">Display Options</string> - <string name="sensor">Toggle Sensor</string> -</resources> diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/A3DSelector.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/A3DSelector.java deleted file mode 100644 index 0e2004f2046f..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/A3DSelector.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2011 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.modelviewer; - -import java.io.File; -import java.io.FileFilter; -import java.util.ArrayList; -import java.util.List; - -import android.app.ListActivity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -/** - * A list view where the last item the user clicked is placed in - * the "activated" state, causing its background to highlight. - */ -public class A3DSelector extends ListActivity { - - File[] mCurrentSubList; - File mCurrentFile; - - class A3DFilter implements FileFilter { - public boolean accept(File file) { - if (file.isDirectory()) { - return true; - } - return file.getName().endsWith(".a3d"); - } - } - - private void populateList(File file) { - - mCurrentFile = file; - setTitle(mCurrentFile.getAbsolutePath() + "/*.a3d"); - List<String> names = new ArrayList<String>(); - names.add(".."); - - mCurrentSubList = mCurrentFile.listFiles(new A3DFilter()); - - if (mCurrentSubList != null) { - for (int i = 0; i < mCurrentSubList.length; i ++) { - String fileName = mCurrentSubList[i].getName(); - if (mCurrentSubList[i].isDirectory()) { - fileName = "/" + fileName; - } - names.add(fileName); - } - } - - // Use the built-in layout for showing a list item with a single - // line of text whose background is changes when activated. - setListAdapter(new ArrayAdapter<String>(this, - android.R.layout.simple_list_item_activated_1, names)); - getListView().setTextFilterEnabled(true); - - // Tell the list view to show one checked/activated item at a time. - getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - populateList(new File("/sdcard/")); - } - - @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - if (position == 0) { - File parent = mCurrentFile.getParentFile(); - if (parent == null) { - return; - } - populateList(parent); - return; - } - - // the first thing in list is parent directory - File selectedFile = mCurrentSubList[position - 1]; - if (selectedFile.isDirectory()) { - populateList(selectedFile); - return; - } - - Intent resultIntent = new Intent(); - resultIntent.setData(Uri.fromFile(selectedFile)); - setResult(RESULT_OK, resultIntent); - finish(); - } - -} diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraph.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraph.java deleted file mode 100644 index c9c4dc1dadc2..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraph.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2008 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.modelviewer; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings.System; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.widget.Button; -import android.widget.ListView; - -import java.lang.Runtime; - -public class SceneGraph extends Activity { - - private SceneGraphView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new SceneGraphView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onPause(); - mView.pause(); - } - -} - diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java deleted file mode 100644 index f91f31ee35e7..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphRS.java +++ /dev/null @@ -1,217 +0,0 @@ -/* - * Copyright (C) 2008 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.modelviewer; - -import java.io.Writer; -import java.util.Map; -import java.util.Vector; - -import android.content.res.Resources; -import android.renderscript.*; -import android.renderscript.Element.Builder; -import android.renderscript.Font.Style; -import android.renderscript.ProgramStore.DepthFunc; -import android.util.Log; - - -public class SceneGraphRS { - - private final int STATE_LAST_FOCUS = 1; - - int mWidth; - int mHeight; - int mRotation; - - public SceneGraphRS() { - } - - public void init(RenderScriptGL rs, Resources res, int width, int height) { - mRS = rs; - mRes = res; - mWidth = width; - mHeight = height; - mRotation = 0; - initRS(); - } - - private Resources mRes; - private RenderScriptGL mRS; - private Sampler mSampler; - private ProgramStore mPSBackground; - private ProgramFragment mPFBackground; - private ProgramVertex mPVBackground; - private ProgramVertexFixedFunction.Constants mPVA; - - private Allocation mGridImage; - private Allocation mAllocPV; - - private Mesh mMesh; - - private Font mItalic; - private Allocation mTextAlloc; - - private ScriptC_scenegraph mScript; - private ScriptC_transform mTransformScript; - - int mLastX; - int mLastY; - - public void touchEvent(int x, int y) { - int dx = mLastX - x; - if (Math.abs(dx) > 50 || Math.abs(dx) < 3) { - dx = 0; - } - - mRotation -= dx; - if (mRotation > 360) { - mRotation -= 360; - } - if (mRotation < 0) { - mRotation += 360; - } - - mScript.set_gRotate(-(float)mRotation); - - mLastX = x; - mLastY = y; - } - - private void initPFS() { - ProgramStore.Builder b = new ProgramStore.Builder(mRS); - - b.setDepthFunc(ProgramStore.DepthFunc.LESS); - b.setDitherEnabled(false); - b.setDepthMaskEnabled(true); - mPSBackground = b.create(); - - mScript.set_gPFSBackground(mPSBackground); - } - - private void initPF() { - Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMinification(Sampler.Value.LINEAR); - bs.setMagnification(Sampler.Value.LINEAR); - bs.setWrapS(Sampler.Value.CLAMP); - bs.setWrapT(Sampler.Value.CLAMP); - mSampler = bs.create(); - - ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); - b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mPFBackground = b.create(); - mPFBackground.bindSampler(mSampler, 0); - - mScript.set_gPFBackground(mPFBackground); - } - - private void initPV() { - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - mPVBackground = pvb.create(); - - mPVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA); - - mScript.set_gPVBackground(mPVBackground); - } - - private void loadImage() { - mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - mScript.set_gTGrid(mGridImage); - } - - private void initTextAllocation() { - String allocString = "Displaying file: R.raw.robot"; - mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT); - mScript.set_gTextAlloc(mTextAlloc); - } - - SgTransform mRootTransform; - SgTransform mGroup1; - - SgTransform mRobot1; - SgTransform mRobot2; - - void initTransformHierarchy() { - mRootTransform = new SgTransform(mRS); - - mGroup1 = new SgTransform(mRS); - mRootTransform.addChild(mGroup1); - - mRobot1 = new SgTransform(mRS); - mRobot2 = new SgTransform(mRS); - - mGroup1.addChild(mRobot1); - mGroup1.addChild(mRobot2); - - mGroup1.setTransform(0, new Float4(0.0f, 0.0f, -15.0f, 0.0f), TransformType.TRANSLATE); - mGroup1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 15.0f), TransformType.ROTATE); - - mRobot1.setTransform(0, new Float4(-3.0f, -0.5f, 0.0f, 0.0f), TransformType.TRANSLATE); - mRobot1.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, 20.0f), TransformType.ROTATE); - mRobot1.setTransform(2, new Float4(0.2f, 0.2f, 0.2f, 0.0f), TransformType.SCALE); - - mRobot2.setTransform(0, new Float4(3.0f, 0.0f, 0.0f, 0.0f), TransformType.TRANSLATE); - mRobot2.setTransform(1, new Float4(0.0f, 1.0f, 0.0f, -20.0f), TransformType.ROTATE); - mRobot2.setTransform(2, new Float4(0.3f, 0.3f, 0.3f, 0.0f), TransformType.SCALE); - } - - private void initRS() { - - mScript = new ScriptC_scenegraph(mRS, mRes, R.raw.scenegraph); - mTransformScript = new ScriptC_transform(mRS, mRes, R.raw.transform); - mTransformScript.set_transformScript(mTransformScript); - - mScript.set_gTransformRS(mTransformScript); - - initPFS(); - initPF(); - initPV(); - - loadImage(); - - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); - FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { - Log.e("rs", "could not load model"); - } else { - mMesh = (Mesh)entry.getObject(); - mScript.set_gTestMesh(mMesh); - } - - mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); - mScript.set_gItalic(mItalic); - - initTextAllocation(); - - initTransformHierarchy(); - - mScript.bind_gRootNode(mRootTransform.getField()); - - mScript.bind_gGroup(mGroup1.mParent.mChildField); - mScript.bind_gRobot1(mRobot1.mParent.mChildField); - mScript.set_gRobot1Index(mRobot1.mIndexInParentGroup); - mScript.bind_gRobot2(mRobot2.mParent.mChildField); - mScript.set_gRobot2Index(mRobot2.mIndexInParentGroup); - - mRS.bindRootScript(mScript); - } -} - - - diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphView.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphView.java deleted file mode 100644 index 0b6a3b863866..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SceneGraphView.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2008 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.modelviewer; - -import java.io.Writer; -import java.util.ArrayList; -import java.util.concurrent.Semaphore; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Message; -import android.util.AttributeSet; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.KeyEvent; -import android.view.MotionEvent; - -public class SceneGraphView extends RSSurfaceView { - - public SceneGraphView(Context context) { - super(context); - //setFocusable(true); - } - - private RenderScriptGL mRS; - private SceneGraphRS mRender; - - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - mRS = createRenderScriptGL(sc); - mRS.setSurface(holder, w, h); - mRender = new SceneGraphRS(); - mRender.init(mRS, getResources(), w, h); - } - } - - @Override - protected void onDetachedFromWindow() { - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) - { - // break point at here - // this method doesn't work when 'extends View' include 'extends ScrollView'. - return super.onKeyDown(keyCode, event); - } - - - @Override - public boolean onTouchEvent(MotionEvent ev) - { - boolean ret = true; - int act = ev.getAction(); - if (act == ev.ACTION_UP) { - ret = false; - } - - mRender.touchEvent((int)ev.getX(), (int)ev.getY()); - return ret; - } -} - - diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SgTransform.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SgTransform.java deleted file mode 100644 index f5484e29c424..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SgTransform.java +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (C) 2008 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.modelviewer; - -import java.io.Writer; -import java.util.Map; -import java.util.Vector; - -import android.content.res.Resources; -import android.renderscript.*; -import android.renderscript.Element.Builder; -import android.renderscript.ProgramStore.DepthFunc; -import android.util.Log; - -enum TransformType { - - NONE(0), - TRANSLATE(1), - ROTATE(2), - SCALE(3); - - int mID; - TransformType(int id) { - mID = id; - } -} - -public class SgTransform { - - - ScriptField_SgTransform mTransformField; - ScriptField_SgTransform mChildField; - public ScriptField_SgTransform.Item mTransformData; - - RenderScript mRS; - - Vector mChildren; - SgTransform mParent; - int mIndexInParentGroup; - - public void setParent(SgTransform parent, int parentIndex) { - mParent = parent; - mIndexInParentGroup = parentIndex; - } - - public void addChild(SgTransform child) { - mChildren.add(child); - child.setParent(this, mChildren.size() - 1); - } - - public void setTransform(int index, Float4 value, TransformType type) { - mTransformData.transforms[index] = value; - mTransformData.transformTypes[index] = type.mID; - } - - void initData() { - int numElements = mTransformData.transforms.length; - mTransformData.transformTypes = new int[numElements]; - for (int i = 0; i < numElements; i ++) { - mTransformData.transforms[i] = new Float4(0, 0, 0, 0); - mTransformData.transformTypes[i] = TransformType.NONE.mID; - } - - mTransformData.isDirty = 1; - mTransformData.children = null; - } - - public SgTransform(RenderScript rs) { - mRS = rs; - mTransformData = new ScriptField_SgTransform.Item(); - mChildren = new Vector(); - initData(); - } - - public ScriptField_SgTransform.Item getData() { - if (mChildren.size() != 0) { - mChildField = new ScriptField_SgTransform(mRS, mChildren.size()); - mTransformData.children = mChildField.getAllocation(); - - for (int i = 0; i < mChildren.size(); i ++) { - SgTransform child = (SgTransform)mChildren.get(i); - mChildField.set(child.getData(), i, false); - } - mChildField.copyAll(); - } - - return mTransformData; - } - - public ScriptField_SgTransform getField() { - mTransformField = new ScriptField_SgTransform(mRS, 1); - mTransformField.set(getData(), 0, true); - return mTransformField; - } -} - - - diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModel.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModel.java deleted file mode 100644 index 2b29ff4400eb..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModel.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2008 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.modelviewer; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.content.res.Configuration; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings.System; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.MenuInflater; -import android.view.Window; -import android.widget.Button; -import android.widget.ListView; -import android.net.Uri; - -import java.lang.Runtime; - -public class SimpleModel extends Activity { - - private SimpleModelView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new SimpleModelView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onPause(); - mView.pause(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.loader_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle item selection - switch (item.getItemId()) { - case R.id.load_model: - loadModel(); - return true; - case R.id.display_options: - return true; - case R.id.sensor: - mView.toggleSensor(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - private static final int FIND_A3D_MODEL = 10; - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK) { - if (requestCode == FIND_A3D_MODEL) { - Uri selectedImageUri = data.getData(); - Log.e("Selected Path: ", selectedImageUri.getPath()); - mView.loadA3DFile(selectedImageUri.getPath()); - } - } - } - - public void loadModel() { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_PICK); - intent.setClassName("com.android.modelviewer", - "com.android.modelviewer.A3DSelector"); - startActivityForResult(intent, FIND_A3D_MODEL); - } - -} - diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java deleted file mode 100644 index 5fa3a9e9a86e..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelRS.java +++ /dev/null @@ -1,187 +0,0 @@ -/* - * Copyright (C) 2011 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.modelviewer; - -import java.io.Writer; - -import android.content.res.Resources; -import android.renderscript.*; -import android.renderscript.ProgramStore.DepthFunc; -import android.util.Log; - - -public class SimpleModelRS { - - public SimpleModelRS() { - } - - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initRS(); - } - - public void surfaceChanged() { - mRS.getWidth(); - mRS.getHeight(); - } - - private Resources mRes; - private RenderScriptGL mRS; - private Sampler mSampler; - private ProgramStore mPSBackground; - private ProgramFragment mPFBackground; - private ProgramVertex mPVBackground; - private ProgramVertexFixedFunction.Constants mPVA; - - private Allocation mGridImage; - private Allocation mAllocPV; - - private Font mItalic; - private Allocation mTextAlloc; - - private ScriptField_MeshInfo mMeshes; - private ScriptC_simplemodel mScript; - - - public void onActionDown(float x, float y) { - mScript.invoke_onActionDown(x, y); - } - - public void onActionScale(float scale) { - mScript.invoke_onActionScale(scale); - } - - public void onActionMove(float x, float y) { - mScript.invoke_onActionMove(x, y); - } - - public void onPostureChanged(Matrix4f posture) { - mScript.set_gPostureMatrix(posture); - } - - private void initPFS() { - ProgramStore.Builder b = new ProgramStore.Builder(mRS); - - b.setDepthFunc(ProgramStore.DepthFunc.LESS); - b.setDitherEnabled(false); - b.setDepthMaskEnabled(true); - mPSBackground = b.create(); - - mScript.set_gPFSBackground(mPSBackground); - } - - private void initPF() { - Sampler.Builder bs = new Sampler.Builder(mRS); - bs.setMinification(Sampler.Value.LINEAR); - bs.setMagnification(Sampler.Value.LINEAR); - bs.setWrapS(Sampler.Value.CLAMP); - bs.setWrapT(Sampler.Value.CLAMP); - mSampler = bs.create(); - - ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); - b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mPFBackground = b.create(); - mPFBackground.bindSampler(mSampler, 0); - - mScript.set_gPFBackground(mPFBackground); - } - - private void initPV() { - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - mPVBackground = pvb.create(); - - mPVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)mPVBackground).bindConstants(mPVA); - - mScript.set_gPVBackground(mPVBackground); - } - - private void loadImage() { - mGridImage = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - mScript.set_gTGrid(mGridImage); - } - - private void initTextAllocation(String fileName) { - String allocString = "Displaying file: " + fileName; - mTextAlloc = Allocation.createFromString(mRS, allocString, Allocation.USAGE_SCRIPT); - mScript.set_gTextAlloc(mTextAlloc); - } - - private void initMeshes(FileA3D model) { - int numEntries = model.getIndexEntryCount(); - int numMeshes = 0; - for (int i = 0; i < numEntries; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - numMeshes ++; - } - } - - if (numMeshes > 0) { - mMeshes = new ScriptField_MeshInfo(mRS, numMeshes); - - for (int i = 0; i < numEntries; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - Mesh mesh = entry.getMesh(); - mMeshes.set_mMesh(i, mesh, false); - mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false); - } - } - mMeshes.copyAll(); - } else { - throw new RSRuntimeException("No valid meshes in file"); - } - - mScript.bind_gMeshes(mMeshes); - mScript.invoke_updateMeshInfo(); - } - - public void loadA3DFile(String path) { - FileA3D model = FileA3D.createFromFile(mRS, path); - initMeshes(model); - initTextAllocation(path); - } - - private void initRS() { - - mScript = new ScriptC_simplemodel(mRS, mRes, R.raw.simplemodel); - - initPFS(); - initPF(); - initPV(); - - loadImage(); - - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); - initMeshes(model); - - mItalic = Font.create(mRS, mRes, "serif", Font.Style.ITALIC, 8); - mScript.set_gItalic(mItalic); - - initTextAllocation("R.raw.robot"); - - mRS.bindRootScript(mScript); - } -} - - - diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelView.java b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelView.java deleted file mode 100644 index 4b7836b002b1..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/SimpleModelView.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (C) 2011 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.modelviewer; - -import android.renderscript.Matrix4f; -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.hardware.Sensor; -import android.hardware.SensorEvent; -import android.hardware.SensorEventListener; -import android.hardware.SensorManager; -import android.view.MotionEvent; -import android.view.SurfaceHolder; -import android.view.ScaleGestureDetector; -import android.util.Log; - -public class SimpleModelView extends RSSurfaceView implements SensorEventListener { - - private RenderScriptGL mRS; - private SimpleModelRS mRender; - - private ScaleGestureDetector mScaleDetector; - - private SensorManager mSensorManager; - private Sensor mRotationVectorSensor; - private final float[] mRotationMatrix = new float[16]; - - private static final int INVALID_POINTER_ID = -1; - private int mActivePointerId = INVALID_POINTER_ID; - private boolean mUseSensor = false; - private Matrix4f mIdentityMatrix = new Matrix4f(); - - public SimpleModelView(Context context) { - super(context); - ensureRenderScript(); - mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); - // Get an instance of the SensorManager - mSensorManager = (SensorManager)getContext().getSystemService(Context.SENSOR_SERVICE); - // find the rotation-vector sensor - mRotationVectorSensor = mSensorManager.getDefaultSensor( - Sensor.TYPE_ROTATION_VECTOR); - mIdentityMatrix.loadIdentity(); - } - - private void ensureRenderScript() { - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - mRS = createRenderScriptGL(sc); - mRender = new SimpleModelRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - public void resume() { - mSensorManager.registerListener(this, mRotationVectorSensor, 10000); - } - - @Override - public void pause() { - mSensorManager.unregisterListener(this); - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ensureRenderScript(); - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - mRender.surfaceChanged(); - } - - @Override - protected void onDetachedFromWindow() { - mRender = null; - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - public void loadA3DFile(String path) { - mRender.loadA3DFile(path); - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - mScaleDetector.onTouchEvent(ev); - - boolean ret = false; - float x = ev.getX(); - float y = ev.getY(); - - final int action = ev.getAction(); - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(0); - ret = true; - break; - } - case MotionEvent.ACTION_MOVE: { - if (!mScaleDetector.isInProgress()) { - mRender.onActionMove(x, y); - } - mRender.onActionDown(x, y); - ret = true; - break; - } - - case MotionEvent.ACTION_UP: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_CANCEL: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_POINTER_UP: { - final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - final int pointerId = ev.getPointerId(pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - x = ev.getX(newPointerIndex); - y = ev.getY(newPointerIndex); - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(newPointerIndex); - } - break; - } - } - - return ret; - } - - private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - @Override - public boolean onScale(ScaleGestureDetector detector) { - mRender.onActionScale(detector.getScaleFactor()); - return true; - } - } - - public void onSensorChanged(SensorEvent event) { - // we received a sensor event. it is a good practice to check - // that we received the proper event - if (mUseSensor) { - if (event.sensor.getType() == Sensor.TYPE_ROTATION_VECTOR) { - // convert the rotation-vector to a 4x4 matrix. the matrix - // is interpreted by Open GL as the inverse of the - // rotation-vector, which is what we want. - SensorManager.getRotationMatrixFromVector( - mRotationMatrix , event.values); - - if (mRender != null) { - mRender.onPostureChanged(new Matrix4f(mRotationMatrix)); - } - } - } - } - - public void onAccuracyChanged(Sensor sensor, int accuracy) { - } - - public void toggleSensor() { - mUseSensor = !mUseSensor; - if (mUseSensor == false) { - mRender.onPostureChanged(mIdentityMatrix); - } - } -} diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs deleted file mode 100644 index 5c5b1c999b68..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/scenegraph.rs +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright (C) 2009 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 version(1) - -#pragma rs java_package_name(com.android.modelviewer) - -#include "rs_graphics.rsh" -#include "transform_def.rsh" - -rs_program_vertex gPVBackground; -rs_program_fragment gPFBackground; - -rs_allocation gTGrid; -rs_mesh gTestMesh; - -rs_program_store gPFSBackground; - -float gRotate; - -rs_font gItalic; -rs_allocation gTextAlloc; - -rs_script gTransformRS; - -SgTransform *gGroup; -SgTransform *gRobot1; -int gRobot1Index; -SgTransform *gRobot2; -int gRobot2Index; - -SgTransform *gRootNode; - -void init() { - gRotate = 0.0f; -} - -int root(void) { - - gGroup->transforms[1].w += 0.5f; - gGroup->isDirty = 1; - - SgTransform *robot1Ptr = gRobot1 + gRobot1Index; - - robot1Ptr->transforms[1].w -= 1.5f; - robot1Ptr->isDirty = 1; - - SgTransform *robot2Ptr = gRobot2 + gRobot2Index; - robot2Ptr->transforms[1].w += 2.5f; - robot2Ptr->isDirty = 1; - - rsForEach(gTransformRS, gRootNode->children, gRootNode->children); - - rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgClearDepth(1.0f); - - rsgBindProgramVertex(gPVBackground); - rs_matrix4x4 proj; - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rsgBindProgramFragment(gPFBackground); - rsgBindProgramStore(gPFSBackground); - rsgBindTexture(gPFBackground, 0, gTGrid); - - rsgProgramVertexLoadModelMatrix(&robot1Ptr->globalMat); - rsgDrawMesh(gTestMesh); - - rsgProgramVertexLoadModelMatrix(&robot2Ptr->globalMat); - rsgDrawMesh(gTestMesh); - - //color(0.3f, 0.3f, 0.3f, 1.0f); - rsgDrawText("Renderscript transform test", 30, 695); - - rsgBindFont(gItalic); - rsgDrawText(gTextAlloc, 30, 730); - - return 10; -} diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs deleted file mode 100644 index d3dd5b9fc8d1..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/simplemodel.rs +++ /dev/null @@ -1,172 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.modelviewer) - -#include "rs_graphics.rsh" - -rs_program_vertex gPVBackground; -rs_program_fragment gPFBackground; - -rs_allocation gTGrid; - -rs_program_store gPFSBackground; - -rs_font gItalic; -rs_allocation gTextAlloc; - -rs_matrix4x4 gPostureMatrix; - -typedef struct MeshInfo { - rs_mesh mMesh; - int mNumIndexSets; - float3 bBoxMin; - float3 bBoxMax; -} MeshInfo_t; - -MeshInfo_t *gMeshes; - -static float3 gLookAt; - -static float gRotateX; -static float gRotateY; -static float gZoom; - -static float gLastX; -static float gLastY; - -static float3 toFloat3(float x, float y, float z) { - float3 f; - f.x = x; - f.y = y; - f.z = z; - return f; -} - -void onActionDown(float x, float y) { - gLastX = x; - gLastY = y; -} - -void onActionScale(float scale) { - - gZoom *= 1.0f / scale; - gZoom = max(0.1f, min(gZoom, 500.0f)); -} - -void onActionMove(float x, float y) { - float dx = gLastX - x; - float dy = gLastY - y; - - if (fabs(dy) <= 2.0f) { - dy = 0.0f; - } - if (fabs(dx) <= 2.0f) { - dx = 0.0f; - } - - gRotateY -= dx; - if (gRotateY > 360) { - gRotateY -= 360; - } - if (gRotateY < 0) { - gRotateY += 360; - } - - gRotateX -= dy; - gRotateX = min(gRotateX, 80.0f); - gRotateX = max(gRotateX, -80.0f); - - gLastX = x; - gLastY = y; -} - -void init() { - gRotateX = 0.0f; - gRotateY = 0.0f; - gZoom = 50.0f; - gLookAt = 0.0f; - rsMatrixLoadIdentity(&gPostureMatrix); -} - -void updateMeshInfo() { - rs_allocation allMeshes = rsGetAllocation(gMeshes); - int size = rsAllocationGetDimX(allMeshes); - gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; - for (int i = 0; i < size; i++) { - MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); - rsgMeshComputeBoundingBox(info->mMesh, - &minX, &minY, &minZ, - &maxX, &maxY, &maxZ); - info->bBoxMin = toFloat3(minX, minY, minZ); - info->bBoxMax = toFloat3(maxX, maxY, maxZ); - gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f; - } - gLookAt = gLookAt / (float)size; -} - -static void renderAllMeshes() { - rs_allocation allMeshes = rsGetAllocation(gMeshes); - int size = rsAllocationGetDimX(allMeshes); - gLookAt = 0.0f; - for (int i = 0; i < size; i++) { - MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); - rsgDrawMesh(info->mMesh); - } -} - -void drawDescription() { - uint height = rsgGetHeight(); - int left = 0, right = 0, top = 0, bottom = 0; - - rsgBindFont(gItalic); - - rsgMeasureText(gTextAlloc, &left, &right, &top, &bottom); - rsgDrawText(gTextAlloc, 2 -left, height - 2 + bottom); -} - -int root(void) { - - rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgClearDepth(1.0f); - - rsgBindProgramVertex(gPVBackground); - rs_matrix4x4 proj; - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rsgBindProgramFragment(gPFBackground); - rsgBindProgramStore(gPFSBackground); - rsgBindTexture(gPFBackground, 0, gTGrid); - - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - // Position our models on the screen - rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom); - rsMatrixMultiply(&matrix, &gPostureMatrix); - rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - - rsgProgramVertexLoadModelMatrix(&matrix); - - renderAllMeshes(); - - drawDescription(); - - return 0; -} diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform.rs b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform.rs deleted file mode 100644 index 85c06306071d..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) 2009 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 version(1) - -#pragma rs java_package_name(com.android.modelviewer) - -#include "transform_def.rsh" - -rs_script transformScript; - -typedef struct { - int changed; - rs_matrix4x4 *mat; -} ParentData; - -static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) { - rs_matrix4x4 temp; - - switch (type) { - case TRANSFORM_TRANSLATE: - rsMatrixLoadTranslate(&temp, data.x, data.y, data.z); - break; - case TRANSFORM_ROTATE: - rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z); - break; - case TRANSFORM_SCALE: - rsMatrixLoadScale(&temp, data.x, data.y, data.z); - break; - } - rsMatrixMultiply(mat, &temp); -} - -void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { - - SgTransform *data = (SgTransform *)v_out; - const ParentData *parent = (const ParentData *)usrData; - - //rsDebug("Transform data", (int)data); - //rsDebug("Entering parent", (int)parent); - - rs_matrix4x4 *localMat = &data->localMat; - rs_matrix4x4 *globalMat = &data->globalMat; - - ParentData toChild; - toChild.changed = 0; - toChild.mat = globalMat; - - //rsDebug("Transform is dirty", data->isDirty); - - // Refresh matrices if dirty - if (data->isDirty) { - data->isDirty = 0; - toChild.changed = 1; - - // Reset our local matrix - rsMatrixLoadIdentity(localMat); - - for (int i = 0; i < 16; i ++) { - if (data->transformTypes[i] == TRANSFORM_NONE) { - break; - } - //rsDebug("Transform adding transformation", transformTypes[i]); - appendTransformation(data->transformTypes[i], data->transforms[i], localMat); - } - } - - //rsDebug("Transform checking parent", (int)0); - - if (parent) { - if (parent->changed) { - toChild.changed = 1; - - rsMatrixLoad(globalMat, parent->mat); - rsMatrixMultiply(globalMat, localMat); - } - } else { - rsMatrixLoad(globalMat, localMat); - } - - //rsDebug("Transform calling self with child ", (int)data->children.p); - if (data->children.p) { - rsForEach(transformScript, data->children, data->children, (void*)&toChild, sizeof(toChild)); - } -} diff --git a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform_def.rsh b/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform_def.rsh deleted file mode 100644 index 24a36c1db28e..000000000000 --- a/tests/RenderScriptTests/ModelViewer/src/com/android/modelviewer/transform_def.rsh +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (C) 2009 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 version(1) - -#pragma rs java_package_name(com.android.modelviewer) - -#define TRANSFORM_NONE 0 -#define TRANSFORM_TRANSLATE 1 -#define TRANSFORM_ROTATE 2 -#define TRANSFORM_SCALE 3 - -typedef struct __attribute__((packed, aligned(4))) SgTransform { - rs_matrix4x4 globalMat; - rs_matrix4x4 localMat; - - float4 transforms[16]; - int transformTypes[16]; - - int isDirty; - - rs_allocation children; - -} SgTransform; diff --git a/tests/RenderScriptTests/PerfTest/Android.mk b/tests/RenderScriptTests/PerfTest/Android.mk deleted file mode 100644 index e9ee771f0c68..000000000000 --- a/tests/RenderScriptTests/PerfTest/Android.mk +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (C) 2008 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_TAGS := tests - -LOCAL_JAVA_LIBRARIES := android.test.runner - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) -#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript - -LOCAL_SDK_VERSION := 17 - -LOCAL_PACKAGE_NAME := PerfTest - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml b/tests/RenderScriptTests/PerfTest/AndroidManifest.xml deleted file mode 100644 index cc6039685736..000000000000 --- a/tests/RenderScriptTests/PerfTest/AndroidManifest.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.perftest"> - - <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> - - <uses-sdk android:minSdkVersion="11" /> - <application android:label="PerfTest" - android:icon="@drawable/test_pattern"> - <uses-library android:name="android.test.runner" /> - <activity android:name="RsBench" - android:label="RsBenchmark"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> - - <instrumentation android:name=".RsPerfTestRunner" - android:targetPackage="com.android.perftest" - android:label="Test runner for RsBench tests" - /> -</manifest> diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/checker.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/checker.png Binary files differdeleted file mode 100644 index b631e1ee4ba6..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/checker.png +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/data.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/data.png Binary files differdeleted file mode 100644 index 8e347146e331..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/data.png +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/flares.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/flares.png Binary files differdeleted file mode 100644 index 3a5c970fc2b9..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/flares.png +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/globe.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/globe.png Binary files differdeleted file mode 100644 index f9d61727cce8..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/globe.png +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/leaf.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/leaf.png Binary files differdeleted file mode 100644 index 3cd37755f549..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/leaf.png +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/light1.jpg b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/light1.jpg Binary files differdeleted file mode 100644 index 2f2f10ee8eb2..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/light1.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/space.jpg b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/space.jpg Binary files differdeleted file mode 100644 index b61f6a3de5dd..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/space.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/test_pattern.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/test_pattern.png Binary files differdeleted file mode 100644 index e7d145554c00..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/test_pattern.png +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/torusmap.png b/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/torusmap.png Binary files differdeleted file mode 100644 index 1e08f3b9ac3e..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/drawable-nodpi/torusmap.png +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml b/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml deleted file mode 100644 index 59a251dbf837..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/menu/loader_menu.xml +++ /dev/null @@ -1,28 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -* Copyright (C) 2011 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. -*/ ---> - -<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/benchmark_all" - android:title="@string/benchmark_all" /> - <item android:id="@+id/benchmark_one" - android:title="@string/benchmark_one" /> - <item android:id="@+id/debug_mode" - android:title="@string/debug_mode" /> -</menu> - diff --git a/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl deleted file mode 100644 index e492a477ff5b..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/multitexf.glsl +++ /dev/null @@ -1,13 +0,0 @@ -varying vec2 varTex0; - -void main() { - vec2 t0 = varTex0.xy; - lowp vec4 col0 = texture2D(UNI_Tex0, t0).rgba; - lowp vec4 col1 = texture2D(UNI_Tex1, t0*4.0).rgba; - lowp vec4 col2 = texture2D(UNI_Tex2, t0).rgba; - col0.xyz = col0.xyz*col1.xyz*1.5; - col0.xyz = mix(col0.xyz, col2.xyz, col2.w); - col0.w = 0.5; - gl_FragColor = col0; -} - diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl deleted file mode 100644 index 5fc05f14a812..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/shader2f.glsl +++ /dev/null @@ -1,29 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -void main() { - - vec3 V = normalize(-varWorldPos.xyz); - vec3 worldNorm = normalize(varWorldNormal); - - vec3 light0Vec = normalize(UNI_light0_Posision.xyz - varWorldPos); - vec3 light0R = -reflect(light0Vec, worldNorm); - float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse; - float light0Spec = clamp(dot(light0R, V), 0.001, 1.0); - float light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular; - - vec3 light1Vec = normalize(UNI_light1_Posision.xyz - varWorldPos); - vec3 light1R = reflect(light1Vec, worldNorm); - float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse; - float light1Spec = clamp(dot(light1R, V), 0.001, 1.0); - float light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular; - - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; - col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz); - col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz; - col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz; - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl deleted file mode 100644 index a2c807e838cc..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/shader2movev.glsl +++ /dev/null @@ -1,21 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -// This is where actual shader code begins -void main() { - vec4 objPos = ATTRIB_position; - vec3 oldPos = objPos.xyz; - objPos.xyz += 0.1*sin(objPos.xyz*2.0 + UNI_time); - objPos.xyz += 0.05*sin(objPos.xyz*4.0 + UNI_time*0.5); - objPos.xyz += 0.02*sin(objPos.xyz*7.0 + UNI_time*0.75); - vec4 worldPos = UNI_model * objPos; - gl_Position = UNI_proj * worldPos; - - mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); - vec3 worldNorm = model3 * (ATTRIB_normal + oldPos - objPos.xyz); - - varWorldPos = worldPos.xyz; - varWorldNormal = worldNorm; - varTex0 = ATTRIB_texture0; -} diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl deleted file mode 100644 index e6885a38aca0..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/shader2v.glsl +++ /dev/null @@ -1,17 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -// This is where actual shader code begins -void main() { - vec4 objPos = ATTRIB_position; - vec4 worldPos = UNI_model * objPos; - gl_Position = UNI_proj * worldPos; - - mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); - vec3 worldNorm = model3 * ATTRIB_normal; - - varWorldPos = worldPos.xyz; - varWorldNormal = worldNorm; - varTex0 = ATTRIB_texture0; -} diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl deleted file mode 100644 index d56e203496c3..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/shaderf.glsl +++ /dev/null @@ -1,16 +0,0 @@ - -varying lowp float light0_Diffuse; -varying lowp float light0_Specular; -varying lowp float light1_Diffuse; -varying lowp float light1_Specular; -varying vec2 varTex0; - -void main() { - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_Tex0, t0).rgba; - col.xyz = col.xyz * (light0_Diffuse * UNI_light0_DiffuseColor.xyz + light1_Diffuse * UNI_light1_DiffuseColor.xyz); - col.xyz += light0_Specular * UNI_light0_SpecularColor.xyz; - col.xyz += light1_Specular * UNI_light1_SpecularColor.xyz; - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl b/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl deleted file mode 100644 index f7d01de384cb..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/shaderv.glsl +++ /dev/null @@ -1,30 +0,0 @@ -varying float light0_Diffuse; -varying float light0_Specular; -varying float light1_Diffuse; -varying float light1_Specular; -varying vec2 varTex0; - -// This is where actual shader code begins -void main() { - vec4 worldPos = UNI_model * ATTRIB_position; - gl_Position = UNI_proj * worldPos; - - mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); - vec3 worldNorm = model3 * ATTRIB_normal; - vec3 V = normalize(-worldPos.xyz); - - vec3 light0Vec = normalize(UNI_light0_Posision.xyz - worldPos.xyz); - vec3 light0R = -reflect(light0Vec, worldNorm); - light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0) * UNI_light0_Diffuse; - float light0Spec = clamp(dot(light0R, V), 0.001, 1.0); - light0_Specular = pow(light0Spec, UNI_light0_CosinePower) * UNI_light0_Specular; - - vec3 light1Vec = normalize(UNI_light1_Posision.xyz - worldPos.xyz); - vec3 light1R = reflect(light1Vec, worldNorm); - light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0) * UNI_light1_Diffuse; - float light1Spec = clamp(dot(light1R, V), 0.001, 1.0); - light1_Specular = pow(light1Spec, UNI_light1_CosinePower) * UNI_light1_Specular; - - gl_PointSize = 1.0; - varTex0 = ATTRIB_texture0; -} diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl deleted file mode 100644 index 83dfc7f4b1f5..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/singletexf.glsl +++ /dev/null @@ -1,8 +0,0 @@ -varying vec2 varTex0; - -void main() { - lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb; - gl_FragColor.xyz = col0; - gl_FragColor.w = 0.5; -} - diff --git a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl b/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl deleted file mode 100644 index 656961c5b2e5..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/singletexfm.glsl +++ /dev/null @@ -1,8 +0,0 @@ -varying vec2 varTex0; - -void main() { - lowp vec3 col0 = texture2D(UNI_Tex0, varTex0).rgb; - gl_FragColor.xyz = col0 * UNI_modulate.rgb; - gl_FragColor.w = UNI_modulate.a; -} - diff --git a/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d b/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d Binary files differdeleted file mode 100644 index 0322b01be8a8..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/raw/torus.a3d +++ /dev/null diff --git a/tests/RenderScriptTests/PerfTest/res/values/strings.xml b/tests/RenderScriptTests/PerfTest/res/values/strings.xml deleted file mode 100644 index ce9819e8d815..000000000000 --- a/tests/RenderScriptTests/PerfTest/res/values/strings.xml +++ /dev/null @@ -1,26 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ ---> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <skip /> - <string name="benchmark_all">Benchmark All</string> - <string name="benchmark_one">Benchmark One</string> - <string name="debug_mode">Debug Mode</string> -</resources> - diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java deleted file mode 100644 index 41f664a0414b..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/FillTest.java +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (C) 2011 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.perftest; - -import android.os.Environment; -import android.content.res.Resources; -import android.renderscript.*; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - - -import android.util.Log; - - -public class FillTest implements RsBenchBaseTest{ - - private static final String TAG = "FillTest"; - private RenderScriptGL mRS; - private Resources mRes; - - // Custom shaders - private ProgramFragment mProgFragmentMultitex; - private ProgramFragment mProgFragmentSingletex; - private ProgramFragment mProgFragmentSingletexModulate; - private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); - int mBenchmarkDimX; - int mBenchmarkDimY; - - private ScriptC_fill_test mFillScript; - ScriptField_TestScripts_s.Item[] mTests; - ScriptField_FillTestFragData_s mFragData; - - private final String[] mNames = { - "Fill screen 10x singletexture", - "Fill screen 10x 3tex multitexture", - "Fill screen 10x blended singletexture", - "Fill screen 10x blended 3tex multitexture", - "Fill screen 3x modulate blended singletexture", - "Fill screen 1x modulate blended singletexture", - }; - - public FillTest() { - mOptionsARGB.inScaled = false; - mOptionsARGB.inPreferredConfig = Bitmap.Config.ARGB_8888; - mBenchmarkDimX = 1280; - mBenchmarkDimY = 720; - } - - void addTest(int index, int testId, int blend, int quadCount) { - mTests[index] = new ScriptField_TestScripts_s.Item(); - mTests[index].testScript = mFillScript; - mTests[index].testName = Allocation.createFromString(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - - ScriptField_FillTestData_s.Item dataItem = new ScriptField_FillTestData_s.Item(); - dataItem.testId = testId; - dataItem.blend = blend; - dataItem.quadCount = quadCount; - ScriptField_FillTestData_s testData = new ScriptField_FillTestData_s(mRS, 1); - testData.set(dataItem, 0, true); - mTests[index].testData = testData.getAllocation(); - } - - public boolean init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initCustomShaders(); - initFillScript(); - mTests = new ScriptField_TestScripts_s.Item[mNames.length]; - - int index = 0; - - addTest(index++, 1 /*testId*/, 0 /*blend*/, 10 /*quadCount*/); - addTest(index++, 0 /*testId*/, 0 /*blend*/, 10 /*quadCount*/); - addTest(index++, 1 /*testId*/, 1 /*blend*/, 10 /*quadCount*/); - addTest(index++, 0 /*testId*/, 1 /*blend*/, 10 /*quadCount*/); - addTest(index++, 2 /*testId*/, 1 /*blend*/, 3 /*quadCount*/); - addTest(index++, 2 /*testId*/, 1 /*blend*/, 1 /*quadCount*/); - - return true; - } - - public ScriptField_TestScripts_s.Item[] getTests() { - return mTests; - } - - public String[] getTestNames() { - return mNames; - } - - private void initCustomShaders() { - ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.multitexf); - for (int texCount = 0; texCount < 3; texCount ++) { - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - } - mProgFragmentMultitex = pfbCustom.create(); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.singletexf); - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - mProgFragmentSingletex = pfbCustom.create(); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.singletexfm); - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - mFragData = new ScriptField_FillTestFragData_s(mRS, 1); - pfbCustom.addConstant(mFragData.getType()); - mProgFragmentSingletexModulate = pfbCustom.create(); - mProgFragmentSingletexModulate.bindConstants(mFragData.getAllocation(), 0); - } - - private Allocation loadTextureARGB(int id) { - Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB); - return Allocation.createFromBitmap(mRS, b, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - private Allocation loadTextureRGB(int id) { - return Allocation.createFromBitmapResource(mRS, mRes, id, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - void initFillScript() { - mFillScript = new ScriptC_fill_test(mRS, mRes, R.raw.fill_test); - - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - ProgramVertexFixedFunction progVertex = pvb.create(); - ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA); - Matrix4f proj = new Matrix4f(); - proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY); - PVA.setProjection(proj); - mFillScript.set_gProgVertex(progVertex); - - mFillScript.set_gProgFragmentTexture(mProgFragmentSingletex); - mFillScript.set_gProgFragmentTextureModulate(mProgFragmentSingletexModulate); - mFillScript.set_gProgFragmentMultitex(mProgFragmentMultitex); - mFillScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS)); - mFillScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS)); - - mFillScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); - mFillScript.set_gLinearWrap(Sampler.WRAP_LINEAR(mRS)); - mFillScript.set_gTexTorus(loadTextureRGB(R.drawable.torusmap)); - mFillScript.set_gTexOpaque(loadTextureRGB(R.drawable.data)); - mFillScript.set_gTexTransparent(loadTextureARGB(R.drawable.leaf)); - mFillScript.set_gTexChecker(loadTextureRGB(R.drawable.checker)); - - mFillScript.bind_gFragData(mFragData); - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java deleted file mode 100644 index cdb443514eb0..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/MeshTest.java +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (C) 2011 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.perftest; - -import android.os.Environment; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.renderscript.*; -import android.renderscript.Element.DataKind; -import android.renderscript.Element.DataType; -import android.renderscript.Allocation.MipmapControl; -import android.renderscript.Program.TextureType; -import android.renderscript.RenderScript.RSMessageHandler; -import android.renderscript.Mesh.Primitive; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramVertexFixedFunction; - -import android.util.Log; - - -public class MeshTest implements RsBenchBaseTest{ - - private static final String TAG = "MeshTest"; - private RenderScriptGL mRS; - private Resources mRes; - - int mBenchmarkDimX; - int mBenchmarkDimY; - - private Mesh m10by10Mesh; - private Mesh m100by100Mesh; - private Mesh mWbyHMesh; - - private ScriptC_mesh_test mGeoScript; - - private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); - - ScriptField_TestScripts_s.Item[] mTests; - - private final String[] mNames = { - "Full screen mesh 10 by 10", - "Full screen mesh 100 by 100", - "Full screen mesh W / 4 by H / 4" - }; - - public MeshTest() { - mBenchmarkDimX = 1280; - mBenchmarkDimY = 720; - } - - void addTest(int index, int meshNum) { - mTests[index] = new ScriptField_TestScripts_s.Item(); - mTests[index].testScript = mGeoScript; - mTests[index].testName = Allocation.createFromString(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - - ScriptField_MeshTestData_s.Item dataItem = new ScriptField_MeshTestData_s.Item(); - dataItem.meshNum = meshNum; - ScriptField_MeshTestData_s testData = new ScriptField_MeshTestData_s(mRS, 1); - testData.set(dataItem, 0, true); - mTests[index].testData = testData.getAllocation(); - } - - public boolean init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initGeoScript(); - mTests = new ScriptField_TestScripts_s.Item[mNames.length]; - - int index = 0; - addTest(index++, 0 /*meshNum*/); - addTest(index++, 1 /*meshNum*/); - addTest(index++, 2 /*meshNum*/); - - return true; - } - - public ScriptField_TestScripts_s.Item[] getTests() { - return mTests; - } - - public String[] getTestNames() { - return mNames; - } - - private Mesh getMbyNMesh(float width, float height, int wResolution, int hResolution) { - - Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, - 2, Mesh.TriangleMeshBuilder.TEXTURE_0); - - for (int y = 0; y <= hResolution; y++) { - final float normalizedY = (float)y / hResolution; - final float yOffset = (normalizedY - 0.5f) * height; - for (int x = 0; x <= wResolution; x++) { - float normalizedX = (float)x / wResolution; - float xOffset = (normalizedX - 0.5f) * width; - tmb.setTexture((float)x % 2, (float)y % 2); - tmb.addVertex(xOffset, yOffset); - } - } - - for (int y = 0; y < hResolution; y++) { - final int curY = y * (wResolution + 1); - final int belowY = (y + 1) * (wResolution + 1); - for (int x = 0; x < wResolution; x++) { - int curV = curY + x; - int belowV = belowY + x; - tmb.addTriangle(curV, belowV, curV + 1); - tmb.addTriangle(belowV, belowV + 1, curV + 1); - } - } - - return tmb.create(true); - } - - private Allocation loadTextureRGB(int id) { - return Allocation.createFromBitmapResource(mRS, mRes, id, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - void initGeoScript() { - mGeoScript = new ScriptC_mesh_test(mRS, mRes, R.raw.mesh_test); - - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - ProgramVertexFixedFunction progVertex = pvb.create(); - ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA); - Matrix4f proj = new Matrix4f(); - proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY); - PVA.setProjection(proj); - - mGeoScript.set_gProgVertex(progVertex); - ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mGeoScript.set_gProgFragmentTexture(texBuilder.create()); - mGeoScript.set_gProgStoreBlendNone(ProgramStore.BLEND_NONE_DEPTH_NONE(mRS)); - - mGeoScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); - mGeoScript.set_gTexOpaque(loadTextureRGB(R.drawable.data)); - - m10by10Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 10, 10); - m100by100Mesh = getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, 100, 100); - mWbyHMesh= getMbyNMesh(mBenchmarkDimX, mBenchmarkDimY, mBenchmarkDimX/4, mBenchmarkDimY/4); - - mGeoScript.set_g10by10Mesh(m10by10Mesh); - mGeoScript.set_g100by100Mesh(m100by100Mesh); - mGeoScript.set_gWbyHMesh(mWbyHMesh); - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java deleted file mode 100644 index 0dceafe73520..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBench.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (C) 2008 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.perftest; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.content.res.Configuration; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings.System; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.MenuInflater; -import android.view.View; -import android.view.Window; -import android.widget.Button; -import android.widget.ListView; -import android.app.AlertDialog; -import android.content.DialogInterface; -import android.widget.Toast; - -import java.lang.Runtime; - -public class RsBench extends Activity { - private final String TAG = "RsBench"; - public RsBenchView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - int iterations = 0; - Intent intent = getIntent(); - Uri uri = intent.getData(); - if (uri != null) { - // when lauched from instrumentation - String scheme = uri.getScheme(); - if ("iterations".equals(scheme)) { - iterations = Integer.parseInt(uri.getSchemeSpecificPart()); - } - } - // Create our Preview view and set it as the content of our - // Activity - mView = new RsBenchView(this); - setContentView(mView); - mView.setLoops(iterations); - } - - @Override - protected void onResume() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity loses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity loses focus - super.onPause(); - mView.pause(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.loader_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle item selection - switch (item.getItemId()) { - case R.id.benchmark_all: - mView.setBenchmarkMode(-1); - mView.suspendRendering(false); - return true; - case R.id.benchmark_one: - mView.suspendRendering(true); - AlertDialog.Builder builder = new AlertDialog.Builder(this); - builder.setTitle("Pick a Test"); - builder.setItems(mView.getTestNames(), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - Toast.makeText(getApplicationContext(), - "Starting to benchmark: " + mView.getTestNames()[item], - Toast.LENGTH_SHORT).show(); - mView.setBenchmarkMode(item); - mView.suspendRendering(false); - } - }); - builder.show(); - return true; - case R.id.debug_mode: - mView.suspendRendering(true); - AlertDialog.Builder debugBuilder = new AlertDialog.Builder(this); - debugBuilder.setTitle("Pick a Test"); - debugBuilder.setItems(mView.getTestNames(), - new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int item) { - Toast.makeText(getApplicationContext(), - "Switching to: " + mView.getTestNames()[item], - Toast.LENGTH_SHORT).show(); - mView.setDebugMode(item); - mView.suspendRendering(false); - } - }); - debugBuilder.show(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java deleted file mode 100644 index 4ac7dd5a9b70..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchRS.java +++ /dev/null @@ -1,328 +0,0 @@ -/* - * Copyright (C) 2010-2011 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.perftest; - -import java.io.Writer; -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.io.File; -import java.io.FileOutputStream; -import java.io.OutputStream; - -import android.os.Environment; -import android.content.res.Resources; -import android.renderscript.*; -import android.renderscript.Element.DataKind; -import android.renderscript.Element.DataType; -import android.renderscript.Allocation.MipmapControl; -import android.renderscript.Program.TextureType; -import android.renderscript.RenderScript.RSMessageHandler; -import android.renderscript.Sampler.Value; -import android.renderscript.Mesh.Primitive; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramVertexFixedFunction; - -import android.util.Log; - - -public class RsBenchRS { - - private static final String TAG = "RsBenchRS"; - int mWidth; - int mHeight; - int mLoops; - int mCurrentLoop; - - int mBenchmarkDimX; - int mBenchmarkDimY; - - public RsBenchRS() { - } - - public void init(RenderScriptGL rs, Resources res, int width, int height, int loops) { - mRS = rs; - mRes = res; - mWidth = width; - mHeight = height; - mMode = 0; - mLoops = loops; - mCurrentLoop = 0; - mBenchmarkDimX = 1280; - mBenchmarkDimY = 720; - initRS(); - } - - private boolean stopTest = false; - - private Resources mRes; - private RenderScriptGL mRS; - - private ProgramStore mProgStoreBlendNone; - private ProgramStore mProgStoreBlendAlpha; - - private ProgramFragment mProgFragmentTexture; - private ProgramFragment mProgFragmentColor; - - private ProgramVertex mProgVertex; - private ProgramVertexFixedFunction.Constants mPVA; - private ProgramVertexFixedFunction.Constants mPvProjectionAlloc; - - private ScriptC_rsbench mScript; - - ScriptField_TestScripts_s.Item[] mIndividualTests; - - int mMode; - - String[] mTestNames; - float[] mLocalTestResults; - - static Allocation createZeroTerminatedAlloc(RenderScript rs, - String str, - int usage) { - byte[] allocArray = null; - try { - allocArray = str.getBytes("UTF-8"); - byte[] allocArrayZero = new byte[allocArray.length + 1]; - System.arraycopy(allocArray, 0, allocArrayZero, 0, allocArray.length); - allocArrayZero[allocArrayZero.length - 1] = '\0'; - Allocation alloc = Allocation.createSized(rs, Element.U8(rs), - allocArrayZero.length, usage); - alloc.copyFrom(allocArrayZero); - return alloc; - } - catch (Exception e) { - throw new RSRuntimeException("Could not convert string to utf-8."); - } - - } - - void appendTests(RsBenchBaseTest testSet) { - ScriptField_TestScripts_s.Item[] newTests = testSet.getTests(); - if (mIndividualTests != null) { - ScriptField_TestScripts_s.Item[] combined; - combined = new ScriptField_TestScripts_s.Item[newTests.length + mIndividualTests.length]; - System.arraycopy(mIndividualTests, 0, combined, 0, mIndividualTests.length); - System.arraycopy(newTests, 0, combined, mIndividualTests.length, newTests.length); - mIndividualTests = combined; - } else { - mIndividualTests = newTests; - } - - String[] newNames = testSet.getTestNames(); - if (mTestNames != null) { - String[] combinedNames; - combinedNames = new String[newNames.length + mTestNames.length]; - System.arraycopy(mTestNames, 0, combinedNames, 0, mTestNames.length); - System.arraycopy(newNames, 0, combinedNames, mTestNames.length, newNames.length); - mTestNames = combinedNames; - } else { - mTestNames = newNames; - } - } - - void createTestAllocation() { - int numTests = mIndividualTests.length; - mLocalTestResults = new float[numTests]; - ScriptField_TestScripts_s allTests; - allTests = new ScriptField_TestScripts_s(mRS, numTests); - for (int i = 0; i < numTests; i ++) { - allTests.set(mIndividualTests[i], i, false); - } - allTests.copyAll(); - mScript.bind_gTestScripts(allTests); - } - - private void saveTestResults() { - String state = Environment.getExternalStorageState(); - if (!Environment.MEDIA_MOUNTED.equals(state)) { - Log.v(TAG, "sdcard is read only"); - return; - } - File sdCard = Environment.getExternalStorageDirectory(); - if (!sdCard.canWrite()) { - Log.v(TAG, "ssdcard is read only"); - return; - } - - File resultFile = new File(sdCard, "rsbench_result" + mCurrentLoop + ".csv"); - resultFile.setWritable(true, false); - - try { - BufferedWriter results = new BufferedWriter(new FileWriter(resultFile)); - for (int i = 0; i < mLocalTestResults.length; i ++) { - results.write(mTestNames[i] + ", " + mLocalTestResults[i] + ",\n"); - } - results.close(); - Log.v(TAG, "Saved results in: " + resultFile.getAbsolutePath()); - } catch (IOException e) { - Log.v(TAG, "Unable to write result file " + e.getMessage()); - } - } - - /** - * Create a message handler to handle message sent from the script - */ - protected RSMessageHandler mRsMessage = new RSMessageHandler() { - public void run() { - if (mID == mScript.get_RS_MSG_RESULTS_READY()) { - for (int i = 0; i < mLocalTestResults.length; i ++) { - mLocalTestResults[i] = Float.intBitsToFloat(mData[i]); - } - saveTestResults(); - if (mLoops > 0) { - mCurrentLoop ++; - mCurrentLoop = mCurrentLoop % mLoops; - } - return; - - } else if (mID == mScript.get_RS_MSG_TEST_DONE()) { - synchronized(this) { - stopTest = true; - this.notifyAll(); - } - return; - } else { - Log.v(TAG, "Perf test got unexpected message"); - return; - } - } - }; - - /** - * Wait for message from the script - */ - public boolean testIsFinished() { - synchronized(this) { - while (true) { - if (stopTest) { - return true; - } else { - try { - this.wait(60*1000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - } - } - - private void initProgramFragment() { - - ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mProgFragmentTexture = texBuilder.create(); - mProgFragmentTexture.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); - - ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - colBuilder.setVaryingColor(false); - mProgFragmentColor = colBuilder.create(); - - mScript.set_gProgFragmentTexture(mProgFragmentTexture); - } - - private void initProgramVertex() { - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - mProgVertex = pvb.create(); - - mPVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)mProgVertex).bindConstants(mPVA); - Matrix4f proj = new Matrix4f(); - proj.loadOrthoWindow(mBenchmarkDimX, mBenchmarkDimY); - mPVA.setProjection(proj); - - mScript.set_gProgVertex(mProgVertex); - } - - private int strlen(byte[] array) { - int count = 0; - while(count < array.length && array[count] != 0) { - count ++; - } - return count; - } - - public void setDebugMode(int num) { - mScript.invoke_setDebugMode(num); - } - - public void setBenchmarkMode(int benchNum) { - mScript.invoke_setBenchmarkMode(benchNum); - } - - public void pause(boolean pause) { - mScript.set_gPauseRendering(pause); - } - - private void initRS() { - - mScript = new ScriptC_rsbench(mRS, mRes, R.raw.rsbench); - mRS.bindRootScript(mScript); - - mRS.setMessageHandler(mRsMessage); - - mScript.set_gMaxLoops(mLoops); - - initProgramVertex(); - initProgramFragment(); - mScript.set_gFontSerif(Font.create(mRS, mRes, "serif", Font.Style.NORMAL, 8)); - - Type.Builder b = new Type.Builder(mRS, Element.RGBA_8888(mRS)); - b.setX(mBenchmarkDimX).setY(mBenchmarkDimY); - Allocation offscreen = Allocation.createTyped(mRS, - b.create(), - Allocation.USAGE_GRAPHICS_TEXTURE | - Allocation.USAGE_GRAPHICS_RENDER_TARGET); - mScript.set_gRenderBufferColor(offscreen); - - b = new Type.Builder(mRS, - Element.createPixel(mRS, DataType.UNSIGNED_16, - DataKind.PIXEL_DEPTH)); - b.setX(mBenchmarkDimX).setY(mBenchmarkDimY); - offscreen = Allocation.createTyped(mRS, - b.create(), - Allocation.USAGE_GRAPHICS_RENDER_TARGET); - mScript.set_gRenderBufferDepth(offscreen); - mScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); - - RsBenchBaseTest test = new TextTest(); - if (test.init(mRS, mRes)) { - appendTests(test); - } - test = new FillTest(); - if (test.init(mRS, mRes)) { - appendTests(test); - } - test = new MeshTest(); - if (test.init(mRS, mRes)) { - appendTests(test); - } - test = new TorusTest(); - if (test.init(mRS, mRes)) { - appendTests(test); - } - test = new UiTest(); - if (test.init(mRS, mRes)) { - appendTests(test); - } - createTestAllocation(); - - mScript.set_gLoadComplete(true); - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchTest.java deleted file mode 100644 index 199200b71b5f..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2011 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.perftest; - -import android.app.Instrumentation; -import android.content.Context; -import android.content.Intent; -import android.net.Uri; -import android.test.ActivityInstrumentationTestCase2; -import android.test.TouchUtils; -import android.test.suitebuilder.annotation.LargeTest; -import android.util.Log; - -/** - * To run the test, please use command - * - * adb shell am instrument -w com.android.perftest/.RsPerfTestRunner - * - */ -public class RsBenchTest extends ActivityInstrumentationTestCase2<RsBench> { - private String TAG = "RsBenchTest"; - private int iterations = 0; - private RsBench mAct; - - public RsBenchTest() { - super(RsBench.class); - } - - @Override - public void setUp() throws Exception { - super.setUp(); - Instrumentation mInst = getInstrumentation(); - RsPerfTestRunner mRunner = (RsPerfTestRunner) getInstrumentation(); - iterations = mRunner.iterations; - Log.v(TAG, "Run benchmark for " + iterations + " iterations."); - - Uri data = Uri.fromParts("iterations", Integer.toString(iterations), null); - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - intent.setClassName("com.android.perftest", "com.android.perftest.RsBench"); - intent.setData(data); - mAct = (RsBench) mInst.startActivitySync(intent); - mInst.waitForIdleSync(); - - } - - @Override - public void tearDown() throws Exception { - mAct.finish(); - super.tearDown(); - } - - /** - * Run tests and wait until the test has been run for iterations. - */ - @LargeTest - public void testRsBench() { - if (mAct.mView.testIsFinished()) { - return; - } else { - fail("test didn't stop correctly"); - } - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java deleted file mode 100644 index 124071e59590..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchView.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2008 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.perftest; - -import java.io.Writer; -import java.util.ArrayList; -import java.util.concurrent.Semaphore; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; -import android.renderscript.RenderScriptGL; -import android.renderscript.RenderScript.RSMessageHandler; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Message; -import android.util.AttributeSet; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.KeyEvent; -import android.view.MotionEvent; - -public class RsBenchView extends RSSurfaceView { - - public RsBenchView(Context context) { - super(context); - } - - private RenderScriptGL mRS; - private RsBenchRS mRender; - private int mLoops = 0; - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - mRS = createRenderScriptGL(sc); - mRS.setSurface(holder, w, h); - mRender = new RsBenchRS(); - Log.v("RsBenchView", "mLoops = " + mLoops); - mRender.init(mRS, getResources(), w, h, mLoops); - } - } - - @Override - protected void onDetachedFromWindow() { - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - /** - * Set the total number of loops the benchmark tests will run - * before the test results are collected. - */ - public void setLoops(int iterations) { - if (iterations > 0) { - mLoops = iterations; - } - } - - /** - * Wait for message from the script - */ - public boolean testIsFinished() { - return mRender.testIsFinished(); - } - - void setBenchmarkMode(int benchNum) { - mRender.setBenchmarkMode(benchNum); - } - - void suspendRendering(boolean pause) { - mRender.pause(pause); - } - - void setDebugMode(int num) { - mRender.setDebugMode(num); - } - - String[] getTestNames() { - return mRender.mTestNames; - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsPerfTestRunner.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsPerfTestRunner.java deleted file mode 100644 index 031af6a08c10..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsPerfTestRunner.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2011 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.perftest; - -//import com.android.perftest.RsBenchTest; - -import android.os.Bundle; -import android.test.InstrumentationTestRunner; -import android.test.InstrumentationTestSuite; - -import junit.framework.TestSuite; - -/** - * Run the RenderScript Performance Test - * adb shell am instrument -w com.android.perftest/.RsPerfTestRunner - * - * with specified iterations: - * adb shell am instrument -e iterations <n> -w com.android.perftest/.RsPerfTestRunner - * - */ -public class RsPerfTestRunner extends InstrumentationTestRunner { - public int iterations = 10; - - @Override - public TestSuite getAllTests() { - TestSuite suite = new InstrumentationTestSuite(this); - suite.addTestSuite(RsBenchTest.class); - return suite; - } - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - String strValue = (String)icicle.get("iterations"); - if (strValue != null) { - int intValue = Integer.parseInt(strValue); - if (iterations > 0) { - iterations = intValue; - } - } - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java deleted file mode 100644 index 3ca279280e06..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TextTest.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright (C) 2011 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.perftest; - -import android.os.Environment; -import android.content.res.Resources; -import android.renderscript.*; -import android.util.DisplayMetrics; - -import android.util.Log; - - -public class TextTest implements RsBenchBaseTest{ - - private static final String TAG = "TextTest"; - private RenderScriptGL mRS; - private Resources mRes; - - private ScriptC_text_test mTextScript; - ScriptField_TestScripts_s.Item[] mTests; - - private final String[] mNames = { - "Fill screen with text 1 time", - "Fill screen with text 3 times", - "Fill screen with text 5 times" - }; - - public TextTest() { - } - - void addTest(int index, int fillNum) { - mTests[index] = new ScriptField_TestScripts_s.Item(); - mTests[index].testScript = mTextScript; - mTests[index].testName = Allocation.createFromString(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - - ScriptField_TextTestData_s.Item dataItem = new ScriptField_TextTestData_s.Item(); - dataItem.fillNum = fillNum; - ScriptField_TextTestData_s testData = new ScriptField_TextTestData_s(mRS, 1); - testData.set(dataItem, 0, true); - mTests[index].testData = testData.getAllocation(); - } - - public boolean init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initTextScript(); - mTests = new ScriptField_TestScripts_s.Item[mNames.length]; - - int index = 0; - addTest(index++, 1 /*fillNum*/); - addTest(index++, 3 /*fillNum*/); - addTest(index++, 5 /*fillNum*/); - - return true; - } - - public ScriptField_TestScripts_s.Item[] getTests() { - return mTests; - } - - public String[] getTestNames() { - return mNames; - } - - void initTextScript() { - DisplayMetrics metrics = mRes.getDisplayMetrics(); - - mTextScript = new ScriptC_text_test(mRS, mRes, R.raw.text_test); - mTextScript.set_gFontSans(Font.create(mRS, mRes, "sans-serif", - Font.Style.NORMAL, 8.0f / metrics.density)); - mTextScript.set_gFontSerif(Font.create(mRS, mRes, "serif", - Font.Style.NORMAL, 8.0f / metrics.density)); - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java deleted file mode 100644 index 5c9ecd5048dd..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/TorusTest.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2011 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.perftest; - -import android.os.Environment; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.renderscript.*; -import android.renderscript.Element.DataKind; -import android.renderscript.Element.DataType; -import android.renderscript.Allocation.MipmapControl; -import android.renderscript.Program.TextureType; -import android.renderscript.RenderScript.RSMessageHandler; -import android.renderscript.Mesh.Primitive; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramVertexFixedFunction; - -import android.util.Log; - - -public class TorusTest implements RsBenchBaseTest{ - - private static final String TAG = "TorusTest"; - private RenderScriptGL mRS; - private Resources mRes; - - private ProgramStore mProgStoreBlendNoneDepth; - private ProgramStore mProgStoreBlendNone; - private ProgramStore mProgStoreBlendAlpha; - - private ProgramFragment mProgFragmentTexture; - private ProgramFragment mProgFragmentColor; - - private ProgramVertex mProgVertex; - private ProgramVertexFixedFunction.Constants mPVA; - private ProgramVertexFixedFunction.Constants mPvProjectionAlloc; - - // Custom shaders - private ProgramVertex mProgVertexCustom; - private ProgramFragment mProgFragmentCustom; - private ProgramFragment mProgFragmentMultitex; - private ProgramVertex mProgVertexPixelLight; - private ProgramVertex mProgVertexPixelLightMove; - private ProgramFragment mProgFragmentPixelLight; - private ScriptField_VertexShaderConstants_s mVSConst; - private ScriptField_FragentShaderConstants_s mFSConst; - private ScriptField_VertexShaderConstants3_s mVSConstPixel; - private ScriptField_FragentShaderConstants3_s mFSConstPixel; - - private Allocation mTexTorus; - private Mesh mTorus; - - private ScriptC_torus_test mTorusScript; - - private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); - - ScriptField_TestScripts_s.Item[] mTests; - - private final String[] mNames = { - "Geo test 25.6k flat color", - "Geo test 51.2k flat color", - "Geo test 204.8k small tries flat color", - "Geo test 25.6k single texture", - "Geo test 51.2k single texture", - "Geo test 204.8k small tries single texture", - "Geo test 25.6k geo heavy vertex", - "Geo test 51.2k geo heavy vertex", - "Geo test 204.8k geo raster load heavy vertex", - "Geo test 25.6k heavy fragment", - "Geo test 51.2k heavy fragment", - "Geo test 204.8k small tries heavy fragment", - "Geo test 25.6k heavy fragment heavy vertex", - "Geo test 51.2k heavy fragment heavy vertex", - "Geo test 204.8k small tries heavy fragment heavy vertex" - }; - - public TorusTest() { - } - - void addTest(int index, int testId, int user1, int user2) { - mTests[index] = new ScriptField_TestScripts_s.Item(); - mTests[index].testScript = mTorusScript; - mTests[index].testName = Allocation.createFromString(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - - ScriptField_TorusTestData_s.Item dataItem = new ScriptField_TorusTestData_s.Item(); - dataItem.testId = testId; - dataItem.user1 = user1; - dataItem.user2 = user2; - ScriptField_TorusTestData_s testData = new ScriptField_TorusTestData_s(mRS, 1); - testData.set(dataItem, 0, true); - mTests[index].testData = testData.getAllocation(); - } - - public boolean init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initCustomShaders(); - loadImages(); - initMesh(); - initTorusScript(); - mTests = new ScriptField_TestScripts_s.Item[mNames.length]; - - int index = 0; - addTest(index++, 0, 0 /*useTexture*/, 1 /*numMeshes*/); - addTest(index++, 0, 0 /*useTexture*/, 2 /*numMeshes*/); - addTest(index++, 0, 0 /*useTexture*/, 8 /*numMeshes*/); - addTest(index++, 0, 1 /*useTexture*/, 1 /*numMeshes*/); - addTest(index++, 0, 1 /*useTexture*/, 2 /*numMeshes*/); - addTest(index++, 0, 1 /*useTexture*/, 8 /*numMeshes*/); - - // Secont test - addTest(index++, 1, 1 /*numMeshes*/, 0 /*unused*/); - addTest(index++, 1, 2 /*numMeshes*/, 0 /*unused*/); - addTest(index++, 1, 8 /*numMeshes*/, 0 /*unused*/); - - // Third test - addTest(index++, 2, 1 /*numMeshes*/, 0 /*heavyVertex*/); - addTest(index++, 2, 2 /*numMeshes*/, 0 /*heavyVertex*/); - addTest(index++, 2, 8 /*numMeshes*/, 0 /*heavyVertex*/); - addTest(index++, 2, 1 /*numMeshes*/, 1 /*heavyVertex*/); - addTest(index++, 2, 2 /*numMeshes*/, 1 /*heavyVertex*/); - addTest(index++, 2, 8 /*numMeshes*/, 1 /*heavyVertex*/); - - return true; - } - - public ScriptField_TestScripts_s.Item[] getTests() { - return mTests; - } - - public String[] getTestNames() { - return mNames; - } - - private void initCustomShaders() { - mVSConst = new ScriptField_VertexShaderConstants_s(mRS, 1); - mFSConst = new ScriptField_FragentShaderConstants_s(mRS, 1); - - mVSConstPixel = new ScriptField_VertexShaderConstants3_s(mRS, 1); - mFSConstPixel = new ScriptField_FragentShaderConstants3_s(mRS, 1); - - // Initialize the shader builder - ProgramVertex.Builder pvbCustom = new ProgramVertex.Builder(mRS); - // Specify the resource that contains the shader string - pvbCustom.setShader(mRes, R.raw.shaderv); - // Use a script field to specify the input layout - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - // Define the constant input layout - pvbCustom.addConstant(mVSConst.getAllocation().getType()); - mProgVertexCustom = pvbCustom.create(); - // Bind the source of constant data - mProgVertexCustom.bindConstants(mVSConst.getAllocation(), 0); - - ProgramFragment.Builder pfbCustom = new ProgramFragment.Builder(mRS); - // Specify the resource that contains the shader string - pfbCustom.setShader(mRes, R.raw.shaderf); - // Tell the builder how many textures we have - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - // Define the constant input layout - pfbCustom.addConstant(mFSConst.getAllocation().getType()); - mProgFragmentCustom = pfbCustom.create(); - // Bind the source of constant data - mProgFragmentCustom.bindConstants(mFSConst.getAllocation(), 0); - - pvbCustom = new ProgramVertex.Builder(mRS); - pvbCustom.setShader(mRes, R.raw.shader2v); - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - pvbCustom.addConstant(mVSConstPixel.getAllocation().getType()); - mProgVertexPixelLight = pvbCustom.create(); - mProgVertexPixelLight.bindConstants(mVSConstPixel.getAllocation(), 0); - - pvbCustom = new ProgramVertex.Builder(mRS); - pvbCustom.setShader(mRes, R.raw.shader2movev); - pvbCustom.addInput(ScriptField_VertexShaderInputs_s.createElement(mRS)); - pvbCustom.addConstant(mVSConstPixel.getAllocation().getType()); - mProgVertexPixelLightMove = pvbCustom.create(); - mProgVertexPixelLightMove.bindConstants(mVSConstPixel.getAllocation(), 0); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.shader2f); - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - pfbCustom.addConstant(mFSConstPixel.getAllocation().getType()); - mProgFragmentPixelLight = pfbCustom.create(); - mProgFragmentPixelLight.bindConstants(mFSConstPixel.getAllocation(), 0); - - pfbCustom = new ProgramFragment.Builder(mRS); - pfbCustom.setShader(mRes, R.raw.multitexf); - for (int texCount = 0; texCount < 3; texCount ++) { - pfbCustom.addTexture(Program.TextureType.TEXTURE_2D); - } - mProgFragmentMultitex = pfbCustom.create(); - - ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - colBuilder.setVaryingColor(false); - mProgFragmentColor = colBuilder.create(); - - ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mProgFragmentTexture = texBuilder.create(); - - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - mProgVertex = pvb.create(); - ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)mProgVertex).bindConstants(PVA); - Matrix4f proj = new Matrix4f(); - proj.loadOrthoWindow(1280, 720); - PVA.setProjection(proj); - } - - private Allocation loadTextureRGB(int id) { - return Allocation.createFromBitmapResource(mRS, mRes, id, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - private void loadImages() { - mTexTorus = loadTextureRGB(R.drawable.torusmap); - } - - private void initMesh() { - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.torus); - FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { - Log.e("rs", "could not load model"); - } else { - mTorus = (Mesh)entry.getObject(); - } - } - - void initTorusScript() { - mTorusScript = new ScriptC_torus_test(mRS, mRes, R.raw.torus_test); - mTorusScript.set_gCullFront(ProgramRaster.CULL_FRONT(mRS)); - mTorusScript.set_gCullBack(ProgramRaster.CULL_BACK(mRS)); - mTorusScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); - mTorusScript.set_gTorusMesh(mTorus); - mTorusScript.set_gTexTorus(mTexTorus); - mTorusScript.set_gProgVertexCustom(mProgVertexCustom); - mTorusScript.set_gProgFragmentCustom(mProgFragmentCustom); - mTorusScript.set_gProgVertexPixelLight(mProgVertexPixelLight); - mTorusScript.set_gProgVertexPixelLightMove(mProgVertexPixelLightMove); - mTorusScript.set_gProgFragmentPixelLight(mProgFragmentPixelLight); - mTorusScript.bind_gVSConstPixel(mVSConstPixel); - mTorusScript.bind_gFSConstPixel(mFSConstPixel); - mTorusScript.bind_gVSConstants(mVSConst); - mTorusScript.bind_gFSConstants(mFSConst); - mTorusScript.set_gProgVertex(mProgVertex); - mTorusScript.set_gProgFragmentTexture(mProgFragmentTexture); - mTorusScript.set_gProgFragmentColor(mProgFragmentColor); - mTorusScript.set_gProgStoreBlendNoneDepth(mProgStoreBlendNoneDepth); - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java deleted file mode 100644 index c8b58b29f63f..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/UiTest.java +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (C) 2011 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.perftest; - -import android.os.Environment; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.renderscript.*; -import android.renderscript.Element.DataKind; -import android.renderscript.Element.DataType; -import android.renderscript.Allocation.MipmapControl; -import android.renderscript.Program.TextureType; -import android.renderscript.ProgramStore.DepthFunc; -import android.renderscript.ProgramStore.BlendSrcFunc; -import android.renderscript.ProgramStore.BlendDstFunc; -import android.renderscript.RenderScript.RSMessageHandler; -import android.renderscript.Mesh.Primitive; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramVertexFixedFunction; - -import android.util.Log; - - -public class UiTest implements RsBenchBaseTest{ - - private static final String TAG = "UiTest"; - private static final String SAMPLE_TEXT = "Bench Test"; - private static final String LIST_TEXT = - "This is a sample list of text to show in the list view"; - private static int PARTICLES_COUNT = 12000; - - private RenderScriptGL mRS; - private Resources mRes; - - Font mFontSans; - - private ScriptField_ListAllocs_s mTextureAllocs; - private ScriptField_ListAllocs_s mSampleTextAllocs; - private ScriptField_ListAllocs_s mSampleListViewAllocs; - private ScriptField_VpConsts mPvStarAlloc; - private ProgramVertexFixedFunction.Constants mPvProjectionAlloc; - - private Mesh mSingleMesh; - private Mesh mParticlesMesh; - - private ScriptC_ui_test mUiScript; - - private final BitmapFactory.Options mOptionsARGB = new BitmapFactory.Options(); - - ScriptField_TestScripts_s.Item[] mTests; - - private final String[] mNames = { - "UI test with icon display 10 by 10", - "UI test with icon display 100 by 100", - "UI test with image and text display 3 pages", - "UI test with image and text display 5 pages", - "UI test with list view", - "UI test with live wallpaper" - }; - - public UiTest() { - } - - void addTest(int index, int testId, int user1, int user2, int user3) { - mTests[index] = new ScriptField_TestScripts_s.Item(); - mTests[index].testScript = mUiScript; - mTests[index].testName = Allocation.createFromString(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - mTests[index].debugName = RsBenchRS.createZeroTerminatedAlloc(mRS, - mNames[index], - Allocation.USAGE_SCRIPT); - - ScriptField_UiTestData_s.Item dataItem = new ScriptField_UiTestData_s.Item(); - dataItem.testId = testId; - dataItem.user1 = user1; - dataItem.user2 = user2; - dataItem.user3 = user3; - ScriptField_UiTestData_s testData = new ScriptField_UiTestData_s(mRS, 1); - testData.set(dataItem, 0, true); - mTests[index].testData = testData.getAllocation(); - } - - public boolean init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - mFontSans = Font.create(mRS, mRes, "sans-serif", Font.Style.NORMAL, 8); - mSingleMesh = getSingleMesh(1, 1); // a unit size mesh - - initUiScript(); - mTests = new ScriptField_TestScripts_s.Item[mNames.length]; - - int index = 0; - - addTest(index++, 0, 0 /*meshMode*/, 0 /*unused*/, 0 /*unused*/); - addTest(index++, 0, 1 /*meshMode*/, 0 /*unused*/, 0 /*unused*/); - addTest(index++, 1, 7 /*wResolution*/, 5 /*hResolution*/, 0 /*meshMode*/); - addTest(index++, 1, 7 /*wResolution*/, 5 /*hResolution*/, 1 /*meshMode*/); - addTest(index++, 2, 0 /*unused*/, 0 /*unused*/, 0 /*unused*/); - addTest(index++, 3, 7 /*wResolution*/, 5 /*hResolution*/, 0 /*unused*/); - - return true; - } - - public ScriptField_TestScripts_s.Item[] getTests() { - return mTests; - } - - public String[] getTestNames() { - return mNames; - } - - private Allocation loadTextureRGB(int id) { - return Allocation.createFromBitmapResource(mRS, mRes, id, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - private Allocation loadTextureARGB(int id) { - Bitmap b = BitmapFactory.decodeResource(mRes, id, mOptionsARGB); - return Allocation.createFromBitmap(mRS, b, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - } - - private void createParticlesMesh() { - ScriptField_Particle p = new ScriptField_Particle(mRS, PARTICLES_COUNT); - - final Mesh.AllocationBuilder meshBuilder = new Mesh.AllocationBuilder(mRS); - meshBuilder.addVertexAllocation(p.getAllocation()); - final int vertexSlot = meshBuilder.getCurrentVertexTypeIndex(); - meshBuilder.addIndexSetType(Primitive.POINT); - mParticlesMesh = meshBuilder.create(); - - mUiScript.set_gParticlesMesh(mParticlesMesh); - mUiScript.bind_Particles(p); - } - - /** - * Create a mesh with a single quad for the given width and height. - */ - private Mesh getSingleMesh(float width, float height) { - Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, - 2, Mesh.TriangleMeshBuilder.TEXTURE_0); - float xOffset = width/2; - float yOffset = height/2; - tmb.setTexture(0, 0); - tmb.addVertex(-1.0f * xOffset, -1.0f * yOffset); - tmb.setTexture(1, 0); - tmb.addVertex(xOffset, -1.0f * yOffset); - tmb.setTexture(1, 1); - tmb.addVertex(xOffset, yOffset); - tmb.setTexture(0, 1); - tmb.addVertex(-1.0f * xOffset, yOffset); - tmb.addTriangle(0, 3, 1); - tmb.addTriangle(1, 3, 2); - return tmb.create(true); - } - - private Matrix4f getProjectionNormalized(int w, int h) { - // range -1,1 in the narrow axis at z = 0. - Matrix4f m1 = new Matrix4f(); - Matrix4f m2 = new Matrix4f(); - - if(w > h) { - float aspect = ((float)w) / h; - m1.loadFrustum(-aspect,aspect, -1,1, 1,100); - } else { - float aspect = ((float)h) / w; - m1.loadFrustum(-1,1, -aspect,aspect, 1,100); - } - - m2.loadRotate(180, 0, 1, 0); - m1.loadMultiply(m1, m2); - - m2.loadScale(-2, 2, 1); - m1.loadMultiply(m1, m2); - - m2.loadTranslate(0, 0, 2); - m1.loadMultiply(m1, m2); - return m1; - } - - private void updateProjectionMatrices() { - Matrix4f projNorm = getProjectionNormalized(1280, 720); - ScriptField_VpConsts.Item i = new ScriptField_VpConsts.Item(); - i.Proj = projNorm; - i.MVP = projNorm; - mPvStarAlloc.set(i, 0, true); - mPvProjectionAlloc.setProjection(projNorm); - } - - void initUiScript() { - mUiScript = new ScriptC_ui_test(mRS, mRes, R.raw.ui_test); - - ProgramFragmentFixedFunction.Builder colBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - colBuilder.setVaryingColor(false); - ProgramFragmentFixedFunction.Builder texBuilder = new ProgramFragmentFixedFunction.Builder(mRS); - texBuilder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - ProgramVertexFixedFunction progVertex = pvb.create(); - ProgramVertexFixedFunction.Constants PVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)progVertex).bindConstants(PVA); - Matrix4f proj = new Matrix4f(); - proj.loadOrthoWindow(1280, 720); - PVA.setProjection(proj); - - mUiScript.set_gProgVertex(progVertex); - mUiScript.set_gProgFragmentColor(colBuilder.create()); - mUiScript.set_gProgFragmentTexture(texBuilder.create()); - mUiScript.set_gProgStoreBlendAlpha(ProgramStore.BLEND_ALPHA_DEPTH_NONE(mRS)); - - mUiScript.set_gLinearClamp(Sampler.CLAMP_LINEAR(mRS)); - - mUiScript.set_gTexTorus(loadTextureRGB(R.drawable.torusmap)); - mUiScript.set_gTexOpaque(loadTextureRGB(R.drawable.data)); - mUiScript.set_gTexGlobe(loadTextureRGB(R.drawable.globe)); - mUiScript.set_gSingleMesh(mSingleMesh); - - // For GALAXY - ProgramStore.Builder psb = new ProgramStore.Builder(mRS); - psb.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); - mRS.bindProgramStore(psb.create()); - - psb.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE); - mUiScript.set_gPSLights(psb.create()); - - // For Galaxy live wallpaper drawing - ProgramFragmentFixedFunction.Builder builder = new ProgramFragmentFixedFunction.Builder(mRS); - builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGB, 0); - ProgramFragment pfb = builder.create(); - pfb.bindSampler(Sampler.WRAP_NEAREST(mRS), 0); - mUiScript.set_gPFBackground(pfb); - - builder = new ProgramFragmentFixedFunction.Builder(mRS); - builder.setPointSpriteTexCoordinateReplacement(true); - builder.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.MODULATE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - builder.setVaryingColor(true); - ProgramFragment pfs = builder.create(); - pfs.bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0); - mUiScript.set_gPFStars(pfs); - - mTextureAllocs = new ScriptField_ListAllocs_s(mRS, 100); - for (int i = 0; i < 100; i++) { - ScriptField_ListAllocs_s.Item texElem = new ScriptField_ListAllocs_s.Item(); - texElem.item = loadTextureRGB(R.drawable.globe); - mTextureAllocs.set(texElem, i, false); - } - mTextureAllocs.copyAll(); - mUiScript.bind_gTexList100(mTextureAllocs); - - mSampleTextAllocs = new ScriptField_ListAllocs_s(mRS, 100); - for (int i = 0; i < 100; i++) { - ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item(); - textElem.item = Allocation.createFromString(mRS, SAMPLE_TEXT, Allocation.USAGE_SCRIPT); - mSampleTextAllocs.set(textElem, i, false); - } - mSampleTextAllocs.copyAll(); - mUiScript.bind_gSampleTextList100(mSampleTextAllocs); - - mSampleListViewAllocs = new ScriptField_ListAllocs_s(mRS, 1000); - for (int i = 0; i < 1000; i++) { - ScriptField_ListAllocs_s.Item textElem = new ScriptField_ListAllocs_s.Item(); - textElem.item = Allocation.createFromString(mRS, LIST_TEXT, Allocation.USAGE_SCRIPT); - mSampleListViewAllocs.set(textElem, i, false); - } - mSampleListViewAllocs.copyAll(); - mUiScript.bind_gListViewText(mSampleListViewAllocs); - - // For galaxy live wallpaper - mPvStarAlloc = new ScriptField_VpConsts(mRS, 1); - mUiScript.bind_vpConstants(mPvStarAlloc); - mPvProjectionAlloc = new ProgramVertexFixedFunction.Constants(mRS); - updateProjectionMatrices(); - - pvb = new ProgramVertexFixedFunction.Builder(mRS); - ProgramVertex pvbp = pvb.create(); - ((ProgramVertexFixedFunction)pvbp).bindConstants(mPvProjectionAlloc); - mUiScript.set_gPVBkProj(pvbp); - - createParticlesMesh(); - - ProgramVertex.Builder sb = new ProgramVertex.Builder(mRS); - String t = "varying vec4 varColor;\n" + - "varying vec2 varTex0;\n" + - "void main() {\n" + - " float dist = ATTRIB_position.y;\n" + - " float angle = ATTRIB_position.x;\n" + - " float x = dist * sin(angle);\n" + - " float y = dist * cos(angle) * 0.892;\n" + - " float p = dist * 5.5;\n" + - " float s = cos(p);\n" + - " float t = sin(p);\n" + - " vec4 pos;\n" + - " pos.x = t * x + s * y;\n" + - " pos.y = s * x - t * y;\n" + - " pos.z = ATTRIB_position.z;\n" + - " pos.w = 1.0;\n" + - " gl_Position = UNI_MVP * pos;\n" + - " gl_PointSize = ATTRIB_color.a * 10.0;\n" + - " varColor.rgb = ATTRIB_color.rgb;\n" + - " varColor.a = 1.0;\n" + - "}\n"; - sb.setShader(t); - sb.addInput(mParticlesMesh.getVertexAllocation(0).getType().getElement()); - sb.addConstant(mPvStarAlloc.getType()); - ProgramVertex pvs = sb.create(); - pvs.bindConstants(mPvStarAlloc.getAllocation(), 0); - mUiScript.set_gPVStars(pvs); - - // For Galaxy live wallpaper - mUiScript.set_gTSpace(loadTextureRGB(R.drawable.space)); - mUiScript.set_gTLight1(loadTextureRGB(R.drawable.light1)); - mUiScript.set_gTFlares(loadTextureARGB(R.drawable.flares)); - - mUiScript.set_gFontSans(mFontSans); - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs deleted file mode 100644 index 281f830d328a..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/fill_test.rs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.perftest) - -#include "rs_graphics.rsh" -#include "subtest_def.rsh" - -rs_program_vertex gProgVertex; -rs_program_fragment gProgFragmentTexture; -rs_program_fragment gProgFragmentTextureModulate; -rs_program_fragment gProgFragmentMultitex; - -rs_program_store gProgStoreBlendNone; -rs_program_store gProgStoreBlendAlpha; - -rs_allocation gTexOpaque; -rs_allocation gTexTorus; -rs_allocation gTexTransparent; -rs_allocation gTexChecker; - -rs_sampler gLinearClamp; -rs_sampler gLinearWrap; - -typedef struct FillTestData_s { - int testId; - int blend; - int quadCount; -} FillTestData; -FillTestData *gData; - -typedef struct FillTestFragData_s { - float4 modulate; -} FillTestFragData; -FillTestFragData *gFragData; - -static float gDt = 0.0f; - -void init() { -} - -static int gRenderSurfaceW = 1280; -static int gRenderSurfaceH = 720; - -static void bindProgramVertexOrtho() { - // Default vertex shader - rsgBindProgramVertex(gProgVertex); - // Setup the projection matrix - rs_matrix4x4 proj; - rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); - rsgProgramVertexLoadProjectionMatrix(&proj); -} - -static void displaySingletexFill(bool blend, int quadCount, bool modulate) { - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - if (!blend) { - rsgBindProgramStore(gProgStoreBlendNone); - } else { - rsgBindProgramStore(gProgStoreBlendAlpha); - } - if (modulate) { - rsgBindProgramFragment(gProgFragmentTextureModulate); - rsgBindSampler(gProgFragmentTextureModulate, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTextureModulate, 0, gTexOpaque); - - gFragData->modulate.r = 0.8f; - gFragData->modulate.g = 0.7f; - gFragData->modulate.b = 0.8f; - gFragData->modulate.a = 0.5f; - rsgAllocationSyncAll(rsGetAllocation(gFragData)); - } else { - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); - } - - for (int i = 0; i < quadCount; i ++) { - float startX = 5 * i, startY = 5 * i; - float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1, - startX + width, startY + height, 0, 1, 1, - startX + width, startY, 0, 1, 0); - } -} - -static void displayMultitextureSample(bool blend, int quadCount) { - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - if (!blend) { - rsgBindProgramStore(gProgStoreBlendNone); - } else { - rsgBindProgramStore(gProgStoreBlendAlpha); - } - rsgBindProgramFragment(gProgFragmentMultitex); - rsgBindSampler(gProgFragmentMultitex, 0, gLinearClamp); - rsgBindSampler(gProgFragmentMultitex, 1, gLinearWrap); - rsgBindSampler(gProgFragmentMultitex, 2, gLinearClamp); - rsgBindTexture(gProgFragmentMultitex, 0, gTexChecker); - rsgBindTexture(gProgFragmentMultitex, 1, gTexTorus); - rsgBindTexture(gProgFragmentMultitex, 2, gTexTransparent); - - for (int i = 0; i < quadCount; i ++) { - float startX = 10 * i, startY = 10 * i; - float width = gRenderSurfaceW - startX, height = gRenderSurfaceH - startY; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 0, - startX, startY + height, 0, 0, 1, - startX + width, startY + height, 0, 1, 1, - startX + width, startY, 0, 1, 0); - } -} - - -void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { - TestData *testData = (TestData*)usrData; - gRenderSurfaceW = testData->renderSurfaceW; - gRenderSurfaceH = testData->renderSurfaceH; - gDt = testData->dt; - - gData = (FillTestData*)v_in; - - switch(gData->testId) { - case 0: - displayMultitextureSample(gData->blend == 1 ? true : false, gData->quadCount); - break; - case 1: - displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, false); - break; - case 2: - displaySingletexFill(gData->blend == 1 ? true : false, gData->quadCount, true); - break; - default: - rsDebug("Wrong test number", 0); - break; - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs deleted file mode 100644 index d7e4857208c9..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/mesh_test.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.perftest) - -#include "rs_graphics.rsh" -#include "shader_def.rsh" -#include "subtest_def.rsh" - -rs_program_vertex gProgVertex; -rs_program_fragment gProgFragmentTexture; - -rs_program_store gProgStoreBlendNone; - -rs_allocation gTexOpaque; - -rs_mesh g10by10Mesh; -rs_mesh g100by100Mesh; -rs_mesh gWbyHMesh; - -rs_sampler gLinearClamp; -static int gRenderSurfaceW; -static int gRenderSurfaceH; - -static float gDt = 0; - -typedef struct MeshTestData_s { - int meshNum; -} MeshTestData; -MeshTestData *gData; - -void init() { -} - -static void bindProgramVertexOrtho() { - // Default vertex shader - rsgBindProgramVertex(gProgVertex); - // Setup the projection matrix - rs_matrix4x4 proj; - rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); - rsgProgramVertexLoadProjectionMatrix(&proj); -} - -static void displayMeshSamples(int meshNum) { - - bindProgramVertexOrtho(); - rs_matrix4x4 matrix; - rsMatrixLoadTranslate(&matrix, gRenderSurfaceW/2, gRenderSurfaceH/2, 0); - rsgProgramVertexLoadModelMatrix(&matrix); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNone); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - - rsgBindTexture(gProgFragmentTexture, 0, gTexOpaque); - - if (meshNum == 0) { - rsgDrawMesh(g10by10Mesh); - } else if (meshNum == 1) { - rsgDrawMesh(g100by100Mesh); - } else if (meshNum == 2) { - rsgDrawMesh(gWbyHMesh); - } -} - -void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { - TestData *testData = (TestData*)usrData; - gRenderSurfaceW = testData->renderSurfaceW; - gRenderSurfaceH = testData->renderSurfaceH; - gDt = testData->dt; - - gData = (MeshTestData*)v_in; - - displayMeshSamples(gData->meshNum); -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs deleted file mode 100644 index 43cf4e0634a8..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/rsbench.rs +++ /dev/null @@ -1,270 +0,0 @@ -// Copyright (C) 2010-2011 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 version(1) - -#pragma rs java_package_name(com.android.perftest) - -#include "rs_graphics.rsh" -#include "shader_def.rsh" -#include "subtest_def.rsh" - -/* Message sent from script to renderscript */ -const int RS_MSG_TEST_DONE = 100; -const int RS_MSG_RESULTS_READY = 101; - -static const int gMaxModes = 64; -int gMaxLoops = 1; -int gDisplayMode = 1; - -// Allocation to write the results into -static float gResultBuffer[gMaxModes]; - -rs_font gFontSerif; -rs_sampler gLinearClamp; - -rs_program_vertex gProgVertex; -rs_program_fragment gProgFragmentTexture; - -rs_allocation gRenderBufferColor; -rs_allocation gRenderBufferDepth; - -VertexShaderInputs *gVSInputs; - -typedef struct TestScripts_s { - rs_allocation testData; - rs_allocation testName; - rs_allocation debugName; - rs_script testScript; -} TestScripts; -TestScripts *gTestScripts; - -bool gLoadComplete = false; -bool gPauseRendering = false; - -static float gDt = 0; - -void init() { -} - -static int gRenderSurfaceW; -static int gRenderSurfaceH; - -static void fillSurfaceParams(TestData *testData) { - testData->renderSurfaceW = gRenderSurfaceW; - testData->renderSurfaceH = gRenderSurfaceH; - testData->dt = gDt; -} - -static void setupOffscreenTarget() { - rsgBindColorTarget(gRenderBufferColor, 0); - rsgBindDepthTarget(gRenderBufferDepth); -} - -static void bindProgramVertexOrtho() { - // Default vertex shader - rsgBindProgramVertex(gProgVertex); - // Setup the projection matrix - rs_matrix4x4 proj; - rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); - rsgProgramVertexLoadProjectionMatrix(&proj); -} - -static void runSubTest(int index) { - TestData testData; - fillSurfaceParams(&testData); - - rs_allocation null_alloc = {0}; - rsForEach(gTestScripts[index].testScript, - gTestScripts[index].testData, - null_alloc, - &testData, - sizeof(testData)); -} - - -static bool checkInit() { - - static int countdown = 3; - - // Perform all the uploads so we only measure rendered time - if(countdown > 1) { - int testCount = rsAllocationGetDimX(rsGetAllocation(gTestScripts)); - for(int i = 0; i < testCount; i ++) { - rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f); - runSubTest(i); - rsgFinish(); - } - countdown --; - rsgClearColor(0.2f, 0.2f, 0.2f, 0.0f); - - rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); - rsgBindFont(gFontSerif); - if (countdown == 1) { - rsgDrawText("Rendering", 50, 50); - } else { - rsgDrawText("Initializing", 50, 50); - } - - return false; - } - - return true; -} - -static int benchMode = 0; -static bool benchmarkSingleTest = false; -static int runningLoops = 0; -static bool sendMsgFlag = false; - -static bool gIsDebugMode = false; -void setDebugMode(int testNumber) { - gIsDebugMode = true; - benchMode = testNumber; - rsgClearAllRenderTargets(); -} - -void setBenchmarkMode(int testNumber) { - gIsDebugMode = false; - if (testNumber == -1) { - benchmarkSingleTest = false; - benchMode = 0; - } else { - benchmarkSingleTest = true; - benchMode = testNumber; - } - - runningLoops = 0; -} - -static void drawOffscreenResult(int posX, int posY, int width, int height) { - bindProgramVertexOrtho(); - - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - - rsgBindProgramFragment(gProgFragmentTexture); - - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gRenderBufferColor); - - float startX = posX, startY = posY; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 1, - startX, startY + height, 0, 0, 0, - startX + width, startY + height, 0, 1, 0, - startX + width, startY, 0, 1, 1); -} - -static void benchmark() { - - gDt = 1.0f / 60.0f; - - rsgFinish(); - int64_t start = rsUptimeMillis(); - - int drawPos = 0; - int frameCount = 100; - for(int i = 0; i < frameCount; i ++) { - setupOffscreenTarget(); - gRenderSurfaceW = rsAllocationGetDimX(gRenderBufferColor); - gRenderSurfaceH = rsAllocationGetDimY(gRenderBufferColor); - rsgClearColor(0.1f, 0.1f, 0.1f, 1.0f); - rsgClearDepth(1.0f); - - runSubTest(benchMode); - rsgClearAllRenderTargets(); - gRenderSurfaceW = rsgGetWidth(); - gRenderSurfaceH = rsgGetHeight(); - int size = 8; - // draw each frame at (8, 3/4 gRenderSurfaceH) with size - drawOffscreenResult((drawPos+=size)%gRenderSurfaceW, (gRenderSurfaceH * 3) / 4, size, size); - } - - rsgFinish(); - - int64_t end = rsUptimeMillis(); - float fps = (float)(frameCount) / ((float)(end - start)*0.001f); - const char *testName = rsGetElementAt(gTestScripts[benchMode].debugName, 0); - rsDebug(testName, fps); - - gResultBuffer[benchMode] = fps; - int bufferW = rsAllocationGetDimX(gRenderBufferColor); - int bufferH = rsAllocationGetDimY(gRenderBufferColor); - - int quadW = gRenderSurfaceW / 2; - int quadH = (quadW * bufferH) / bufferW; - drawOffscreenResult(0, 0, quadW, quadH); - - int left = 0, right = 0, top = 0, bottom = 0; - uint height = rsgGetHeight(); - rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); - rsgBindFont(gFontSerif); - rsgMeasureText(gTestScripts[benchMode].testName, &left, &right, &top, &bottom); - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgDrawText(gTestScripts[benchMode].testName, 2 -left, height - 2 + bottom); - - if (benchmarkSingleTest) { - return; - } - - benchMode ++; - int testCount = rsAllocationGetDimX(rsGetAllocation(gTestScripts)); - if (benchMode == testCount) { - rsSendToClientBlocking(RS_MSG_RESULTS_READY, gResultBuffer, testCount*sizeof(float)); - benchMode = 0; - runningLoops++; - if ((gMaxLoops > 0) && (runningLoops > gMaxLoops) && !sendMsgFlag) { - //Notifiy the test to stop and get results - rsDebug("gMaxLoops and runningLoops: ", gMaxLoops, runningLoops); - rsSendToClientBlocking(RS_MSG_TEST_DONE); - sendMsgFlag = true; - } - } -} - -static void debug() { - gDt = rsGetDt(); - runSubTest(benchMode); -} - -int root(void) { - gRenderSurfaceW = rsgGetWidth(); - gRenderSurfaceH = rsgGetHeight(); - rsgClearColor(0.2f, 0.2f, 0.2f, 1.0f); - rsgClearDepth(1.0f); - - if (!gLoadComplete) { - rsgFontColor(0.9f, 0.9f, 0.95f, 1.0f); - rsgBindFont(gFontSerif); - rsgDrawText("Loading", 50, 50); - return 0; - } - - if(!checkInit()) { - return 1; - } - - if (gPauseRendering) { - rsgDrawText("Paused", 50, 50); - return 30; - } - if (gIsDebugMode) { - debug(); - } else { - benchmark(); - } - - return 1; -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh deleted file mode 100644 index 648359c09385..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/shader_def.rsh +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (C) 2009 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 version(1) - -#pragma rs java_package_name(com.android.perftest) - -typedef struct VertexShaderConstants_s { - rs_matrix4x4 model; - rs_matrix4x4 proj; - float4 light0_Posision; - float light0_Diffuse; - float light0_Specular; - float light0_CosinePower; - - float4 light1_Posision; - float light1_Diffuse; - float light1_Specular; - float light1_CosinePower; -} VertexShaderConstants; - -typedef struct VertexShaderConstants3_s { - rs_matrix4x4 model; - rs_matrix4x4 proj; - float time; -} VertexShaderConstants3; - - -typedef struct FragentShaderConstants_s { - float4 light0_DiffuseColor; - float4 light0_SpecularColor; - - float4 light1_DiffuseColor; - float4 light1_SpecularColor; -} FragentShaderConstants; - -typedef struct FragentShaderConstants2_s { - float4 light_DiffuseColor[2]; - float4 light_SpecularColor[2]; -} FragentShaderConstants2; - -typedef struct FragentShaderConstants3_s { - float4 light0_DiffuseColor; - float4 light0_SpecularColor; - float4 light0_Posision; - float light0_Diffuse; - float light0_Specular; - float light0_CosinePower; - - float4 light1_DiffuseColor; - float4 light1_SpecularColor; - float4 light1_Posision; - float light1_Diffuse; - float light1_Specular; - float light1_CosinePower; -} FragentShaderConstants3; - -typedef struct VertexShaderInputs_s { - float4 position; - float3 normal; - float2 texture0; -} VertexShaderInputs; - diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh deleted file mode 100644 index 43658b15a2cf..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/subtest_def.rsh +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.perftest) - -typedef struct TestData_s { - int renderSurfaceW; - int renderSurfaceH; - float dt; -} TestData; - diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs deleted file mode 100644 index 0f50828cd0b8..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/text_test.rs +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.perftest) - -#include "rs_graphics.rsh" -#include "subtest_def.rsh" - -rs_font gFontSans; -rs_font gFontSerif; - -typedef struct TextTestData_s { - int fillNum; -} TextTestData; -TextTestData *gData; - -void init() { -} - -static int gRenderSurfaceW = 1280; -static int gRenderSurfaceH = 720; - -static const char *sampleText = "This is a sample of small text for performace"; -// Offsets for multiple layer of text -static int textOffsets[] = { 0, 0, -5, -5, 5, 5, -8, -8, 8, 8}; -static float textColors[] = {1.0f, 1.0f, 1.0f, 1.0f, - 0.5f, 0.7f, 0.5f, 1.0f, - 0.7f, 0.5f, 0.5f, 1.0f, - 0.5f, 0.5f, 0.7f, 1.0f, - 0.5f, 0.6f, 0.7f, 1.0f, -}; - -static void displayFontSamples(int fillNum) { - - rs_font fonts[5]; - fonts[0] = gFontSans; - fonts[1] = gFontSerif; - fonts[2] = gFontSans; - fonts[3] = gFontSerif; - fonts[4] = gFontSans; - - uint height = gRenderSurfaceH; - int left = 0, right = 0, top = 0, bottom = 0; - rsgMeasureText(sampleText, &left, &right, &top, &bottom); - - int textHeight = top - bottom; - int textWidth = right - left; - int numVerticalLines = height / textHeight; - int yPos = top; - - int xOffset = 0, yOffset = 0; - for(int fillI = 0; fillI < fillNum; fillI ++) { - rsgBindFont(fonts[fillI]); - xOffset = textOffsets[fillI * 2]; - yOffset = textOffsets[fillI * 2 + 1]; - float *colPtr = textColors + fillI * 4; - rsgFontColor(colPtr[0], colPtr[1], colPtr[2], colPtr[3]); - for (int h = 0; h < 4; h ++) { - yPos = top + yOffset; - for (int v = 0; v < numVerticalLines; v ++) { - rsgDrawText(sampleText, xOffset + textWidth * h, yPos); - yPos += textHeight; - } - } - } -} - -void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { - TestData *testData = (TestData*)usrData; - gRenderSurfaceW = testData->renderSurfaceW; - gRenderSurfaceH = testData->renderSurfaceH; - - gData = (TextTestData*)v_in; - - displayFontSamples(gData->fillNum); -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs deleted file mode 100644 index 853a05d1c874..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/torus_test.rs +++ /dev/null @@ -1,295 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.perftest) - -#include "rs_graphics.rsh" -#include "subtest_def.rsh" -#include "shader_def.rsh" - -rs_program_vertex gProgVertex; -rs_program_fragment gProgFragmentColor; -rs_program_fragment gProgFragmentTexture; - -rs_program_store gProgStoreBlendNoneDepth; -rs_mesh gTorusMesh; - -rs_program_raster gCullBack; -rs_program_raster gCullFront; - -// Custom vertex shader compunents -VertexShaderConstants *gVSConstants; -FragentShaderConstants *gFSConstants; -VertexShaderConstants3 *gVSConstPixel; -FragentShaderConstants3 *gFSConstPixel; - -// Custom shaders we use for lighting -rs_program_vertex gProgVertexCustom; -rs_program_fragment gProgFragmentCustom; - -rs_sampler gLinearClamp; -rs_allocation gTexTorus; - -rs_program_vertex gProgVertexPixelLight; -rs_program_vertex gProgVertexPixelLightMove; -rs_program_fragment gProgFragmentPixelLight; - -typedef struct TorusTestData_s { - int testId; - int user1; - int user2; -} TorusTestData; -TorusTestData *gData; - -static float gDt = 0.0f; - -static int gRenderSurfaceW; -static int gRenderSurfaceH; - - -static float gTorusRotation = 0; -static void updateModelMatrix(rs_matrix4x4 *matrix, void *buffer) { - if (buffer == 0) { - rsgProgramVertexLoadModelMatrix(matrix); - } else { - rsgAllocationSyncAll(rsGetAllocation(buffer)); - } -} - -static void drawToruses(int numMeshes, rs_matrix4x4 *matrix, void *buffer) { - - if (numMeshes == 1) { - rsMatrixLoadTranslate(matrix, 0.0f, 0.0f, -7.5f); - rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f); - updateModelMatrix(matrix, buffer); - rsgDrawMesh(gTorusMesh); - return; - } - - if (numMeshes == 2) { - rsMatrixLoadTranslate(matrix, -1.6f, 0.0f, -7.5f); - rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f); - updateModelMatrix(matrix, buffer); - rsgDrawMesh(gTorusMesh); - - rsMatrixLoadTranslate(matrix, 1.6f, 0.0f, -7.5f); - rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f); - updateModelMatrix(matrix, buffer); - rsgDrawMesh(gTorusMesh); - return; - } - - float startX = -5.0f; - float startY = -1.5f; - float startZ = -15.0f; - float dist = 3.2f; - - for (int h = 0; h < 4; h ++) { - for (int v = 0; v < 2; v ++) { - // Position our model on the screen - rsMatrixLoadTranslate(matrix, startX + dist * h, startY + dist * v, startZ); - rsMatrixRotate(matrix, gTorusRotation, 1.0f, 0.0f, 0.0f); - updateModelMatrix(matrix, buffer); - rsgDrawMesh(gTorusMesh); - } - } -} - - -// Quick hack to get some geometry numbers -static void displaySimpleGeoSamples(bool useTexture, int numMeshes) { - rsgBindProgramVertex(gProgVertex); - rsgBindProgramRaster(gCullBack); - // Setup the projection matrix with 30 degree field of view - rs_matrix4x4 proj; - float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH; - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 0.1f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNoneDepth); - if (useTexture) { - rsgBindProgramFragment(gProgFragmentTexture); - } else { - rsgBindProgramFragment(gProgFragmentColor); - rsgProgramFragmentConstantColor(gProgFragmentColor, 0.1, 0.7, 0.1, 1); - } - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexTorus); - - // Apply a rotation to our mesh - gTorusRotation += 50.0f * gDt; - if (gTorusRotation > 360.0f) { - gTorusRotation -= 360.0f; - } - - rs_matrix4x4 matrix; - drawToruses(numMeshes, &matrix, 0); -} - -float gLight0Rotation = 0; -float gLight1Rotation = 0; - -static void setupCustomShaderLights() { - float4 light0Pos = {-5.0f, 5.0f, -10.0f, 1.0f}; - float4 light1Pos = {2.0f, 5.0f, 15.0f, 1.0f}; - float4 light0DiffCol = {0.9f, 0.7f, 0.7f, 1.0f}; - float4 light0SpecCol = {0.9f, 0.6f, 0.6f, 1.0f}; - float4 light1DiffCol = {0.5f, 0.5f, 0.9f, 1.0f}; - float4 light1SpecCol = {0.5f, 0.5f, 0.9f, 1.0f}; - - gLight0Rotation += 50.0f * gDt; - if (gLight0Rotation > 360.0f) { - gLight0Rotation -= 360.0f; - } - gLight1Rotation -= 50.0f * gDt; - if (gLight1Rotation > 360.0f) { - gLight1Rotation -= 360.0f; - } - - rs_matrix4x4 l0Mat; - rsMatrixLoadRotate(&l0Mat, gLight0Rotation, 1.0f, 0.0f, 0.0f); - light0Pos = rsMatrixMultiply(&l0Mat, light0Pos); - rs_matrix4x4 l1Mat; - rsMatrixLoadRotate(&l1Mat, gLight1Rotation, 0.0f, 0.0f, 1.0f); - light1Pos = rsMatrixMultiply(&l1Mat, light1Pos); - - // Set light 0 properties - gVSConstants->light0_Posision = light0Pos; - gVSConstants->light0_Diffuse = 1.0f; - gVSConstants->light0_Specular = 0.5f; - gVSConstants->light0_CosinePower = 10.0f; - // Set light 1 properties - gVSConstants->light1_Posision = light1Pos; - gVSConstants->light1_Diffuse = 1.0f; - gVSConstants->light1_Specular = 0.7f; - gVSConstants->light1_CosinePower = 25.0f; - rsgAllocationSyncAll(rsGetAllocation(gVSConstants)); - - // Update fragment shader constants - // Set light 0 colors - gFSConstants->light0_DiffuseColor = light0DiffCol; - gFSConstants->light0_SpecularColor = light0SpecCol; - // Set light 1 colors - gFSConstants->light1_DiffuseColor = light1DiffCol; - gFSConstants->light1_SpecularColor = light1SpecCol; - rsgAllocationSyncAll(rsGetAllocation(gFSConstants)); - - // Set light 0 properties for per pixel lighting - gFSConstPixel->light0_Posision = light0Pos; - gFSConstPixel->light0_Diffuse = 1.0f; - gFSConstPixel->light0_Specular = 0.5f; - gFSConstPixel->light0_CosinePower = 10.0f; - gFSConstPixel->light0_DiffuseColor = light0DiffCol; - gFSConstPixel->light0_SpecularColor = light0SpecCol; - // Set light 1 properties - gFSConstPixel->light1_Posision = light1Pos; - gFSConstPixel->light1_Diffuse = 1.0f; - gFSConstPixel->light1_Specular = 0.7f; - gFSConstPixel->light1_CosinePower = 25.0f; - gFSConstPixel->light1_DiffuseColor = light1DiffCol; - gFSConstPixel->light1_SpecularColor = light1SpecCol; - rsgAllocationSyncAll(rsGetAllocation(gFSConstPixel)); -} - -static void displayCustomShaderSamples(int numMeshes) { - - // Update vertex shader constants - // Load model matrix - // Apply a rotation to our mesh - gTorusRotation += 50.0f * gDt; - if (gTorusRotation > 360.0f) { - gTorusRotation -= 360.0f; - } - - // Setup the projection matrix - float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH; - rsMatrixLoadPerspective(&gVSConstants->proj, 30.0f, aspect, 0.1f, 100.0f); - setupCustomShaderLights(); - - rsgBindProgramVertex(gProgVertexCustom); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNoneDepth); - rsgBindProgramFragment(gProgFragmentCustom); - rsgBindSampler(gProgFragmentCustom, 0, gLinearClamp); - rsgBindTexture(gProgFragmentCustom, 0, gTexTorus); - - // Use back face culling - rsgBindProgramRaster(gCullBack); - - drawToruses(numMeshes, &gVSConstants->model, gVSConstants); -} - -static void displayPixelLightSamples(int numMeshes, bool heavyVertex) { - - // Update vertex shader constants - // Load model matrix - // Apply a rotation to our mesh - gTorusRotation += 30.0f * gDt; - if (gTorusRotation > 360.0f) { - gTorusRotation -= 360.0f; - } - - gVSConstPixel->time = rsUptimeMillis()*0.005; - - // Setup the projection matrix - float aspect = (float)gRenderSurfaceW / (float)gRenderSurfaceH; - rsMatrixLoadPerspective(&gVSConstPixel->proj, 30.0f, aspect, 0.1f, 100.0f); - setupCustomShaderLights(); - - if (heavyVertex) { - rsgBindProgramVertex(gProgVertexPixelLightMove); - } else { - rsgBindProgramVertex(gProgVertexPixelLight); - } - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendNoneDepth); - rsgBindProgramFragment(gProgFragmentPixelLight); - rsgBindSampler(gProgFragmentPixelLight, 0, gLinearClamp); - rsgBindTexture(gProgFragmentPixelLight, 0, gTexTorus); - - // Use back face culling - rsgBindProgramRaster(gCullBack); - - drawToruses(numMeshes, &gVSConstPixel->model, gVSConstPixel); -} - - -void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { - TestData *testData = (TestData*)usrData; - gRenderSurfaceW = testData->renderSurfaceW; - gRenderSurfaceH = testData->renderSurfaceH; - gDt = testData->dt; - - gData = (TorusTestData*)v_in; - - switch(gData->testId) { - case 0: - displaySimpleGeoSamples(gData->user1 == 1 ? true : false, gData->user2); - break; - case 1: - displayCustomShaderSamples(gData->user1); - break; - case 2: - displayPixelLightSamples(gData->user1, gData->user2 == 1 ? true : false); - break; - default: - rsDebug("Wrong test number", gData->testId); - break; - } -} diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs b/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs deleted file mode 100644 index e87db39d1966..000000000000 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/ui_test.rs +++ /dev/null @@ -1,442 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.perftest) - -#include "rs_graphics.rsh" -#include "shader_def.rsh" -#include "subtest_def.rsh" - -// Parameters for galaxy live wallpaper -rs_allocation gTSpace; -rs_allocation gTLight1; -rs_allocation gTFlares; -rs_mesh gParticlesMesh; - -rs_program_fragment gPFBackground; -rs_program_fragment gPFStars; -rs_program_vertex gPVStars; -rs_program_vertex gPVBkProj; -rs_program_store gPSLights; - -float gXOffset = 0.5f; - -#define ELLIPSE_RATIO 0.892f -#define PI 3.1415f -#define TWO_PI 6.283f -#define ELLIPSE_TWIST 0.023333333f - -static float angle = 50.f; -static int gOldWidth; -static int gOldHeight; -static int gWidth; -static int gHeight; -static float gSpeed[12000]; -static int gGalaxyRadius = 300; -static rs_allocation gParticlesBuffer; - -typedef struct __attribute__((packed, aligned(4))) Particle { - uchar4 color; - float3 position; -} Particle_t; -Particle_t *Particles; - -typedef struct VpConsts { - rs_matrix4x4 Proj; - rs_matrix4x4 MVP; -} VpConsts_t; -VpConsts_t *vpConstants; -// End of parameters for galaxy live wallpaper - -rs_program_vertex gProgVertex; -rs_program_fragment gProgFragmentColor; -rs_program_fragment gProgFragmentTexture; - -rs_program_store gProgStoreBlendAlpha; - -rs_allocation gTexOpaque; -rs_allocation gTexTorus; -rs_allocation gTexGlobe; - -typedef struct ListAllocs_s { - rs_allocation item; -} ListAllocs; - -ListAllocs *gTexList100; -ListAllocs *gSampleTextList100; -ListAllocs *gListViewText; - -rs_mesh gSingleMesh; - -rs_font gFontSans; - -rs_sampler gLinearClamp; - -typedef struct UiTestData_s { - int testId; - int user1; - int user2; - int user3; -} UiTestData; -UiTestData *gData; - -static float gDt = 0; - - -void init() { -} - -static int gRenderSurfaceW; -static int gRenderSurfaceH; - -static void bindProgramVertexOrtho() { - // Default vertex shader - rsgBindProgramVertex(gProgVertex); - // Setup the projection matrix - rs_matrix4x4 proj; - rsMatrixLoadOrtho(&proj, 0, gRenderSurfaceW, gRenderSurfaceH, 0, -500, 500); - rsgProgramVertexLoadProjectionMatrix(&proj); -} - -/** - * Methods to draw the galaxy live wall paper - */ -static float mapf(float minStart, float minStop, float maxStart, float maxStop, float value) { - return maxStart + (maxStart - maxStop) * ((value - minStart) / (minStop - minStart)); -} - -/** - * Helper function to generate the stars. - */ -static float randomGauss() { - float x1; - float x2; - float w = 2.f; - - while (w >= 1.0f) { - x1 = rsRand(2.0f) - 1.0f; - x2 = rsRand(2.0f) - 1.0f; - w = x1 * x1 + x2 * x2; - } - - w = sqrt(-2.0f * log(w) / w); - return x1 * w; -} - -/** - * Generates the properties for a given star. - */ -static void createParticle(Particle_t *part, int idx, float scale) { - float d = fabs(randomGauss()) * gGalaxyRadius * 0.5f + rsRand(64.0f); - float id = d / gGalaxyRadius; - float z = randomGauss() * 0.4f * (1.0f - id); - - if (d < gGalaxyRadius * 0.33f) { - part->color.x = (uchar) (220 + id * 35); - part->color.y = 220; - part->color.z = 220; - } else { - part->color.x = 180; - part->color.y = 180; - part->color.z = (uchar) clamp(140.f + id * 115.f, 140.f, 255.f); - } - // Stash point size * 10 in Alpha - part->color.w = (uchar) (rsRand(1.2f, 2.1f) * 60); - - if (d > gGalaxyRadius * 0.15f) { - z *= 0.6f * (1.0f - id); - } else { - z *= 0.72f; - } - - // Map to the projection coordinates (viewport.x = -1.0 -> 1.0) - d = mapf(-4.0f, gGalaxyRadius + 4.0f, 0.0f, scale, d); - - part->position.x = rsRand(TWO_PI); - part->position.y = d; - gSpeed[idx] = rsRand(0.0015f, 0.0025f) * (0.5f + (scale / d)) * 0.8f; - - part->position.z = z / 5.0f; -} - -/** - * Initialize all the starts, called from Java - */ -void initParticles() { - Particle_t *part = Particles; - float scale = gGalaxyRadius / (gWidth * 0.5f); - int count = rsAllocationGetDimX(gParticlesBuffer); - for (int i = 0; i < count; i ++) { - createParticle(part, i, scale); - part++; - } -} - -static void drawSpace() { - rsgBindProgramFragment(gPFBackground); - rsgBindTexture(gPFBackground, 0, gTSpace); - rsgDrawQuadTexCoords( - 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, - gWidth, 0.0f, 0.0f, 2.0f, 1.0f, - gWidth, gHeight, 0.0f, 2.0f, 0.0f, - 0.0f, gHeight, 0.0f, 0.0f, 0.0f); -} - -static void drawLights() { - rsgBindProgramVertex(gPVBkProj); - rsgBindProgramFragment(gPFBackground); - rsgBindTexture(gPFBackground, 0, gTLight1); - - float scale = 512.0f / gWidth; - float x = -scale - scale * 0.05f; - float y = -scale; - - scale *= 2.0f; - - rsgDrawQuad(x, y, 0.0f, - x + scale * 1.1f, y, 0.0f, - x + scale * 1.1f, y + scale, 0.0f, - x, y + scale, 0.0f); -} - -static void drawParticles(float offset) { - float a = offset * angle; - float absoluteAngle = fabs(a); - - rs_matrix4x4 matrix; - rsMatrixLoadTranslate(&matrix, 0.0f, 0.0f, 10.0f - 6.0f * absoluteAngle / 50.0f); - if (gHeight > gWidth) { - rsMatrixScale(&matrix, 6.6f, 6.0f, 1.0f); - } else { - rsMatrixScale(&matrix, 12.6f, 12.0f, 1.0f); - } - rsMatrixRotate(&matrix, absoluteAngle, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, a, 0.0f, 0.4f, 0.1f); - rsMatrixLoad(&vpConstants->MVP, &vpConstants->Proj); - rsMatrixMultiply(&vpConstants->MVP, &matrix); - rsgAllocationSyncAll(rsGetAllocation(vpConstants)); - - rsgBindProgramVertex(gPVStars); - rsgBindProgramFragment(gPFStars); - rsgBindProgramStore(gPSLights); - rsgBindTexture(gPFStars, 0, gTFlares); - - Particle_t *vtx = Particles; - int count = rsAllocationGetDimX(gParticlesBuffer); - for (int i = 0; i < count; i++) { - vtx->position.x = vtx->position.x + gSpeed[i]; - vtx++; - } - - rsgDrawMesh(gParticlesMesh); -} -/* end of methods for drawing galaxy */ - -// Display sample images in a mesh with different texture -static void displayIcons(int meshMode) { - bindProgramVertexOrtho(); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendAlpha); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - rsgBindTexture(gProgFragmentTexture, 0, gTexTorus); - rsgDrawQuadTexCoords( - 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, - 0.0f, gRenderSurfaceH, 0.0f, 0.0f, 1.0f, - gRenderSurfaceW, gRenderSurfaceH, 0.0f, 1.0f, 1.0f, - gRenderSurfaceW, 0.0f, 0.0f, 1.0f, 0.0f); - - int meshCount = (int)pow(10.0f, (float)(meshMode + 1)); - - float wSize = gRenderSurfaceW/(float)meshCount; - float hSize = gRenderSurfaceH/(float)meshCount; - rs_matrix4x4 matrix; - rsMatrixLoadScale(&matrix, wSize, hSize, 1.0); - - float yPos = 0; - float yPad = hSize / 2; - float xPad = wSize / 2; - for (int y = 0; y < meshCount; y++) { - yPos = y * hSize + yPad; - float xPos = 0; - for (int x = 0; x < meshCount; x++) { - xPos = x * wSize + xPad; - rs_matrix4x4 transMatrix; - rsMatrixLoadTranslate(&transMatrix, xPos, yPos, 0); - rsMatrixMultiply(&transMatrix, &matrix); - rsgProgramVertexLoadModelMatrix(&transMatrix); - int i = (x + y * meshCount) % 100; - rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item); - rsgDrawMesh(gSingleMesh); - } - } -} - -// Draw meshes in a single page with top left corner coordinates (xStart, yStart) -static void drawMeshInPage(float xStart, float yStart, int wResolution, int hResolution) { - // Draw wResolution * hResolution meshes in one page - float wMargin = 100.0f; - float hMargin = 100.0f; - float xPad = 50.0f; - float yPad = 20.0f; - float size = 100.0f; // size of images - - // font info - rs_font font = gFontSans; - rsgBindFont(font); - rsgFontColor(1.0f, 1.0f, 1.0f, 1.0f); - - // Measure text size - int left = 0, right = 0, top = 0, bottom = 0; - rsgMeasureText(gSampleTextList100[0].item, &left, &right, &top, &bottom); - float textHeight = (float)(top - bottom); - - rs_matrix4x4 matrix; - rsMatrixLoadScale(&matrix, size, size, 1.0); - - for (int y = 0; y < hResolution; y++) { - float yPos = yStart + hMargin + y * size + y * yPad; - for (int x = 0; x < wResolution; x++) { - float xPos = xStart + wMargin + x * size + x * xPad; - - rs_matrix4x4 transMatrix; - rsMatrixLoadTranslate(&transMatrix, xPos + size/2, yPos + size/2, 0); - rsMatrixMultiply(&transMatrix, &matrix); // scale the mesh - rsgProgramVertexLoadModelMatrix(&transMatrix); - - int i = (y * wResolution + x) % 100; - rsgBindTexture(gProgFragmentTexture, 0, gTexList100[i].item); - rsgDrawMesh(gSingleMesh); - rsgDrawText(gSampleTextList100[i].item, xPos, yPos + size + yPad/2 + textHeight); - } - } -} - -// Display both images and text as shown in launcher and homepage -// meshMode will decide how many pages we draw -// meshMode = 0: draw 3 pages of meshes -// meshMode = 1: draw 5 pages of meshes -static void displayImageWithText(int wResolution, int hResolution, int meshMode) { - bindProgramVertexOrtho(); - - // Fragment shader with texture - rsgBindProgramStore(gProgStoreBlendAlpha); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - - drawMeshInPage(0, 0, wResolution, hResolution); - drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution); - if (meshMode == 1) { - // draw another two pages of meshes - drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution); - } -} - -// Display a list of text as the list view -static void displayListView() { - // set text color - rsgFontColor(0.9f, 0.9f, 0.9f, 1.0f); - rsgBindFont(gFontSans); - - // get the size of the list - rs_allocation textAlloc; - textAlloc = rsGetAllocation(gListViewText); - int allocSize = rsAllocationGetDimX(textAlloc); - - int listItemHeight = 80; - int yOffset = listItemHeight; - - // set the color for the list divider - rsgBindProgramFragment(gProgFragmentColor); - rsgProgramFragmentConstantColor(gProgFragmentColor, 1.0, 1.0, 1.0, 1); - - // draw the list with divider - for (int i = 0; i < allocSize; i++) { - if (yOffset - listItemHeight > gRenderSurfaceH) { - break; - } - rsgDrawRect(0, yOffset - 1, gRenderSurfaceW, yOffset, 0); - rsgDrawText(gListViewText[i].item, 20, yOffset - 10); - yOffset += listItemHeight; - } -} - -static void drawGalaxy() { - rsgClearColor(0.f, 0.f, 0.f, 1.f); - gParticlesBuffer = rsGetAllocation(Particles); - rsgBindProgramFragment(gPFBackground); - - gWidth = rsgGetWidth(); - gHeight = rsgGetHeight(); - if ((gWidth != gOldWidth) || (gHeight != gOldHeight)) { - initParticles(); - gOldWidth = gWidth; - gOldHeight = gHeight; - } - - float offset = mix(-1.0f, 1.0f, gXOffset); - drawSpace(); - drawParticles(offset); - drawLights(); -} - -// Display images and text with live wallpaper in the background -static void displayLiveWallPaper(int wResolution, int hResolution) { - bindProgramVertexOrtho(); - - drawGalaxy(); - - rsgBindProgramVertex(gProgVertex); - rsgBindProgramStore(gProgStoreBlendAlpha); - rsgBindProgramFragment(gProgFragmentTexture); - rsgBindSampler(gProgFragmentTexture, 0, gLinearClamp); - - drawMeshInPage(0, 0, wResolution, hResolution); - drawMeshInPage(-1.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(1.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(-2.0f*gRenderSurfaceW, 0, wResolution, hResolution); - drawMeshInPage(2.0f*gRenderSurfaceW, 0, wResolution, hResolution); -} - -void root(const void *v_in, void *v_out, const void *usrData, uint32_t x, uint32_t y) { - TestData *testData = (TestData*)usrData; - gRenderSurfaceW = testData->renderSurfaceW; - gRenderSurfaceH = testData->renderSurfaceH; - gDt = testData->dt; - - gData = (UiTestData*)v_in; - - switch(gData->testId) { - case 0: - displayIcons(gData->user1); - break; - case 1: - displayImageWithText(gData->user1, gData->user2, gData->user3); - break; - case 2: - displayListView(); - break; - case 3: - displayLiveWallPaper(gData->user1, gData->user2); - break; - default: - rsDebug("Wrong test number", 0); - break; - } -} diff --git a/tests/RenderScriptTests/SceneGraph/Android.mk b/tests/RenderScriptTests/SceneGraph/Android.mk deleted file mode 100644 index 6047305ceb70..000000000000 --- a/tests/RenderScriptTests/SceneGraph/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2011 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_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - -LOCAL_SDK_VERSION := 17 - -LOCAL_PACKAGE_NAME := SceneGraphTest - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml b/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml deleted file mode 100644 index 67af0fa04f53..000000000000 --- a/tests/RenderScriptTests/SceneGraph/AndroidManifest.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.testapp"> - <uses-permission - android:name="android.permission.INTERNET" /> - <application android:label="SceneGraphTest"> - <activity android:name="TestApp" - android:label="SceneGraphTest"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - <activity android:name="SimpleApp" - android:label="SimpleSceneGraph"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - <activity android:name="FileSelector" - android:label="FileSelector" - android:hardwareAccelerated="true"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg b/tests/RenderScriptTests/SceneGraph/assets/blue.jpg Binary files differdeleted file mode 100644 index 494e77a199e1..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/blue.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg b/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg Binary files differdeleted file mode 100644 index 2fcecb0be1f5..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/carbonfiber.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/assets/green.jpg b/tests/RenderScriptTests/SceneGraph/assets/green.jpg Binary files differdeleted file mode 100644 index a86a754fe2e3..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/green.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg b/tests/RenderScriptTests/SceneGraph/assets/grey.jpg Binary files differdeleted file mode 100644 index 5870b1af055e..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/grey.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg b/tests/RenderScriptTests/SceneGraph/assets/orange.jpg Binary files differdeleted file mode 100644 index 7dbe942af1a8..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/orange.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d Binary files differdeleted file mode 100644 index 07318ae11249..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.a3d +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae b/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae deleted file mode 100644 index 7eef443fa0e2..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/orientation_test.dae +++ /dev/null @@ -1,1102 +0,0 @@ -<?xml version="1.0" ?> -<COLLADA xmlns="http://www.collada.org/2005/11/COLLADASchema" version="1.4.1"> - <asset> - <contributor> - <author>alexst</author> - <authoring_tool>OpenCOLLADA2010</authoring_tool> - <comments>ColladaMaya export options: bakeTransforms=0;relativePaths=0;copyTextures=0;exportTriangles=1;exportCgfxFileReferences=0; isSampling=0;curveConstrainSampling=0;removeStaticCurves=1;exportPolygonMeshes=1;exportLights=1; exportCameras=1;exportJointsAndSkin=1;exportAnimations=0;exportInvisibleNodes=0;exportDefaultCameras=0; exportTexCoords=1;exportNormals=1;exportNormalsPerVertex=1;exportVertexColors=0;exportVertexColorsPerVertex=0; exportTexTangents=0;exportTangents=0;exportReferencedMaterials=1;exportMaterialsOnly=0; exportXRefs=1;dereferenceXRefs=1;exportCameraAsLookat=0;cameraXFov=0;cameraYFov=1;doublePrecision=0</comments> - <source_data>file:///Volumes/Android/art/orientation_test.mb</source_data> - </contributor> - <created>2011-09-30T15:31:38</created> - <modified>2011-09-30T15:31:38</modified> - <unit meter="0.01" name="centimeter" /> - <up_axis>Y_UP</up_axis> - </asset> - <library_cameras> - <camera id="cameraShape1" name="cameraShape1"> - <optics> - <technique_common> - <perspective> - <yfov>37.8493</yfov> - <aspect_ratio>1.5</aspect_ratio> - <znear>1</znear> - <zfar>400</zfar> - </perspective> - </technique_common> - </optics> - <extra> - <technique profile="OpenCOLLADAMaya"> - <film_fit>0</film_fit> - <film_fit_offset>0</film_fit_offset> - <film_offsetX>0</film_offsetX> - <film_offsetY>0</film_offsetY> - <horizontal_aperture>3.599993</horizontal_aperture> - <lens_squeeze>1</lens_squeeze> - <originalMayaNodeId>cameraShape1</originalMayaNodeId> - <vertical_aperture>2.399995</vertical_aperture> - </technique> - </extra> - </camera> - <camera id="CameraDistShape" name="CameraDistShape"> - <optics> - <technique_common> - <perspective> - <yfov>37.8493</yfov> - <aspect_ratio>1.5</aspect_ratio> - <znear>1</znear> - <zfar>1000</zfar> - </perspective> - </technique_common> - </optics> - <extra> - <technique profile="OpenCOLLADAMaya"> - <film_fit>0</film_fit> - <film_fit_offset>0</film_fit_offset> - <film_offsetX>0</film_offsetX> - <film_offsetY>0</film_offsetY> - <horizontal_aperture>3.599993</horizontal_aperture> - <lens_squeeze>1</lens_squeeze> - <originalMayaNodeId>CameraDistShape</originalMayaNodeId> - <vertical_aperture>2.399995</vertical_aperture> - </technique> - </extra> - </camera> - </library_cameras> - <library_materials> - <material id="Paint1" name="Paint1"> - <instance_effect url="#Paint1-fx" /> - </material> - <material id="lambert2" name="lambert2"> - <instance_effect url="#lambert2-fx" /> - </material> - <material id="Plastic" name="Plastic"> - <instance_effect url="#Plastic-fx" /> - </material> - <material id="Metal" name="Metal"> - <instance_effect url="#Metal-fx" /> - </material> - <material id="PlasticCenter" name="PlasticCenter"> - <instance_effect url="#PlasticCenter-fx" /> - </material> - <material id="PlasticRed" name="PlasticRed"> - <instance_effect url="#PlasticRed-fx" /> - </material> - <material id="lambert10" name="lambert10"> - <instance_effect url="#lambert10-fx" /> - </material> - <material id="lambert11" name="lambert11"> - <instance_effect url="#lambert11-fx" /> - </material> - </library_materials> - <library_effects> - <effect id="Metal-fx"> - <profile_COMMON> - <newparam sid="file23-surface"> - <surface type="2D"> - <init_from>file23</init_from> - </surface> - </newparam> - <newparam sid="file23-sampler"> - <sampler2D> - <source>file23-surface</source> - </sampler2D> - </newparam> - <technique sid="common"> - <lambert> - <emission> - <color>0 0 0 1</color> - </emission> - <ambient> - <color>0 0 0 1</color> - </ambient> - <diffuse> - <texture texture="file23-sampler" texcoord="TEX0"> - <extra> - <technique profile="OpenCOLLADAMaya"> - <blend_mode>NONE</blend_mode> - <coverageU>1</coverageU> - <coverageV>1</coverageV> - <fast>0</fast> - <mirrorU>0</mirrorU> - <mirrorV>0</mirrorV> - <noiseU>0</noiseU> - <noiseV>0</noiseV> - <offsetU>0</offsetU> - <offsetV>0</offsetV> - <repeatU>1</repeatU> - <repeatV>1</repeatV> - <rotateFrame>0</rotateFrame> - <rotateUV>0</rotateUV> - <stagger>0</stagger> - <translateFrameU>0</translateFrameU> - <translateFrameV>0</translateFrameV> - <wrapU>1</wrapU> - <wrapV>1</wrapV> - </technique> - </extra> - </texture> - </diffuse> - <transparent opaque="RGB_ZERO"> - <color>0 0 0 1</color> - </transparent> - <transparency> - <float>1</float> - </transparency> - </lambert> - </technique> - </profile_COMMON> - </effect> - <effect id="Paint1-fx"> - <profile_COMMON> - <newparam sid="file25-surface"> - <surface type="2D"> - <init_from>file25</init_from> - </surface> - </newparam> - <newparam sid="file25-sampler"> - <sampler2D> - <source>file25-surface</source> - </sampler2D> - </newparam> - <technique sid="common"> - <lambert> - <emission> - <color>0 0 0 1</color> - </emission> - <ambient> - <color>0 0 0 1</color> - </ambient> - <diffuse> - <texture texture="file25-sampler" texcoord="TEX0"> - <extra> - <technique profile="OpenCOLLADAMaya"> - <blend_mode>NONE</blend_mode> - <coverageU>1</coverageU> - <coverageV>1</coverageV> - <fast>0</fast> - <mirrorU>0</mirrorU> - <mirrorV>0</mirrorV> - <noiseU>0</noiseU> - <noiseV>0</noiseV> - <offsetU>0</offsetU> - <offsetV>0</offsetV> - <repeatU>1</repeatU> - <repeatV>1</repeatV> - <rotateFrame>0</rotateFrame> - <rotateUV>0</rotateUV> - <stagger>0</stagger> - <translateFrameU>0</translateFrameU> - <translateFrameV>0</translateFrameV> - <wrapU>1</wrapU> - <wrapV>1</wrapV> - </technique> - </extra> - </texture> - </diffuse> - <transparent opaque="RGB_ZERO"> - <color>0 0 0 1</color> - </transparent> - <transparency> - <float>1</float> - </transparency> - </lambert> - </technique> - </profile_COMMON> - </effect> - <effect id="Plastic-fx"> - <profile_COMMON> - <newparam sid="file24-surface"> - <surface type="2D"> - <init_from>file24</init_from> - </surface> - </newparam> - <newparam sid="file24-sampler"> - <sampler2D> - <source>file24-surface</source> - </sampler2D> - </newparam> - <technique sid="common"> - <lambert> - <emission> - <color>0 0 0 1</color> - </emission> - <ambient> - <color>0 0 0 1</color> - </ambient> - <diffuse> - <texture texture="file24-sampler" texcoord="TEX0"> - <extra> - <technique profile="OpenCOLLADAMaya"> - <blend_mode>NONE</blend_mode> - <coverageU>1</coverageU> - <coverageV>1</coverageV> - <fast>0</fast> - <mirrorU>0</mirrorU> - <mirrorV>0</mirrorV> - <noiseU>0</noiseU> - <noiseV>0</noiseV> - <offsetU>0</offsetU> - <offsetV>0</offsetV> - <repeatU>1</repeatU> - <repeatV>1</repeatV> - <rotateFrame>0</rotateFrame> - <rotateUV>0</rotateUV> - <stagger>0</stagger> - <translateFrameU>0</translateFrameU> - <translateFrameV>0</translateFrameV> - <wrapU>1</wrapU> - <wrapV>1</wrapV> - </technique> - </extra> - </texture> - </diffuse> - <transparent opaque="RGB_ZERO"> - <color>0 0 0 1</color> - </transparent> - <transparency> - <float>1</float> - </transparency> - </lambert> - </technique> - </profile_COMMON> - </effect> - <effect id="PlasticCenter-fx"> - <profile_COMMON> - <newparam sid="file24-surface"> - <surface type="2D"> - <init_from>file24</init_from> - </surface> - </newparam> - <newparam sid="file24-sampler"> - <sampler2D> - <source>file24-surface</source> - </sampler2D> - </newparam> - <technique sid="common"> - <lambert> - <emission> - <color>0 0 0 1</color> - </emission> - <ambient> - <color>0 0 0 1</color> - </ambient> - <diffuse> - <texture texture="file24-sampler" texcoord="TEX0"> - <extra> - <technique profile="OpenCOLLADAMaya"> - <blend_mode>NONE</blend_mode> - <coverageU>1</coverageU> - <coverageV>1</coverageV> - <fast>0</fast> - <mirrorU>0</mirrorU> - <mirrorV>0</mirrorV> - <noiseU>0</noiseU> - <noiseV>0</noiseV> - <offsetU>0</offsetU> - <offsetV>0</offsetV> - <repeatU>1</repeatU> - <repeatV>1</repeatV> - <rotateFrame>0</rotateFrame> - <rotateUV>0</rotateUV> - <stagger>0</stagger> - <translateFrameU>0</translateFrameU> - <translateFrameV>0</translateFrameV> - <wrapU>1</wrapU> - <wrapV>1</wrapV> - </technique> - </extra> - </texture> - </diffuse> - <transparent opaque="RGB_ZERO"> - <color>0 0 0 1</color> - </transparent> - <transparency> - <float>1</float> - </transparency> - </lambert> - </technique> - </profile_COMMON> - </effect> - <effect id="PlasticRed-fx"> - <profile_COMMON> - <newparam sid="file23-surface"> - <surface type="2D"> - <init_from>file23</init_from> - </surface> - </newparam> - <newparam sid="file23-sampler"> - <sampler2D> - <source>file23-surface</source> - </sampler2D> - </newparam> - <technique sid="common"> - <lambert> - <emission> - <color>0 0 0 1</color> - </emission> - <ambient> - <color>0 0 0 1</color> - </ambient> - <diffuse> - <texture texture="file23-sampler" texcoord="TEX0"> - <extra> - <technique profile="OpenCOLLADAMaya"> - <blend_mode>NONE</blend_mode> - <coverageU>1</coverageU> - <coverageV>1</coverageV> - <fast>0</fast> - <mirrorU>0</mirrorU> - <mirrorV>0</mirrorV> - <noiseU>0</noiseU> - <noiseV>0</noiseV> - <offsetU>0</offsetU> - <offsetV>0</offsetV> - <repeatU>1</repeatU> - <repeatV>1</repeatV> - <rotateFrame>0</rotateFrame> - <rotateUV>0</rotateUV> - <stagger>0</stagger> - <translateFrameU>0</translateFrameU> - <translateFrameV>0</translateFrameV> - <wrapU>1</wrapU> - <wrapV>1</wrapV> - </technique> - </extra> - </texture> - </diffuse> - <transparent opaque="RGB_ZERO"> - <color>0 0 0 1</color> - </transparent> - <transparency> - <float>1</float> - </transparency> - </lambert> - </technique> - </profile_COMMON> - </effect> - <effect id="lambert10-fx"> - <profile_COMMON> - <newparam sid="file28-surface"> - <surface type="2D"> - <init_from>file28</init_from> - </surface> - </newparam> - <newparam sid="file28-sampler"> - <sampler2D> - <source>file28-surface</source> - </sampler2D> - </newparam> - <technique sid="common"> - <lambert> - <emission> - <color>0 0 0 1</color> - </emission> - <ambient> - <color>0 0 0 1</color> - </ambient> - <diffuse> - <texture texture="file28-sampler" texcoord="TEX0"> - <extra> - <technique profile="OpenCOLLADAMaya"> - <blend_mode>NONE</blend_mode> - <coverageU>1</coverageU> - <coverageV>1</coverageV> - <fast>0</fast> - <mirrorU>0</mirrorU> - <mirrorV>0</mirrorV> - <noiseU>0</noiseU> - <noiseV>0</noiseV> - <offsetU>0</offsetU> - <offsetV>0</offsetV> - <repeatU>1</repeatU> - <repeatV>1</repeatV> - <rotateFrame>0</rotateFrame> - <rotateUV>0</rotateUV> - <stagger>0</stagger> - <translateFrameU>0</translateFrameU> - <translateFrameV>0</translateFrameV> - <wrapU>1</wrapU> - <wrapV>1</wrapV> - </technique> - </extra> - </texture> - </diffuse> - <transparent opaque="RGB_ZERO"> - <color>0 0 0 1</color> - </transparent> - <transparency> - <float>1</float> - </transparency> - </lambert> - </technique> - </profile_COMMON> - </effect> - <effect id="lambert11-fx"> - <profile_COMMON> - <newparam sid="file29-surface"> - <surface type="2D"> - <init_from>file29</init_from> - </surface> - </newparam> - <newparam sid="file29-sampler"> - <sampler2D> - <source>file29-surface</source> - </sampler2D> - </newparam> - <technique sid="common"> - <lambert> - <emission> - <color>0 0 0 1</color> - </emission> - <ambient> - <color>0 0 0 1</color> - </ambient> - <diffuse> - <texture texture="file29-sampler" texcoord="TEX0"> - <extra> - <technique profile="OpenCOLLADAMaya"> - <blend_mode>NONE</blend_mode> - <coverageU>1</coverageU> - <coverageV>1</coverageV> - <fast>0</fast> - <mirrorU>0</mirrorU> - <mirrorV>0</mirrorV> - <noiseU>0</noiseU> - <noiseV>0</noiseV> - <offsetU>0</offsetU> - <offsetV>0</offsetV> - <repeatU>1</repeatU> - <repeatV>1</repeatV> - <rotateFrame>0</rotateFrame> - <rotateUV>0</rotateUV> - <stagger>0</stagger> - <translateFrameU>0</translateFrameU> - <translateFrameV>0</translateFrameV> - <wrapU>1</wrapU> - <wrapV>1</wrapV> - </technique> - </extra> - </texture> - </diffuse> - <transparent opaque="RGB_ZERO"> - <color>0 0 0 1</color> - </transparent> - <transparency> - <float>1</float> - </transparency> - </lambert> - </technique> - </profile_COMMON> - </effect> - <effect id="lambert2-fx"> - <profile_COMMON> - <newparam sid="file22-surface"> - <surface type="2D"> - <init_from>file22</init_from> - </surface> - </newparam> - <newparam sid="file22-sampler"> - <sampler2D> - <source>file22-surface</source> - </sampler2D> - </newparam> - <technique sid="common"> - <lambert> - <emission> - <color>0 0 0 1</color> - </emission> - <ambient> - <color>0 0 0 1</color> - </ambient> - <diffuse> - <texture texture="file22-sampler" texcoord="TEX0"> - <extra> - <technique profile="OpenCOLLADAMaya"> - <blend_mode>NONE</blend_mode> - <coverageU>1</coverageU> - <coverageV>1</coverageV> - <fast>0</fast> - <mirrorU>0</mirrorU> - <mirrorV>0</mirrorV> - <noiseU>0</noiseU> - <noiseV>0</noiseV> - <offsetU>0</offsetU> - <offsetV>0</offsetV> - <repeatU>1</repeatU> - <repeatV>1</repeatV> - <rotateFrame>0</rotateFrame> - <rotateUV>0</rotateUV> - <stagger>0</stagger> - <translateFrameU>0</translateFrameU> - <translateFrameV>0</translateFrameV> - <wrapU>1</wrapU> - <wrapV>1</wrapV> - </technique> - </extra> - </texture> - </diffuse> - <transparent opaque="RGB_ZERO"> - <color>0 0 0 1</color> - </transparent> - <transparency> - <float>1</float> - </transparency> - </lambert> - </technique> - </profile_COMMON> - </effect> - </library_effects> - <library_images> - <image id="file29" name="file29" height="0" width="0"> - <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/blue.jpg</init_from> - <extra> - <technique profile="OpenCOLLADAMaya"> - <dgnode_type>kFile</dgnode_type> - <image_sequence>0</image_sequence> - <originalMayaNodeId>file29</originalMayaNodeId> - </technique> - </extra> - </image> - <image id="file25" name="file25" height="0" width="0"> - <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/carbonfiber.jpg</init_from> - <extra> - <technique profile="OpenCOLLADAMaya"> - <dgnode_type>kFile</dgnode_type> - <image_sequence>0</image_sequence> - <originalMayaNodeId>file25</originalMayaNodeId> - </technique> - </extra> - </image> - <image id="file28" name="file28" height="0" width="0"> - <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/green.jpg</init_from> - <extra> - <technique profile="OpenCOLLADAMaya"> - <dgnode_type>kFile</dgnode_type> - <image_sequence>0</image_sequence> - <originalMayaNodeId>file28</originalMayaNodeId> - </technique> - </extra> - </image> - <image id="file22" name="file22" height="0" width="0"> - <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/grey.jpg</init_from> - <extra> - <technique profile="OpenCOLLADAMaya"> - <dgnode_type>kFile</dgnode_type> - <image_sequence>0</image_sequence> - <originalMayaNodeId>file22</originalMayaNodeId> - </technique> - </extra> - </image> - <image id="file24" name="file24" height="0" width="0"> - <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/orange.jpg</init_from> - <extra> - <technique profile="OpenCOLLADAMaya"> - <dgnode_type>kFile</dgnode_type> - <image_sequence>0</image_sequence> - <originalMayaNodeId>file24</originalMayaNodeId> - </technique> - </extra> - </image> - <image id="file23" name="file23" height="0" width="0"> - <init_from>file:///Volumes/Android/Sanity/SceneGraph/assets/red.jpg</init_from> - <extra> - <technique profile="OpenCOLLADAMaya"> - <dgnode_type>kFile</dgnode_type> - <image_sequence>0</image_sequence> - <originalMayaNodeId>file23</originalMayaNodeId> - </technique> - </extra> - </image> - </library_images> - <library_visual_scenes> - <visual_scene id="VisualSceneNode" name="orientation_test"> - <node id="camera1" name="camera1"> - <translate sid="translate">24.5791 14.1321 31.4654</translate> - <rotate sid="rotateZ">0 0 1 0</rotate> - <rotate sid="rotateY">0 1 0 42</rotate> - <rotate sid="rotateX">1 0 0 -16.2</rotate> - <scale sid="scale">1 1 1</scale> - <instance_camera url="#cameraShape1" /> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>camera1</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="CameraAim" name="CameraAim"> - <translate sid="translate">0.0209301 3.68542 2.06912</translate> - <rotate sid="rotateY">0 1 0 43.2561</rotate> - <rotate sid="rotateX">1 0 0 -20</rotate> - <scale sid="scale">1 1 1</scale> - <node id="CameraDist" name="CameraDist"> - <translate sid="translate">0 0 45</translate> - <scale sid="scale">1 1 1</scale> - <instance_camera url="#CameraDistShape" /> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>CameraDist</originalMayaNodeId> - </technique> - </extra> - </node> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>CameraAim</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere4" name="pSphere4"> - <translate sid="translate">-9.69237 0 7.70498</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape4"> - <bind_material> - <technique_common> - <instance_material symbol="lambert7SG" target="#Paint1"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere4</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere1" name="pSphere1"> - <translate sid="translate">13.0966 0 5.76254</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape1"> - <bind_material> - <technique_common> - <instance_material symbol="lambert7SG" target="#Paint1"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere1</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere2" name="pSphere2"> - <translate sid="translate">21.7661 0 -13.6375</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape2"> - <bind_material> - <technique_common> - <instance_material symbol="lambert7SG" target="#Paint1"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere2</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere3" name="pSphere3"> - <translate sid="translate">-13.862 0 -13.6154</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape3"> - <bind_material> - <technique_common> - <instance_material symbol="lambert7SG" target="#Paint1"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere3</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere5" name="pSphere5"> - <translate sid="translate">31.0862 0 18.5992</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape5"> - <bind_material> - <technique_common> - <instance_material symbol="lambert7SG" target="#Paint1"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere5</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pCube1" name="pCube1"> - <translate sid="translate">0 0 0</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pCubeShape1"> - <bind_material> - <technique_common> - <instance_material symbol="lambert4SG" target="#lambert2"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pCube1</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="group1" name="group1"> - <translate sid="translate">0 0 0</translate> - <rotate sid="rotateZ">0 0 1 -162.693</rotate> - <rotate sid="rotateY">0 1 0 21.3345</rotate> - <rotate sid="rotateX">1 0 0 -100.567</rotate> - <scale sid="scale">1 1 1</scale> - <node id="pSphere6" name="pSphere6"> - <translate sid="translate">-13.862 0 -13.6154</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape6"> - <bind_material> - <technique_common> - <instance_material symbol="lambert6SG" target="#Plastic"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere6</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere7" name="pSphere7"> - <translate sid="translate">-9.69237 0 7.70498</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape7"> - <bind_material> - <technique_common> - <instance_material symbol="lambert6SG" target="#Plastic"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere7</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere8" name="pSphere8"> - <translate sid="translate">21.7661 0 -13.6375</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape8"> - <bind_material> - <technique_common> - <instance_material symbol="lambert6SG" target="#Plastic"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere8</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere9" name="pSphere9"> - <translate sid="translate">13.0966 0 5.76254</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape9"> - <bind_material> - <technique_common> - <instance_material symbol="lambert6SG" target="#Plastic"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere9</originalMayaNodeId> - </technique> - </extra> - </node> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>group1</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="group2" name="group2"> - <translate sid="translate">0 0 0</translate> - <rotate sid="rotateZ">0 0 1 45.4017</rotate> - <rotate sid="rotateY">0 1 0 79.393</rotate> - <rotate sid="rotateX">1 0 0 5.10889</rotate> - <scale sid="scale">1 1 1</scale> - <node id="pSphere10" name="pSphere10"> - <translate sid="translate">31.0862 0 18.5992</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape10"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere10</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere11" name="pSphere11"> - <translate sid="translate">13.0966 0 5.76254</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape11"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere11</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere12" name="pSphere12"> - <translate sid="translate">7.4784 16.3496 7.36882</translate> - <rotate sid="rotateZ">0 0 1 17.3073</rotate> - <rotate sid="rotateY">0 1 0 158.666</rotate> - <rotate sid="rotateX">1 0 0 79.4335</rotate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape12"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere12</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere13" name="pSphere13"> - <translate sid="translate">-9.69237 0 7.70498</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape13"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere13</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere14" name="pSphere14"> - <translate sid="translate">11.3635 -4.3926 2.21012</translate> - <rotate sid="rotateZ">0 0 1 17.3073</rotate> - <rotate sid="rotateY">0 1 0 158.666</rotate> - <rotate sid="rotateX">1 0 0 79.4335</rotate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape14"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere14</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere15" name="pSphere15"> - <translate sid="translate">21.7661 0 -13.6375</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape15"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere15</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere16" name="pSphere16"> - <translate sid="translate">-9.5945 -8.92317 -5.74901</translate> - <rotate sid="rotateZ">0 0 1 17.3073</rotate> - <rotate sid="rotateY">0 1 0 158.666</rotate> - <rotate sid="rotateX">1 0 0 79.4335</rotate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape16"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere16</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere17" name="pSphere17"> - <translate sid="translate">-13.862 0 -13.6154</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape17"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere17</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pSphere18" name="pSphere18"> - <translate sid="translate">-24.2135 6.497 -5.58935</translate> - <rotate sid="rotateZ">0 0 1 17.3073</rotate> - <rotate sid="rotateY">0 1 0 158.666</rotate> - <rotate sid="rotateX">1 0 0 79.4335</rotate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pSphereShape18"> - <bind_material> - <technique_common> - <instance_material symbol="lambert5SG" target="#Metal"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pSphere18</originalMayaNodeId> - </technique> - </extra> - </node> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>group2</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pCube2" name="pCube2"> - <translate sid="translate">0 0 0</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pCubeShape2"> - <bind_material> - <technique_common> - <instance_material symbol="lambert8SG" target="#PlasticCenter"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pCube2</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pCube3" name="pCube3"> - <translate sid="translate">15 0 0</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pCubeShape3"> - <bind_material> - <technique_common> - <instance_material symbol="lambert9SG" target="#PlasticRed"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pCube3</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pCube4" name="pCube4"> - <translate sid="translate">0 15 0</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pCubeShape4"> - <bind_material> - <technique_common> - <instance_material symbol="lambert10SG" target="#lambert10"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pCube4</originalMayaNodeId> - </technique> - </extra> - </node> - <node id="pCube5" name="pCube5"> - <translate sid="translate">0 0 15</translate> - <scale sid="scale">1 1 1</scale> - <instance_geometry url="#pCubeShape5"> - <bind_material> - <technique_common> - <instance_material symbol="lambert11SG" target="#lambert11"> - <bind_vertex_input semantic="TEX0" input_semantic="TEXCOORD" input_set="0" /> - </instance_material> - </technique_common> - </bind_material> - </instance_geometry> - <extra> - <technique profile="OpenCOLLADAMaya"> - <originalMayaNodeId>pCube5</originalMayaNodeId> - </technique> - </extra> - </node> - </visual_scene> - </library_visual_scenes> - <scene> - <instance_visual_scene url="#VisualSceneNode" /> - </scene> -</COLLADA> diff --git a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg b/tests/RenderScriptTests/SceneGraph/assets/paint.jpg Binary files differdeleted file mode 100644 index 0791045b5c18..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/paint.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/assets/red.jpg b/tests/RenderScriptTests/SceneGraph/assets/red.jpg Binary files differdeleted file mode 100644 index 320a2a6ad187..000000000000 --- a/tests/RenderScriptTests/SceneGraph/assets/red.jpg +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/icon.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/icon.png Binary files differdeleted file mode 100644 index ff34a7ffcc4f..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/icon.png +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png Binary files differdeleted file mode 100644 index f7353fd61c5b..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/drawable-nodpi/robot.png +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml b/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml deleted file mode 100644 index 9ea3010759b6..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/menu/loader_menu.xml +++ /dev/null @@ -1,25 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -* Copyright (C) 2011 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. -*/ ---> - -<menu xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:id="@+id/load_model" - android:title="@string/load_model" /> - <item android:id="@+id/use_blur" - android:title="@string/use_blur" /> -</menu> diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl deleted file mode 100644 index c34adc9e334d..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/blur_h.glsl +++ /dev/null @@ -1,15 +0,0 @@ -varying vec2 varTex0; - -void main() { - vec2 blurCoord = varTex0; - blurCoord.x = varTex0.x + UNI_blurOffset0; - vec3 col = texture2D(UNI_color, blurCoord).rgb; - blurCoord.x = varTex0.x + UNI_blurOffset1; - col += texture2D(UNI_color, blurCoord).rgb; - blurCoord.x = varTex0.x + UNI_blurOffset2; - col += texture2D(UNI_color, blurCoord).rgb; - blurCoord.x = varTex0.x + UNI_blurOffset3; - col += texture2D(UNI_color, blurCoord).rgb; - - gl_FragColor = vec4(col * 0.25, 0.0); -} diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl deleted file mode 100644 index ade05a27920d..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/blur_v.glsl +++ /dev/null @@ -1,17 +0,0 @@ -varying vec2 varTex0; - -void main() { - vec2 blurCoord = varTex0; - blurCoord.y = varTex0.y + UNI_blurOffset0; - vec3 col = texture2D(UNI_color, blurCoord).rgb; - blurCoord.y = varTex0.y + UNI_blurOffset1; - col += texture2D(UNI_color, blurCoord).rgb; - blurCoord.y = varTex0.y + UNI_blurOffset2; - col += texture2D(UNI_color, blurCoord).rgb; - blurCoord.y = varTex0.y + UNI_blurOffset3; - col += texture2D(UNI_color, blurCoord).rgb; - - col = col * 0.25; - - gl_FragColor = vec4(col, 0.0); -} diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl deleted file mode 100644 index bc824b6eb77e..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/blur_vertex.glsl +++ /dev/null @@ -1,7 +0,0 @@ -varying vec2 varTex0; - -void main() { - gl_Position = ATTRIB_position; - varTex0 = ATTRIB_texture0; -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl deleted file mode 100644 index 2eb102872afd..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse.glsl +++ /dev/null @@ -1,19 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -void main() { - - vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); - vec3 worldNorm = (varWorldNormal); - - vec3 light0Vec = V; - vec3 light0R = reflect(light0Vec, worldNorm); - float light0_Diffuse = dot(worldNorm, light0Vec); - - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_diffuse, t0).rgba; - col.xyz = col.xyz * light0_Diffuse * 1.2; - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/diffuse_lights.glsl deleted file mode 100644 index ef93e1c27ad2..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/diffuse_lights.glsl +++ /dev/null @@ -1,22 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -void main() { - - vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); - vec3 worldNorm = normalize(varWorldNormal); - - vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz); - float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0); - - vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz); - float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0); - - vec2 t0 = varTex0.xy; - lowp vec4 col = UNI_diffuse; - col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz + - light1_Diffuse * UNI_lightColor_1.xyz); - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl deleted file mode 100644 index b90a7b27354c..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/metal.glsl +++ /dev/null @@ -1,23 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -void main() { - - vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); - vec3 worldNorm = normalize(varWorldNormal); - - vec3 light0Vec = V; - vec3 light0R = reflect(light0Vec, worldNorm); - float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0); - float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0); - float light0_Specular = pow(light0Spec, 15.0) * 0.5; - - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_diffuse, t0).rgba; - col.xyz = col.xyz * (textureCube(UNI_reflection, worldNorm).rgb * 0.5 + vec3(light0_Diffuse)); - col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0); - - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl deleted file mode 100644 index f3b89ede5369..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/paintf.glsl +++ /dev/null @@ -1,26 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -void main() { - - vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); - vec3 worldNorm = normalize(varWorldNormal); - - vec3 light0Vec = V; - vec3 light0R = reflect(light0Vec, worldNorm); - float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.01, 0.99); - float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0); - float light0_Specular = pow(light0Spec, 150.0) * 0.5; - - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_diffuse, t0).rgba; - col.xyz = col.xyz * light0_Diffuse * 1.1; - col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0); - - float fresnel = mix(pow(1.0 - light0_Diffuse, 15.0), 1.0, 0.1); - col.xyz = mix(col.xyz, textureCube(UNI_reflection, -light0R).rgb * 2.4, fresnel); - col.w = 0.8; - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl deleted file mode 100644 index 56f7151f22af..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/plastic.glsl +++ /dev/null @@ -1,22 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -void main() { - - vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); - vec3 worldNorm = normalize(varWorldNormal); - - vec3 light0Vec = V; - vec3 light0R = reflect(light0Vec, worldNorm); - float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0); - float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0); - float light0_Specular = pow(light0Spec, 10.0) * 0.5; - - vec2 t0 = varTex0.xy; - lowp vec4 col = texture2D(UNI_diffuse, t0).rgba; - col.xyz = col.xyz * light0_Diffuse * 1.2; - col.xyz += light0_Specular * vec3(0.8, 0.8, 1.0); - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl deleted file mode 100644 index b2536226afb7..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/plastic_lights.glsl +++ /dev/null @@ -1,29 +0,0 @@ -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -void main() { - - vec3 V = normalize(UNI_cameraPos.xyz - varWorldPos.xyz); - vec3 worldNorm = normalize(varWorldNormal); - - vec3 light0Vec = normalize(UNI_lightPos_0.xyz - varWorldPos.xyz); - vec3 light0R = reflect(light0Vec, worldNorm); - float light0_Diffuse = clamp(dot(worldNorm, light0Vec), 0.0, 1.0); - float light0Spec = clamp(dot(-light0R, V), 0.001, 1.0); - float light0_Specular = pow(light0Spec, 10.0) * 0.7; - - vec3 light1Vec = normalize(UNI_lightPos_1.xyz - varWorldPos.xyz); - vec3 light1R = reflect(light1Vec, worldNorm); - float light1_Diffuse = clamp(dot(worldNorm, light1Vec), 0.0, 1.0); - float light1Spec = clamp(dot(-light1R, V), 0.001, 1.0); - float light1_Specular = pow(light1Spec, 10.0) * 0.7; - - vec2 t0 = varTex0.xy; - lowp vec4 col = UNI_diffuse; - col.xyz = col.xyz * (light0_Diffuse * UNI_lightColor_0.xyz + - light1_Diffuse * UNI_lightColor_1.xyz); - col.xyz += (light0_Specular + light1_Specular); - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d Binary files differdeleted file mode 100644 index f48895cd8451..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/robot.a3d +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl deleted file mode 100644 index 1a927cab6236..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/select_color.glsl +++ /dev/null @@ -1,13 +0,0 @@ -varying vec2 varTex0; - -void main() { - vec3 col = texture2D(UNI_color, varTex0).rgb; - - vec3 desat = vec3(0.299, 0.587, 0.114); - float lum = dot(desat, col); - float stepVal = step(lum, 0.8); - col = mix(col, vec3(0.0), stepVal)*0.5; - - gl_FragColor = vec4(col, 0.0); -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl deleted file mode 100644 index 7910a5448675..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/shader2v.glsl +++ /dev/null @@ -1,22 +0,0 @@ -/* - rs_matrix4x4 model; - rs_matrix4x4 viewProj; -*/ - -varying vec3 varWorldPos; -varying vec3 varWorldNormal; -varying vec2 varTex0; - -// This is where actual shader code begins -void main() { - vec4 objPos = ATTRIB_position; - vec4 worldPos = UNI_model * objPos; - gl_Position = UNI_viewProj * worldPos; - - mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz); - vec3 worldNorm = model3 * ATTRIB_normal; - - varWorldPos = worldPos.xyz; - varWorldNormal = worldNorm; - varTex0 = ATTRIB_texture0; -} diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl b/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl deleted file mode 100644 index 662ecd852af2..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/texture.glsl +++ /dev/null @@ -1,7 +0,0 @@ -varying vec2 varTex0; - -void main() { - lowp vec4 col = texture2D(UNI_color, varTex0).rgba; - gl_FragColor = col; -} - diff --git a/tests/RenderScriptTests/SceneGraph/res/raw/unit_obj.a3d b/tests/RenderScriptTests/SceneGraph/res/raw/unit_obj.a3d Binary files differdeleted file mode 100644 index 56eff046c696..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/raw/unit_obj.a3d +++ /dev/null diff --git a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml b/tests/RenderScriptTests/SceneGraph/res/values/strings.xml deleted file mode 100644 index c916d791c143..000000000000 --- a/tests/RenderScriptTests/SceneGraph/res/values/strings.xml +++ /dev/null @@ -1,24 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- -/* -* Copyright (C) 2011 The Android Open Source Project -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ ---> - -<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> - <skip /> - <string name="load_model">Load Model</string> - <string name="use_blur">Use Blur</string> -</resources> diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java deleted file mode 100644 index 42f2be5e1f59..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Camera.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import com.android.scenegraph.SceneManager; - -import android.renderscript.*; -import android.renderscript.Matrix4f; -import android.renderscript.RenderScriptGL; -import android.util.Log; - -/** - * @hide - */ -public class Camera extends SceneGraphBase { - - Transform mTransform; - - ScriptField_Camera_s.Item mData; - ScriptField_Camera_s mField; - - public Camera() { - mData = new ScriptField_Camera_s.Item(); - mData.near = 0.1f; - mData.far = 1000.0f; - mData.horizontalFOV = 60.0f; - mData.aspect = 0; - } - - public void setTransform(Transform t) { - mTransform = t; - if (mField != null) { - mField.set_transformMatrix(0, mTransform.getRSData().getAllocation(), true); - mField.set_isDirty(0, 1, true); - } - } - public void setFOV(float fov) { - mData.horizontalFOV = fov; - if (mField != null) { - mField.set_horizontalFOV(0, fov, true); - mField.set_isDirty(0, 1, true); - } - } - - public void setNear(float n) { - mData.near = n; - if (mField != null) { - mField.set_near(0, n, true); - mField.set_isDirty(0, 1, true); - } - } - - public void setFar(float f) { - mData.far = f; - if (mField != null) { - mField.set_far(0, f, true); - mField.set_isDirty(0, 1, true); - } - } - - public void setName(String n) { - super.setName(n); - if (mField != null) { - RenderScriptGL rs = SceneManager.getRS(); - mData.name = getNameAlloc(rs); - mField.set_name(0, mData.name, true); - mField.set_isDirty(0, 1, true); - } - } - - ScriptField_Camera_s getRSData() { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - if (rs == null) { - return null; - } - - if (mTransform == null) { - throw new RuntimeException("Cameras without transforms are invalid"); - } - - mField = new ScriptField_Camera_s(rs, 1); - - mData.transformMatrix = mTransform.getRSData().getAllocation(); - mData.transformTimestamp = 1; - mData.timestamp = 1; - mData.isDirty = 1; - mData.name = getNameAlloc(rs); - mField.set(mData, 0, true); - - return mField; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java deleted file mode 100644 index b4b6fb9b795b..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaParser.java +++ /dev/null @@ -1,563 +0,0 @@ -/*
- * Copyright (C) 2011 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.scenegraph;
-import com.android.scenegraph.CompoundTransform.TranslateComponent;
-import com.android.scenegraph.CompoundTransform.RotateComponent;
-import com.android.scenegraph.CompoundTransform.ScaleComponent;
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.StringTokenizer;
-import java.util.HashMap;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.ParserConfigurationException;
-
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.SAXException;
-
-import android.renderscript.*;
-import android.util.Log;
-
-public class ColladaParser {
- static final String TAG = "ColladaParser";
- Document mDom;
-
- HashMap<String, LightBase> mLights;
- HashMap<String, Camera> mCameras;
- HashMap<String, ArrayList<ShaderParam> > mEffectsParams;
- HashMap<String, Texture2D> mImages;
- HashMap<String, Texture2D> mSamplerImageMap;
- HashMap<String, String> mMeshIdNameMap;
- Scene mScene;
-
- String mRootDir;
-
- String toString(Float3 v) {
- String valueStr = v.x + " " + v.y + " " + v.z;
- return valueStr;
- }
-
- String toString(Float4 v) {
- String valueStr = v.x + " " + v.y + " " + v.z + " " + v.w;
- return valueStr;
- }
-
- public ColladaParser(){
- mLights = new HashMap<String, LightBase>();
- mCameras = new HashMap<String, Camera>();
- mEffectsParams = new HashMap<String, ArrayList<ShaderParam> >();
- mImages = new HashMap<String, Texture2D>();
- mMeshIdNameMap = new HashMap<String, String>();
- }
-
- public void init(InputStream is, String rootDir) {
- mLights.clear();
- mCameras.clear();
- mEffectsParams.clear();
-
- mRootDir = rootDir;
-
- long start = System.currentTimeMillis();
- DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
- try {
- DocumentBuilder db = dbf.newDocumentBuilder();
- mDom = db.parse(is);
- } catch(ParserConfigurationException e) {
- e.printStackTrace();
- } catch(SAXException e) {
- e.printStackTrace();
- } catch(IOException e) {
- e.printStackTrace();
- }
- long end = System.currentTimeMillis();
- Log.v("TIMER", " Parse time: " + (end - start));
- exportSceneData();
- }
-
- Scene getScene() {
- return mScene;
- }
-
- private void exportSceneData(){
- mScene = new Scene();
-
- Element docEle = mDom.getDocumentElement();
- NodeList nl = docEle.getElementsByTagName("light");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element l = (Element)nl.item(i);
- convertLight(l);
- }
- }
-
- nl = docEle.getElementsByTagName("camera");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element c = (Element)nl.item(i);
- convertCamera(c);
- }
- }
-
- nl = docEle.getElementsByTagName("image");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element img = (Element)nl.item(i);
- convertImage(img);
- }
- }
-
- nl = docEle.getElementsByTagName("effect");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element e = (Element)nl.item(i);
- convertEffects(e);
- }
- }
-
- // Material is just a link to the effect
- nl = docEle.getElementsByTagName("material");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element m = (Element)nl.item(i);
- convertMaterials(m);
- }
- }
-
- // Look through the geometry list and build up a correlation between id's and names
- nl = docEle.getElementsByTagName("geometry");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element m = (Element)nl.item(i);
- convertGeometries(m);
- }
- }
-
-
- nl = docEle.getElementsByTagName("visual_scene");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element s = (Element)nl.item(i);
- getScene(s);
- }
- }
- }
-
- private void getRenderable(Element shape, Transform t) {
- String geoURL = shape.getAttribute("url").substring(1);
- String geoName = mMeshIdNameMap.get(geoURL);
- if (geoName != null) {
- geoURL = geoName;
- }
- //RenderableGroup group = new RenderableGroup();
- //group.setName(geoURL.substring(1));
- //mScene.appendRenderable(group);
- NodeList nl = shape.getElementsByTagName("instance_material");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element materialRef = (Element)nl.item(i);
- String meshIndexName = materialRef.getAttribute("symbol");
- String materialName = materialRef.getAttribute("target");
-
- Renderable d = new Renderable();
- d.setMesh(geoURL, meshIndexName);
- d.setMaterialName(materialName.substring(1));
- d.setName(geoURL);
-
- //Log.v(TAG, "Created drawable geo " + geoURL + " index " + meshIndexName + " material " + materialName);
-
- d.setTransform(t);
- //Log.v(TAG, "Set source param " + t.getName());
-
- // Now find all the parameters that exist on the material
- ArrayList<ShaderParam> materialParams;
- materialParams = mEffectsParams.get(materialName.substring(1));
- for (int pI = 0; pI < materialParams.size(); pI ++) {
- d.appendSourceParams(materialParams.get(pI));
- //Log.v(TAG, "Set source param i: " + pI + " name " + materialParams.get(pI).getParamName());
- }
- mScene.appendRenderable(d);
- //group.appendChildren(d);
- }
- }
- }
-
- private void updateLight(Element shape, Transform t) {
- String lightURL = shape.getAttribute("url");
- // collada uses a uri structure to link things,
- // but we ignore it for now and do a simple search
- LightBase light = mLights.get(lightURL.substring(1));
- if (light != null) {
- light.setTransform(t);
- //Log.v(TAG, "Set Light " + light.getName() + " " + t.getName());
- }
- }
-
- private void updateCamera(Element shape, Transform t) {
- String camURL = shape.getAttribute("url");
- // collada uses a uri structure to link things,
- // but we ignore it for now and do a simple search
- Camera cam = mCameras.get(camURL.substring(1));
- if (cam != null) {
- cam.setTransform(t);
- //Log.v(TAG, "Set Camera " + cam.getName() + " " + t.getName());
- }
- }
-
- private void getNode(Element node, Transform parent, String indent) {
- String name = node.getAttribute("name");
- String id = node.getAttribute("id");
- CompoundTransform current = new CompoundTransform();
- current.setName(name);
- if (parent != null) {
- parent.appendChild(current);
- } else {
- mScene.appendTransform(current);
- }
-
- mScene.addToTransformMap(current);
-
- //Log.v(TAG, indent + "|");
- //Log.v(TAG, indent + "[" + name + "]");
-
- Node childNode = node.getFirstChild();
- while (childNode != null) {
- if (childNode.getNodeType() == Node.ELEMENT_NODE) {
- Element field = (Element)childNode;
- String fieldName = field.getTagName();
- String description = field.getAttribute("sid");
- if (fieldName.equals("translate")) {
- Float3 value = getFloat3(field);
- current.addTranslate(description, value);
- //Log.v(TAG, indent + " translate " + description + toString(value));
- } else if (fieldName.equals("rotate")) {
- Float4 value = getFloat4(field);
- //Log.v(TAG, indent + " rotate " + description + toString(value));
- Float3 axis = new Float3(value.x, value.y, value.z);
- current.addRotate(description, axis, value.w);
- } else if (fieldName.equals("scale")) {
- Float3 value = getFloat3(field);
- //Log.v(TAG, indent + " scale " + description + toString(value));
- current.addScale(description, value);
- } else if (fieldName.equals("instance_geometry")) {
- getRenderable(field, current);
- } else if (fieldName.equals("instance_light")) {
- updateLight(field, current);
- } else if (fieldName.equals("instance_camera")) {
- updateCamera(field, current);
- } else if (fieldName.equals("node")) {
- getNode(field, current, indent + " ");
- }
- }
- childNode = childNode.getNextSibling();
- }
- }
-
- // This will find the actual texture node, which is sometimes hidden behind a sampler
- // and sometimes referenced directly
- Texture2D getTexture(String samplerName) {
- String texName = samplerName;
-
- // Check to see if the image file is hidden by a sampler surface link combo
- Element sampler = mDom.getElementById(samplerName);
- if (sampler != null) {
- NodeList nl = sampler.getElementsByTagName("source");
- if (nl != null && nl.getLength() == 1) {
- Element ref = (Element)nl.item(0);
- String surfaceName = getString(ref);
- if (surfaceName == null) {
- return null;
- }
-
- Element surface = mDom.getElementById(surfaceName);
- if (surface == null) {
- return null;
- }
- nl = surface.getElementsByTagName("init_from");
- if (nl != null && nl.getLength() == 1) {
- ref = (Element)nl.item(0);
- texName = getString(ref);
- }
- }
- }
-
- //Log.v(TAG, "Extracted texture name " + texName);
- return mImages.get(texName);
- }
-
- void extractParams(Element fx, ArrayList<ShaderParam> params) {
- Node paramNode = fx.getFirstChild();
- while (paramNode != null) {
- if (paramNode.getNodeType() == Node.ELEMENT_NODE) {
- String name = paramNode.getNodeName();
- // Now find what type it is
- Node typeNode = paramNode.getFirstChild();
- while (typeNode != null && typeNode.getNodeType() != Node.ELEMENT_NODE) {
- typeNode = typeNode.getNextSibling();
- }
- String paramType = typeNode.getNodeName();
- Element typeElem = (Element)typeNode;
- ShaderParam sceneParam = null;
- if (paramType.equals("color")) {
- Float4Param f4p = new Float4Param(name);
- Float4 value = getFloat4(typeElem);
- f4p.setValue(value);
- sceneParam = f4p;
- //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + toString(value));
- } else if (paramType.equals("float")) {
- Float4Param f4p = new Float4Param(name);
- float value = getFloat(typeElem);
- f4p.setValue(new Float4(value, value, value, value));
- sceneParam = f4p;
- //Log.v(TAG, "Extracted " + sceneParam.getParamName() + " value " + value);
- } else if (paramType.equals("texture")) {
- String samplerName = typeElem.getAttribute("texture");
- Texture2D tex = getTexture(samplerName);
- TextureParam texP = new TextureParam(name);
- texP.setTexture(tex);
- sceneParam = texP;
- //Log.v(TAG, "Extracted texture " + tex);
- }
- if (sceneParam != null) {
- params.add(sceneParam);
- }
- }
- paramNode = paramNode.getNextSibling();
- }
- }
-
- private void convertMaterials(Element mat) {
- String id = mat.getAttribute("id");
- NodeList nl = mat.getElementsByTagName("instance_effect");
- if (nl != null && nl.getLength() == 1) {
- Element ref = (Element)nl.item(0);
- String url = ref.getAttribute("url");
- ArrayList<ShaderParam> params = mEffectsParams.get(url.substring(1));
- mEffectsParams.put(id, params);
- }
- }
-
- private void convertGeometries(Element geo) {
- String id = geo.getAttribute("id");
- String name = geo.getAttribute("name");
- if (!id.equals(name)) {
- mMeshIdNameMap.put(id, name);
- }
- }
-
- private void convertEffects(Element fx) {
- String id = fx.getAttribute("id");
- ArrayList<ShaderParam> params = new ArrayList<ShaderParam>();
-
- NodeList nl = fx.getElementsByTagName("newparam");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element field = (Element)nl.item(i);
- field.setIdAttribute("sid", true);
- }
- }
-
- nl = fx.getElementsByTagName("blinn");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element field = (Element)nl.item(i);
- //Log.v(TAG, "blinn");
- extractParams(field, params);
- }
- }
- nl = fx.getElementsByTagName("lambert");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element field = (Element)nl.item(i);
- //Log.v(TAG, "lambert");
- extractParams(field, params);
- }
- }
- nl = fx.getElementsByTagName("phong");
- if (nl != null) {
- for(int i = 0; i < nl.getLength(); i++) {
- Element field = (Element)nl.item(i);
- //Log.v(TAG, "phong");
- extractParams(field, params);
- }
- }
- mEffectsParams.put(id, params);
- }
-
- private void convertLight(Element light) {
- String name = light.getAttribute("name");
- String id = light.getAttribute("id");
-
- // Determine type
- String[] knownTypes = { "point", "spot", "directional" };
- final int POINT_LIGHT = 0;
- final int SPOT_LIGHT = 1;
- final int DIR_LIGHT = 2;
- int type = -1;
- for (int i = 0; i < knownTypes.length; i ++) {
- NodeList nl = light.getElementsByTagName(knownTypes[i]);
- if (nl != null && nl.getLength() != 0) {
- type = i;
- break;
- }
- }
-
- //Log.v(TAG, "Found Light Type " + type);
-
- LightBase sceneLight = null;
- switch (type) {
- case POINT_LIGHT:
- sceneLight = new PointLight();
- break;
- case SPOT_LIGHT: // TODO: finish light types
- break;
- case DIR_LIGHT: // TODO: finish light types
- break;
- }
-
- if (sceneLight == null) {
- return;
- }
-
- Float3 color = getFloat3(light, "color");
- sceneLight.setColor(color.x, color.y, color.z);
- sceneLight.setName(name);
- mScene.appendLight(sceneLight);
- mLights.put(id, sceneLight);
-
- //Log.v(TAG, "Light " + name + " color " + toString(color));
- }
-
- private void convertCamera(Element camera) {
- String name = camera.getAttribute("name");
- String id = camera.getAttribute("id");
- float fov = 30.0f;
- if (getString(camera, "yfov") != null) {
- fov = getFloat(camera, "yfov");
- } else if(getString(camera, "xfov") != null) {
- float aspect = getFloat(camera, "aspect_ratio");
- fov = getFloat(camera, "xfov") / aspect;
- }
-
- float near = getFloat(camera, "znear");
- float far = getFloat(camera, "zfar");
-
- Camera sceneCamera = new Camera();
- sceneCamera.setFOV(fov);
- sceneCamera.setNear(near);
- sceneCamera.setFar(far);
- sceneCamera.setName(name);
- mScene.appendCamera(sceneCamera);
- mCameras.put(id, sceneCamera);
- }
-
- private void convertImage(Element img) {
- String name = img.getAttribute("name");
- String id = img.getAttribute("id");
- String file = getString(img, "init_from");
-
- Texture2D tex = new Texture2D();
- tex.setFileName(file);
- tex.setFileDir(mRootDir);
- mScene.appendTextures(tex);
- mImages.put(id, tex);
- }
-
- private void getScene(Element scene) {
- String name = scene.getAttribute("name");
- String id = scene.getAttribute("id");
-
- Node childNode = scene.getFirstChild();
- while (childNode != null) {
- if (childNode.getNodeType() == Node.ELEMENT_NODE) {
- String indent = "";
- getNode((Element)childNode, null, indent);
- }
- childNode = childNode.getNextSibling();
- }
- }
-
- private String getString(Element elem, String name) {
- String text = null;
- NodeList nl = elem.getElementsByTagName(name);
- if (nl != null && nl.getLength() != 0) {
- text = ((Element)nl.item(0)).getFirstChild().getNodeValue();
- }
- return text;
- }
-
- private String getString(Element elem) {
- String text = null;
- text = elem.getFirstChild().getNodeValue();
- return text;
- }
-
- private int getInt(Element elem, String name) {
- return Integer.parseInt(getString(elem, name));
- }
-
- private float getFloat(Element elem, String name) {
- return Float.parseFloat(getString(elem, name));
- }
-
- private float getFloat(Element elem) {
- return Float.parseFloat(getString(elem));
- }
-
- private Float3 parseFloat3(String valueString) {
- StringTokenizer st = new StringTokenizer(valueString);
- float x = Float.parseFloat(st.nextToken());
- float y = Float.parseFloat(st.nextToken());
- float z = Float.parseFloat(st.nextToken());
- return new Float3(x, y, z);
- }
-
- private Float4 parseFloat4(String valueString) {
- StringTokenizer st = new StringTokenizer(valueString);
- float x = Float.parseFloat(st.nextToken());
- float y = Float.parseFloat(st.nextToken());
- float z = Float.parseFloat(st.nextToken());
- float w = Float.parseFloat(st.nextToken());
- return new Float4(x, y, z, w);
- }
-
- private Float3 getFloat3(Element elem, String name) {
- String valueString = getString(elem, name);
- return parseFloat3(valueString);
- }
-
- private Float4 getFloat4(Element elem, String name) {
- String valueString = getString(elem, name);
- return parseFloat4(valueString);
- }
-
- private Float3 getFloat3(Element elem) {
- String valueString = getString(elem);
- return parseFloat3(valueString);
- }
-
- private Float4 getFloat4(Element elem) {
- String valueString = getString(elem);
- return parseFloat4(valueString);
- }
-}
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java deleted file mode 100644 index 301075e52441..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ColladaScene.java +++ /dev/null @@ -1,139 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.FileInputStream; -import java.io.BufferedInputStream; -import java.io.Writer; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Vector; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.renderscript.*; -import android.renderscript.Allocation.MipmapControl; -import android.renderscript.Element.Builder; -import android.renderscript.Font.Style; -import android.renderscript.Program.TextureType; -import android.renderscript.ProgramStore.DepthFunc; -import android.util.Log; -import com.android.scenegraph.SceneManager.SceneLoadedCallback; - - -public class ColladaScene { - - private String modelName; - private static String TAG = "ColladaScene"; - private final int STATE_LAST_FOCUS = 1; - boolean mLoadFromSD = false; - - SceneLoadedCallback mCallback; - - public ColladaScene(String name, SceneLoadedCallback cb) { - modelName = name; - mCallback = cb; - } - - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - - mLoadFromSD = SceneManager.isSDCardPath(modelName); - - new ColladaLoaderTask().execute(modelName); - } - - private Resources mRes; - private RenderScriptGL mRS; - Scene mActiveScene; - - private class ColladaLoaderTask extends AsyncTask<String, Void, Boolean> { - ColladaParser sceneSource; - protected Boolean doInBackground(String... names) { - String rootDir = names[0].substring(0, names[0].lastIndexOf('/') + 1); - long start = System.currentTimeMillis(); - sceneSource = new ColladaParser(); - InputStream is = null; - try { - if (!mLoadFromSD) { - is = mRes.getAssets().open(names[0]); - } else { - File f = new File(names[0]); - is = new BufferedInputStream(new FileInputStream(f)); - } - } catch (IOException e) { - Log.e(TAG, "Could not open collada file"); - return new Boolean(false); - } - long end = System.currentTimeMillis(); - Log.v("TIMER", "Stream load time: " + (end - start)); - - start = System.currentTimeMillis(); - sceneSource.init(is, rootDir); - end = System.currentTimeMillis(); - Log.v("TIMER", "Collada parse time: " + (end - start)); - return new Boolean(true); - } - - protected void onPostExecute(Boolean result) { - mActiveScene = sceneSource.getScene(); - if (mCallback != null) { - mCallback.mLoadedScene = mActiveScene; - mCallback.run(); - } - - String shortName = modelName.substring(0, modelName.lastIndexOf('.')); - new A3DLoaderTask().execute(shortName + ".a3d"); - } - } - - private class A3DLoaderTask extends AsyncTask<String, Void, Boolean> { - protected Boolean doInBackground(String... names) { - long start = System.currentTimeMillis(); - FileA3D model; - if (!mLoadFromSD) { - model = FileA3D.createFromAsset(mRS, mRes.getAssets(), names[0]); - } else { - model = FileA3D.createFromFile(mRS, names[0]); - } - int numModels = model.getIndexEntryCount(); - for (int i = 0; i < numModels; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - mActiveScene.meshLoaded(entry.getMesh()); - } - } - long end = System.currentTimeMillis(); - Log.v("TIMER", "A3D load time: " + (end - start)); - return new Boolean(true); - } - - protected void onPostExecute(Boolean result) { - } - } - -} - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java deleted file mode 100644 index 9274b171b62c..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/CompoundTransform.java +++ /dev/null @@ -1,215 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import com.android.scenegraph.SceneManager; - -import android.renderscript.*; -import android.renderscript.Float3; -import android.renderscript.Matrix4f; -import android.util.Log; - -/** - * @hide - */ -public class CompoundTransform extends Transform { - - public static abstract class Component { - String mName; - CompoundTransform mParent; - int mParentIndex; - protected ScriptField_TransformComponent_s.Item mData; - - Component(int type, String name) { - mData = new ScriptField_TransformComponent_s.Item(); - mData.type = type; - mName = name; - } - - void setNameAlloc() { - RenderScriptGL rs = SceneManager.getRS(); - if (mData.name != null) { - return; - } - mData.name = SceneManager.getCachedAlloc(getName()); - if (mData.name == null) { - mData.name = SceneManager.getStringAsAllocation(rs, getName()); - SceneManager.cacheAlloc(getName(), mData.name); - } - } - - ScriptField_TransformComponent_s.Item getRSData() { - setNameAlloc(); - return mData; - } - - protected void update() { - if (mParent != null) { - mParent.updateRSComponent(this); - } - } - - public String getName() { - return mName; - } - } - - public static class TranslateComponent extends Component { - public TranslateComponent(String name, Float3 translate) { - super(ScriptC_export.const_Transform_TRANSLATE, name); - setValue(translate); - } - public Float3 getValue() { - return new Float3(mData.value.x, mData.value.y, mData.value.z); - } - public void setValue(Float3 val) { - mData.value.x = val.x; - mData.value.y = val.y; - mData.value.z = val.z; - update(); - } - } - - public static class RotateComponent extends Component { - public RotateComponent(String name, Float3 axis, float angle) { - super(ScriptC_export.const_Transform_ROTATE, name); - setAxis(axis); - setAngle(angle); - } - public Float3 getAxis() { - return new Float3(mData.value.x, mData.value.y, mData.value.z); - } - public float getAngle() { - return mData.value.w; - } - public void setAxis(Float3 val) { - mData.value.x = val.x; - mData.value.y = val.y; - mData.value.z = val.z; - update(); - } - public void setAngle(float val) { - mData.value.w = val; - update(); - } - } - - public static class ScaleComponent extends Component { - public ScaleComponent(String name, Float3 scale) { - super(ScriptC_export.const_Transform_SCALE, name); - setValue(scale); - } - public Float3 getValue() { - return new Float3(mData.value.x, mData.value.y, mData.value.z); - } - public void setValue(Float3 val) { - mData.value.x = val.x; - mData.value.y = val.y; - mData.value.z = val.z; - update(); - } - } - - ScriptField_TransformComponent_s mComponentField; - public ArrayList<Component> mTransformComponents; - - public CompoundTransform() { - mTransformComponents = new ArrayList<Component>(); - } - - public TranslateComponent addTranslate(String name, Float3 translate) { - TranslateComponent c = new TranslateComponent(name, translate); - addComponent(c); - return c; - } - - public RotateComponent addRotate(String name, Float3 axis, float angle) { - RotateComponent c = new RotateComponent(name, axis, angle); - addComponent(c); - return c; - } - - public ScaleComponent addScale(String name, Float3 scale) { - ScaleComponent c = new ScaleComponent(name, scale); - addComponent(c); - return c; - } - - public void addComponent(Component c) { - if (c.mParent != null) { - throw new IllegalArgumentException("Transform components may not be shared"); - } - c.mParent = this; - c.mParentIndex = mTransformComponents.size(); - mTransformComponents.add(c); - updateRSComponentAllocation(); - } - - public void setComponent(int index, Component c) { - if (c.mParent != null) { - throw new IllegalArgumentException("Transform components may not be shared"); - } - if (index >= mTransformComponents.size()) { - throw new IllegalArgumentException("Invalid component index"); - } - c.mParent = this; - c.mParentIndex = index; - mTransformComponents.set(index, c); - updateRSComponent(c); - } - - void updateRSComponent(Component c) { - if (mField == null || mComponentField == null) { - return; - } - mComponentField.set(c.getRSData(), c.mParentIndex, true); - mField.set_isDirty(0, 1, true); - } - - void updateRSComponentAllocation() { - if (mField == null) { - return; - } - initLocalData(); - - mField.set_components(0, mTransformData.components, false); - mField.set_isDirty(0, 1, true); - } - - void initLocalData() { - RenderScriptGL rs = SceneManager.getRS(); - int numComponenets = mTransformComponents.size(); - if (numComponenets > 0) { - mComponentField = new ScriptField_TransformComponent_s(rs, numComponenets); - for (int i = 0; i < numComponenets; i ++) { - Component ith = mTransformComponents.get(i); - mComponentField.set(ith.getRSData(), i, false); - } - mComponentField.copyAll(); - - mTransformData.components = mComponentField.getAllocation(); - } - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java deleted file mode 100644 index 15024588cad9..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Float4Param.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import com.android.scenegraph.Scene; -import com.android.scenegraph.SceneManager; - -import android.renderscript.Element; -import android.renderscript.Float4; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.renderscript.RenderScriptGL; -import android.util.Log; - -/** - * @hide - */ -public class Float4Param extends ShaderParam { - private static String TAG = "Float4Param"; - - LightBase mLight; - - public Float4Param(String name) { - super(name); - } - - public Float4Param(String name, float x) { - super(name); - set(x, 0, 0, 0); - } - - public Float4Param(String name, float x, float y) { - super(name); - set(x, y, 0, 0); - } - - public Float4Param(String name, float x, float y, float z) { - super(name); - set(x, y, z, 0); - } - - public Float4Param(String name, float x, float y, float z, float w) { - super(name); - set(x, y, z, w); - } - - void set(float x, float y, float z, float w) { - mData.float_value.x = x; - mData.float_value.y = y; - mData.float_value.z = z; - mData.float_value.w = w; - if (mField != null) { - mField.set_float_value(0, mData.float_value, true); - } - incTimestamp(); - } - - public void setValue(Float4 v) { - set(v.x, v.y, v.z, v.w); - } - - public Float4 getValue() { - return mData.float_value; - } - - public void setLight(LightBase l) { - mLight = l; - if (mField != null) { - mData.light = mLight.getRSData().getAllocation(); - mField.set_light(0, mData.light, true); - } - incTimestamp(); - } - - boolean findLight(String property) { - String indexStr = mParamName.substring(property.length() + 1); - if (indexStr == null) { - Log.e(TAG, "Invalid light index."); - return false; - } - int index = Integer.parseInt(indexStr); - if (index == -1) { - return false; - } - Scene parentScene = SceneManager.getInstance().getActiveScene(); - ArrayList<LightBase> allLights = parentScene.getLights(); - if (index >= allLights.size()) { - return false; - } - mLight = allLights.get(index); - if (mLight == null) { - return false; - } - return true; - } - - int getTypeFromName() { - int paramType = ScriptC_export.const_ShaderParam_FLOAT4_DATA; - if (mParamName.equalsIgnoreCase(cameraPos)) { - paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_POS; - } else if(mParamName.equalsIgnoreCase(cameraDir)) { - paramType = ScriptC_export.const_ShaderParam_FLOAT4_CAMERA_DIR; - } else if(mParamName.startsWith(lightColor) && findLight(lightColor)) { - paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_COLOR; - } else if(mParamName.startsWith(lightPos) && findLight(lightPos)) { - paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_POS; - } else if(mParamName.startsWith(lightDir) && findLight(lightDir)) { - paramType = ScriptC_export.const_ShaderParam_FLOAT4_LIGHT_DIR; - } - return paramType; - } - - void initLocalData() { - mData.type = getTypeFromName(); - if (mCamera != null) { - mData.camera = mCamera.getRSData().getAllocation(); - } - if (mLight != null) { - mData.light = mLight.getRSData().getAllocation(); - } - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java deleted file mode 100644 index 8a468db9a1cf..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/FragmentShader.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import com.android.scenegraph.TextureBase; - -import android.content.res.Resources; -import android.renderscript.*; -import android.renderscript.ProgramFragment.Builder; -import android.util.Log; - -/** - * @hide - */ -public class FragmentShader extends Shader { - ProgramFragment mProgram; - ScriptField_FragmentShader_s mField; - - public static class Builder { - - FragmentShader mShader; - ProgramFragment.Builder mBuilder; - - public Builder(RenderScriptGL rs) { - mShader = new FragmentShader(); - mBuilder = new ProgramFragment.Builder(rs); - } - - public Builder setShader(Resources resources, int resourceID) { - mBuilder.setShader(resources, resourceID); - return this; - } - - public Builder setShader(String code) { - mBuilder.setShader(code); - return this; - } - - public Builder setObjectConst(Type type) { - mShader.mPerObjConstants = type; - return this; - } - - public Builder setShaderConst(Type type) { - mShader.mPerShaderConstants = type; - return this; - } - - public Builder addShaderTexture(Program.TextureType texType, String name) { - mShader.mShaderTextureNames.add(name); - mShader.mShaderTextureTypes.add(texType); - return this; - } - - public Builder addTexture(Program.TextureType texType, String name) { - mShader.mTextureNames.add(name); - mShader.mTextureTypes.add(texType); - return this; - } - - public FragmentShader create() { - if (mShader.mPerShaderConstants != null) { - mBuilder.addConstant(mShader.mPerShaderConstants); - } - if (mShader.mPerObjConstants != null) { - mBuilder.addConstant(mShader.mPerObjConstants); - } - for (int i = 0; i < mShader.mTextureTypes.size(); i ++) { - mBuilder.addTexture(mShader.mTextureTypes.get(i), - mShader.mTextureNames.get(i)); - } - for (int i = 0; i < mShader.mShaderTextureTypes.size(); i ++) { - mBuilder.addTexture(mShader.mShaderTextureTypes.get(i), - mShader.mShaderTextureNames.get(i)); - } - - mShader.mProgram = mBuilder.create(); - return mShader; - } - } - - public ProgramFragment getProgram() { - return mProgram; - } - - ScriptField_ShaderParam_s getTextureParams() { - RenderScriptGL rs = SceneManager.getRS(); - Resources res = SceneManager.getRes(); - if (rs == null || res == null) { - return null; - } - - ArrayList<ScriptField_ShaderParam_s.Item> paramList; - paramList = new ArrayList<ScriptField_ShaderParam_s.Item>(); - - int shaderTextureStart = mTextureTypes.size(); - for (int i = 0; i < mShaderTextureNames.size(); i ++) { - ShaderParam sp = mSourceParams.get(mShaderTextureNames.get(i)); - if (sp != null && sp instanceof TextureParam) { - TextureParam p = (TextureParam)sp; - ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item(); - paramRS.bufferOffset = shaderTextureStart + i; - paramRS.transformTimestamp = 0; - paramRS.dataTimestamp = 0; - paramRS.data = p.getRSData().getAllocation(); - paramList.add(paramRS); - } - } - - ScriptField_ShaderParam_s rsParams = null; - int paramCount = paramList.size(); - if (paramCount != 0) { - rsParams = new ScriptField_ShaderParam_s(rs, paramCount); - for (int i = 0; i < paramCount; i++) { - rsParams.set(paramList.get(i), i, false); - } - rsParams.copyAll(); - } - return rsParams; - } - - ScriptField_FragmentShader_s getRSData() { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - Resources res = SceneManager.getRes(); - if (rs == null || res == null) { - return null; - } - - ScriptField_FragmentShader_s.Item item = new ScriptField_FragmentShader_s.Item(); - item.program = mProgram; - - ScriptField_ShaderParam_s texParams = getTextureParams(); - if (texParams != null) { - item.shaderTextureParams = texParams.getAllocation(); - } - - linkConstants(rs); - if (mPerShaderConstants != null) { - item.shaderConst = mConstantBuffer; - item.shaderConstParams = mConstantBufferParams.getAllocation(); - mProgram.bindConstants(item.shaderConst, 0); - } - - item.objectConstIndex = -1; - if (mPerObjConstants != null) { - item.objectConstIndex = mPerShaderConstants != null ? 1 : 0; - } - - mField = new ScriptField_FragmentShader_s(rs, 1); - mField.set(item, 0, true); - return mField; - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java deleted file mode 100644 index 8f5e2e78c33f..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/LightBase.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import android.renderscript.Float3; -import android.renderscript.Float4; -import android.renderscript.Matrix4f; -import android.renderscript.RenderScriptGL; -import android.util.Log; - -/** - * @hide - */ -public abstract class LightBase extends SceneGraphBase { - static final int RS_LIGHT_POINT = 0; - static final int RS_LIGHT_DIRECTIONAL = 1; - - ScriptField_Light_s mField; - ScriptField_Light_s.Item mFieldData; - Transform mTransform; - Float4 mColor; - float mIntensity; - public LightBase() { - mColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f); - mIntensity = 1.0f; - } - - public void setTransform(Transform t) { - mTransform = t; - updateRSData(); - } - - public void setColor(float r, float g, float b) { - mColor.x = r; - mColor.y = g; - mColor.z = b; - updateRSData(); - } - - public void setColor(Float3 c) { - setColor(c.x, c.y, c.z); - } - - public void setIntensity(float i) { - mIntensity = i; - updateRSData(); - } - - public void setName(String n) { - super.setName(n); - updateRSData(); - } - - protected void updateRSData() { - if (mField == null) { - return; - } - RenderScriptGL rs = SceneManager.getRS(); - mFieldData.transformMatrix = mTransform.getRSData().getAllocation(); - mFieldData.name = getNameAlloc(rs); - mFieldData.color = mColor; - mFieldData.intensity = mIntensity; - - initLocalData(); - - mField.set(mFieldData, 0, true); - } - - abstract void initLocalData(); - - ScriptField_Light_s getRSData() { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - if (rs == null) { - return null; - } - if (mField == null) { - mField = new ScriptField_Light_s(rs, 1); - mFieldData = new ScriptField_Light_s.Item(); - } - - updateRSData(); - - return mField; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java deleted file mode 100644 index 6d70bc9e4cf4..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/MatrixTransform.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import android.renderscript.Matrix4f; -import android.util.Log; - -/** - * @hide - */ -public class MatrixTransform extends Transform { - - Matrix4f mLocalMatrix; - public MatrixTransform() { - mLocalMatrix = new Matrix4f(); - } - - public void setMatrix(Matrix4f matrix) { - mLocalMatrix = matrix; - updateRSData(); - } - - public Matrix4f getMatrix() { - return new Matrix4f(mLocalMatrix.getArray()); - } - - void initLocalData() { - mTransformData.localMat = mLocalMatrix; - } - - void updateRSData() { - if (mField == null) { - return; - } - mField.set_localMat(0, mLocalMatrix, false); - mField.set_isDirty(0, 1, true); - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java deleted file mode 100644 index 02fd69d20078..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderPass.java +++ /dev/null @@ -1,124 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import android.util.Log; - -import android.renderscript.*; -import android.content.res.Resources; - -/** - * @hide - */ -public class RenderPass extends SceneGraphBase { - - TextureRenderTarget mColorTarget; - Float4 mClearColor; - boolean mShouldClearColor; - - TextureRenderTarget mDepthTarget; - float mClearDepth; - boolean mShouldClearDepth; - - ArrayList<RenderableBase> mObjectsToDraw; - - Camera mCamera; - - ScriptField_RenderPass_s.Item mRsField; - - public RenderPass() { - mObjectsToDraw = new ArrayList<RenderableBase>(); - mClearColor = new Float4(0.0f, 0.0f, 0.0f, 0.0f); - mShouldClearColor = true; - mClearDepth = 1.0f; - mShouldClearDepth = true; - } - - public void appendRenderable(Renderable d) { - mObjectsToDraw.add(d); - } - - public void setCamera(Camera c) { - mCamera = c; - } - - public void setColorTarget(TextureRenderTarget colorTarget) { - mColorTarget = colorTarget; - } - public void setClearColor(Float4 clearColor) { - mClearColor = clearColor; - } - public void setShouldClearColor(boolean shouldClearColor) { - mShouldClearColor = shouldClearColor; - } - - public void setDepthTarget(TextureRenderTarget depthTarget) { - mDepthTarget = depthTarget; - } - public void setClearDepth(float clearDepth) { - mClearDepth = clearDepth; - } - public void setShouldClearDepth(boolean shouldClearDepth) { - mShouldClearDepth = shouldClearDepth; - } - - public ArrayList<RenderableBase> getRenderables() { - return mObjectsToDraw; - } - - ScriptField_RenderPass_s.Item getRsField(RenderScriptGL rs, Resources res) { - if (mRsField != null) { - return mRsField; - } - - mRsField = new ScriptField_RenderPass_s.Item(); - if (mColorTarget != null) { - mRsField.color_target = mColorTarget.getRsData(true).get_texture(0); - } - if (mColorTarget != null) { - mRsField.depth_target = mDepthTarget.getRsData(true).get_texture(0); - } - mRsField.camera = mCamera != null ? mCamera.getRSData().getAllocation() : null; - - if (mObjectsToDraw.size() != 0) { - Allocation drawableData = Allocation.createSized(rs, - Element.ALLOCATION(rs), - mObjectsToDraw.size()); - Allocation[] drawableAllocs = new Allocation[mObjectsToDraw.size()]; - for (int i = 0; i < mObjectsToDraw.size(); i ++) { - Renderable dI = (Renderable)mObjectsToDraw.get(i); - drawableAllocs[i] = dI.getRsField(rs, res).getAllocation(); - } - drawableData.copyFrom(drawableAllocs); - mRsField.objects = drawableData; - } - - mRsField.clear_color = mClearColor; - mRsField.clear_depth = mClearDepth; - mRsField.should_clear_color = mShouldClearColor; - mRsField.should_clear_depth = mShouldClearDepth; - return mRsField; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java deleted file mode 100644 index c08a72283a9e..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderState.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; -import android.content.res.Resources; - -import android.renderscript.Allocation; -import android.renderscript.Element; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramRaster; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.renderscript.RSRuntimeException; -import android.renderscript.RenderScript; -import android.renderscript.RenderScriptGL; -import android.util.Log; - -/** - * @hide - */ -public class RenderState extends SceneGraphBase { - VertexShader mVertex; - FragmentShader mFragment; - ProgramStore mStore; - ProgramRaster mRaster; - - ScriptField_RenderState_s mField; - - public RenderState(VertexShader pv, - FragmentShader pf, - ProgramStore ps, - ProgramRaster pr) { - mVertex = pv; - mFragment = pf; - mStore = ps; - mRaster = pr; - } - - public RenderState(RenderState r) { - mVertex = r.mVertex; - mFragment = r.mFragment; - mStore = r.mStore; - mRaster = r.mRaster; - } - - public void setProgramVertex(VertexShader pv) { - mVertex = pv; - updateRSData(); - } - - public void setProgramFragment(FragmentShader pf) { - mFragment = pf; - updateRSData(); - } - - public void setProgramStore(ProgramStore ps) { - mStore = ps; - updateRSData(); - } - - public void setProgramRaster(ProgramRaster pr) { - mRaster = pr; - updateRSData(); - } - - void updateRSData() { - if (mField == null) { - return; - } - ScriptField_RenderState_s.Item item = new ScriptField_RenderState_s.Item(); - item.pv = mVertex.getRSData().getAllocation(); - item.pf = mFragment.getRSData().getAllocation(); - item.ps = mStore; - item.pr = mRaster; - - mField.set(item, 0, true); - } - - public ScriptField_RenderState_s getRSData() { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - if (rs == null) { - return null; - } - - mField = new ScriptField_RenderState_s(rs, 1); - updateRSData(); - - return mField; - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java deleted file mode 100644 index 9266f3058cf7..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Renderable.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; - -import com.android.scenegraph.Float4Param; -import com.android.scenegraph.MatrixTransform; -import com.android.scenegraph.SceneManager; -import com.android.scenegraph.ShaderParam; -import com.android.scenegraph.TransformParam; - -import android.content.res.Resources; -import android.renderscript.Allocation; -import android.renderscript.Element; -import android.renderscript.Element.DataType; -import android.renderscript.Matrix4f; -import android.renderscript.Mesh; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.renderscript.RenderScriptGL; -import android.util.Log; - -/** - * @hide - */ -public class Renderable extends RenderableBase { - HashMap<String, ShaderParam> mSourceParams; - - RenderState mRenderState; - Transform mTransform; - - String mMeshName; - String mMeshIndexName; - - public String mMaterialName; - - ScriptField_Renderable_s mField; - ScriptField_Renderable_s.Item mData; - - public Renderable() { - mSourceParams = new HashMap<String, ShaderParam>(); - mData = new ScriptField_Renderable_s.Item(); - } - - public void setCullType(int cull) { - mData.cullType = cull; - } - - public void setRenderState(RenderState renderState) { - mRenderState = renderState; - if (mField != null) { - RenderScriptGL rs = SceneManager.getRS(); - updateFieldItem(rs); - mField.set(mData, 0, true); - } - } - - public void setMesh(Mesh mesh) { - mData.mesh = mesh; - if (mField != null) { - mField.set_mesh(0, mData.mesh, true); - } - } - - public void setMesh(String mesh, String indexName) { - mMeshName = mesh; - mMeshIndexName = indexName; - } - - public void setMaterialName(String name) { - mMaterialName = name; - } - - public Transform getTransform() { - return mTransform; - } - - public void setTransform(Transform t) { - mTransform = t; - if (mField != null) { - RenderScriptGL rs = SceneManager.getRS(); - updateFieldItem(rs); - mField.set(mData, 0, true); - } - } - - public void appendSourceParams(ShaderParam p) { - mSourceParams.put(p.getParamName(), p); - // Possibly lift this restriction later - if (mField != null) { - throw new RuntimeException("Can't add source params to objects that are rendering"); - } - } - - public void resolveMeshData(Mesh mesh) { - mData.mesh = mesh; - if (mData.mesh == null) { - Log.v("DRAWABLE: ", "*** NO MESH *** " + mMeshName); - return; - } - int subIndexCount = mData.mesh.getPrimitiveCount(); - if (subIndexCount == 1 || mMeshIndexName == null) { - mData.meshIndex = 0; - } else { - for (int i = 0; i < subIndexCount; i ++) { - if (mData.mesh.getIndexSetAllocation(i).getName().equals(mMeshIndexName)) { - mData.meshIndex = i; - break; - } - } - } - if (mField != null) { - mField.set(mData, 0, true); - } - } - - void updateTextures(RenderScriptGL rs) { - Iterator<ShaderParam> allParamsIter = mSourceParams.values().iterator(); - int paramIndex = 0; - while (allParamsIter.hasNext()) { - ShaderParam sp = allParamsIter.next(); - if (sp instanceof TextureParam) { - TextureParam p = (TextureParam)sp; - TextureBase tex = p.getTexture(); - if (tex != null) { - mData.pf_textures[paramIndex++] = tex.getRsData(false).getAllocation(); - } - } - } - ProgramFragment pf = mRenderState.mFragment.mProgram; - mData.pf_num_textures = pf != null ? Math.min(pf.getTextureCount(), paramIndex) : 0; - if (mField != null) { - mField.set_pf_textures(0, mData.pf_textures, true); - mField.set_pf_num_textures(0, mData.pf_num_textures, true); - } - } - - public void setVisible(boolean vis) { - mData.cullType = vis ? 0 : 2; - if (mField != null) { - mField.set_cullType(0, mData.cullType, true); - } - } - - ScriptField_Renderable_s getRsField(RenderScriptGL rs, Resources res) { - if (mField != null) { - return mField; - } - updateFieldItem(rs); - updateTextures(rs); - - mField = new ScriptField_Renderable_s(rs, 1); - mField.set(mData, 0, true); - - return mField; - } - - void updateVertexConstants(RenderScriptGL rs) { - Allocation pvParams = null, vertexConstants = null; - VertexShader pv = mRenderState.mVertex; - if (pv != null && pv.getObjectConstants() != null) { - vertexConstants = Allocation.createTyped(rs, pv.getObjectConstants()); - Element vertexConst = vertexConstants.getType().getElement(); - pvParams = ShaderParam.fillInParams(vertexConst, mSourceParams, - mTransform).getAllocation(); - } - mData.pv_const = vertexConstants; - mData.pv_constParams = pvParams; - } - - void updateFragmentConstants(RenderScriptGL rs) { - Allocation pfParams = null, fragmentConstants = null; - FragmentShader pf = mRenderState.mFragment; - if (pf != null && pf.getObjectConstants() != null) { - fragmentConstants = Allocation.createTyped(rs, pf.getObjectConstants()); - Element fragmentConst = fragmentConstants.getType().getElement(); - pfParams = ShaderParam.fillInParams(fragmentConst, mSourceParams, - mTransform).getAllocation(); - } - mData.pf_const = fragmentConstants; - mData.pf_constParams = pfParams; - } - - void updateFieldItem(RenderScriptGL rs) { - if (mRenderState == null) { - mRenderState = SceneManager.getDefaultState(); - } - if (mTransform == null) { - mTransform = SceneManager.getDefaultTransform(); - } - updateVertexConstants(rs); - updateFragmentConstants(rs); - - mData.transformMatrix = mTransform.getRSData().getAllocation(); - - mData.name = getNameAlloc(rs); - mData.render_state = mRenderState.getRSData().getAllocation(); - mData.bVolInitialized = 0; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java deleted file mode 100644 index 590bbab9c5f8..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableGroup.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.util.Log; - -/** - * @hide - */ -public class RenderableGroup extends RenderableBase { - - ArrayList<RenderableBase> mChildren; - - public RenderableGroup() { - mChildren = new ArrayList<RenderableBase>(); - } - - public void appendChildren(RenderableBase d) { - mChildren.add(d); - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java deleted file mode 100644 index 27336abd5849..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Scene.java +++ /dev/null @@ -1,373 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.android.scenegraph.Camera; -import com.android.scenegraph.CompoundTransform; -import com.android.scenegraph.RenderPass; -import com.android.scenegraph.Renderable; -import com.android.scenegraph.SceneManager; -import com.android.scenegraph.TextureBase; - -import android.content.res.Resources; -import android.os.AsyncTask; -import android.renderscript.*; -import android.renderscript.Mesh; -import android.renderscript.RenderScriptGL; -import android.util.Log; - -/** - * @hide - */ -public class Scene extends SceneGraphBase { - private static String TIMER_TAG = "TIMER"; - - CompoundTransform mRootTransforms; - HashMap<String, Transform> mTransformMap; - ArrayList<RenderPass> mRenderPasses; - ArrayList<LightBase> mLights; - ArrayList<Camera> mCameras; - ArrayList<FragmentShader> mFragmentShaders; - ArrayList<VertexShader> mVertexShaders; - ArrayList<RenderableBase> mRenderables; - HashMap<String, RenderableBase> mRenderableMap; - ArrayList<Texture2D> mTextures; - - HashMap<String, ArrayList<Renderable> > mRenderableMeshMap; - - // RS Specific stuff - ScriptField_SgTransform mTransformRSData; - - RenderScriptGL mRS; - Resources mRes; - - ScriptField_RenderPass_s mRenderPassAlloc; - - public Scene() { - mRenderPasses = new ArrayList<RenderPass>(); - mLights = new ArrayList<LightBase>(); - mCameras = new ArrayList<Camera>(); - mFragmentShaders = new ArrayList<FragmentShader>(); - mVertexShaders = new ArrayList<VertexShader>(); - mRenderables = new ArrayList<RenderableBase>(); - mRenderableMap = new HashMap<String, RenderableBase>(); - mRenderableMeshMap = new HashMap<String, ArrayList<Renderable> >(); - mTextures = new ArrayList<Texture2D>(); - mRootTransforms = new CompoundTransform(); - mRootTransforms.setName("_scene_root_"); - mTransformMap = new HashMap<String, Transform>(); - } - - public void appendTransform(Transform t) { - if (t == null) { - throw new RuntimeException("Adding null object"); - } - mRootTransforms.appendChild(t); - } - - public CompoundTransform appendNewCompoundTransform() { - CompoundTransform t = new CompoundTransform(); - appendTransform(t); - return t; - } - - public MatrixTransform appendNewMatrixTransform() { - MatrixTransform t = new MatrixTransform(); - appendTransform(t); - return t; - } - - // temporary - public void addToTransformMap(Transform t) { - mTransformMap.put(t.getName(), t); - } - - public Transform getTransformByName(String name) { - return mTransformMap.get(name); - } - - public void appendRenderPass(RenderPass p) { - if (p == null) { - throw new RuntimeException("Adding null object"); - } - mRenderPasses.add(p); - } - - public RenderPass appendNewRenderPass() { - RenderPass p = new RenderPass(); - appendRenderPass(p); - return p; - } - - public void clearRenderPasses() { - mRenderPasses.clear(); - } - - public void appendLight(LightBase l) { - if (l == null) { - throw new RuntimeException("Adding null object"); - } - mLights.add(l); - } - - public void appendCamera(Camera c) { - if (c == null) { - throw new RuntimeException("Adding null object"); - } - mCameras.add(c); - } - - public Camera appendNewCamera() { - Camera c = new Camera(); - appendCamera(c); - return c; - } - - public void appendShader(FragmentShader f) { - if (f == null) { - throw new RuntimeException("Adding null object"); - } - mFragmentShaders.add(f); - } - - public void appendShader(VertexShader v) { - if (v == null) { - throw new RuntimeException("Adding null object"); - } - mVertexShaders.add(v); - } - - public ArrayList<Camera> getCameras() { - return mCameras; - } - - public ArrayList<LightBase> getLights() { - return mLights; - } - - public void appendRenderable(RenderableBase d) { - if (d == null) { - throw new RuntimeException("Adding null object"); - } - mRenderables.add(d); - if (d.getName() != null) { - mRenderableMap.put(d.getName(), d); - } - } - - public Renderable appendNewRenderable() { - Renderable r = new Renderable(); - appendRenderable(r); - return r; - } - - public ArrayList<RenderableBase> getRenderables() { - return mRenderables; - } - - public RenderableBase getRenderableByName(String name) { - return mRenderableMap.get(name); - } - - public void appendTextures(Texture2D tex) { - if (tex == null) { - throw new RuntimeException("Adding null object"); - } - mTextures.add(tex); - } - - public void assignRenderStateToMaterial(RenderState renderState, String regex) { - Pattern pattern = Pattern.compile(regex); - int numRenderables = mRenderables.size(); - for (int i = 0; i < numRenderables; i ++) { - Renderable shape = (Renderable)mRenderables.get(i); - Matcher m = pattern.matcher(shape.mMaterialName); - if (m.find()) { - shape.setRenderState(renderState); - } - } - } - - public void assignRenderState(RenderState renderState) { - int numRenderables = mRenderables.size(); - for (int i = 0; i < numRenderables; i ++) { - Renderable shape = (Renderable)mRenderables.get(i); - shape.setRenderState(renderState); - } - } - - public void meshLoaded(Mesh m) { - ArrayList<Renderable> entries = mRenderableMeshMap.get(m.getName()); - int numEntries = entries.size(); - for (int i = 0; i < numEntries; i++) { - Renderable d = entries.get(i); - d.resolveMeshData(m); - } - } - - void addToMeshMap(Renderable d) { - ArrayList<Renderable> entries = mRenderableMeshMap.get(d.mMeshName); - if (entries == null) { - entries = new ArrayList<Renderable>(); - mRenderableMeshMap.put(d.mMeshName, entries); - } - entries.add(d); - } - - public void destroyRS() { - SceneManager sceneManager = SceneManager.getInstance(); - mTransformRSData = null; - sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData); - sceneManager.mRenderLoop.set_gRenderableObjects(null); - mRenderPassAlloc = null; - sceneManager.mRenderLoop.set_gRenderPasses(null); - sceneManager.mRenderLoop.bind_gFrontToBack(null); - sceneManager.mRenderLoop.bind_gBackToFront(null); - sceneManager.mRenderLoop.set_gCameras(null); - - mTransformMap = null; - mRenderPasses = null; - mLights = null; - mCameras = null; - mRenderables = null; - mRenderableMap = null; - mTextures = null; - mRenderableMeshMap = null; - mRootTransforms = null; - } - - public void initRenderPassRS(RenderScriptGL rs, SceneManager sceneManager) { - if (mRenderPasses.size() != 0) { - mRenderPassAlloc = new ScriptField_RenderPass_s(mRS, mRenderPasses.size()); - for (int i = 0; i < mRenderPasses.size(); i ++) { - mRenderPassAlloc.set(mRenderPasses.get(i).getRsField(mRS, mRes), i, false); - } - mRenderPassAlloc.copyAll(); - sceneManager.mRenderLoop.set_gRenderPasses(mRenderPassAlloc.getAllocation()); - } - } - - private void addDrawables(RenderScriptGL rs, Resources res, SceneManager sceneManager) { - Allocation drawableData = Allocation.createSized(rs, - Element.ALLOCATION(rs), - mRenderables.size()); - Allocation[] drawableAllocs = new Allocation[mRenderables.size()]; - for (int i = 0; i < mRenderables.size(); i ++) { - Renderable dI = (Renderable)mRenderables.get(i); - addToMeshMap(dI); - drawableAllocs[i] = dI.getRsField(rs, res).getAllocation(); - } - drawableData.copyFrom(drawableAllocs); - sceneManager.mRenderLoop.set_gRenderableObjects(drawableData); - - initRenderPassRS(rs, sceneManager); - } - - private void addShaders(RenderScriptGL rs, Resources res, SceneManager sceneManager) { - if (mVertexShaders.size() > 0) { - Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), - mVertexShaders.size()); - Allocation[] shaderAllocs = new Allocation[mVertexShaders.size()]; - for (int i = 0; i < mVertexShaders.size(); i ++) { - VertexShader sI = mVertexShaders.get(i); - shaderAllocs[i] = sI.getRSData().getAllocation(); - } - shaderData.copyFrom(shaderAllocs); - sceneManager.mRenderLoop.set_gVertexShaders(shaderData); - } - - if (mFragmentShaders.size() > 0) { - Allocation shaderData = Allocation.createSized(rs, Element.ALLOCATION(rs), - mFragmentShaders.size()); - Allocation[] shaderAllocs = new Allocation[mFragmentShaders.size()]; - for (int i = 0; i < mFragmentShaders.size(); i ++) { - FragmentShader sI = mFragmentShaders.get(i); - shaderAllocs[i] = sI.getRSData().getAllocation(); - } - shaderData.copyFrom(shaderAllocs); - sceneManager.mRenderLoop.set_gFragmentShaders(shaderData); - } - } - - public void initRS() { - SceneManager sceneManager = SceneManager.getInstance(); - mRS = SceneManager.getRS(); - mRes = SceneManager.getRes(); - long start = System.currentTimeMillis(); - mTransformRSData = mRootTransforms.getRSData(); - long end = System.currentTimeMillis(); - Log.v(TIMER_TAG, "Transform init time: " + (end - start)); - - start = System.currentTimeMillis(); - - sceneManager.mRenderLoop.bind_gRootNode(mTransformRSData); - end = System.currentTimeMillis(); - Log.v(TIMER_TAG, "Script init time: " + (end - start)); - - start = System.currentTimeMillis(); - addDrawables(mRS, mRes, sceneManager); - end = System.currentTimeMillis(); - Log.v(TIMER_TAG, "Renderable init time: " + (end - start)); - - addShaders(mRS, mRes, sceneManager); - - Allocation opaqueBuffer = null; - if (mRenderables.size() > 0) { - opaqueBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size()); - } - Allocation transparentBuffer = null; - if (mRenderables.size() > 0) { - transparentBuffer = Allocation.createSized(mRS, Element.U32(mRS), mRenderables.size()); - } - - sceneManager.mRenderLoop.bind_gFrontToBack(opaqueBuffer); - sceneManager.mRenderLoop.bind_gBackToFront(transparentBuffer); - - if (mCameras.size() > 0) { - Allocation cameraData; - cameraData = Allocation.createSized(mRS, Element.ALLOCATION(mRS), mCameras.size()); - Allocation[] cameraAllocs = new Allocation[mCameras.size()]; - for (int i = 0; i < mCameras.size(); i ++) { - cameraAllocs[i] = mCameras.get(i).getRSData().getAllocation(); - } - cameraData.copyFrom(cameraAllocs); - sceneManager.mRenderLoop.set_gCameras(cameraData); - } - - if (mLights.size() > 0) { - Allocation lightData = Allocation.createSized(mRS, - Element.ALLOCATION(mRS), - mLights.size()); - Allocation[] lightAllocs = new Allocation[mLights.size()]; - for (int i = 0; i < mLights.size(); i ++) { - lightAllocs[i] = mLights.get(i).getRSData().getAllocation(); - } - lightData.copyFrom(lightAllocs); - sceneManager.mRenderLoop.set_gLights(lightData); - } - } -} - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java deleted file mode 100644 index 412ffbf77900..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneGraphBase.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import com.android.scenegraph.SceneManager; - -import android.renderscript.Allocation; -import android.renderscript.Element; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.renderscript.RSRuntimeException; -import android.renderscript.RenderScript; -import android.renderscript.RenderScriptGL; -import android.util.Log; - -/** - * @hide - */ -public abstract class SceneGraphBase { - String mName; - Allocation mNameAlloc; - public void setName(String n) { - mName = n; - mNameAlloc = null; - } - - public String getName() { - return mName; - } - - Allocation getNameAlloc(RenderScriptGL rs) { - if (mNameAlloc == null) { - mNameAlloc = SceneManager.getStringAsAllocation(rs, getName()); - } - return mNameAlloc; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java deleted file mode 100644 index 4ff2c8b09371..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/SceneManager.java +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.io.BufferedInputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.Writer; -import java.lang.Math; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import com.android.scenegraph.Camera; -import com.android.scenegraph.FragmentShader; -import com.android.scenegraph.MatrixTransform; -import com.android.scenegraph.Scene; -import com.android.scenegraph.VertexShader; -import com.android.testapp.R; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.renderscript.*; -import android.renderscript.Allocation.MipmapControl; -import android.renderscript.Mesh; -import android.renderscript.RenderScriptGL; -import android.util.Log; -import android.view.SurfaceHolder; - -/** - * @hide - */ -public class SceneManager extends SceneGraphBase { - - HashMap<String, Allocation> mAllocationMap; - - ScriptC_render mRenderLoop; - ScriptC mCameraScript; - ScriptC mLightScript; - ScriptC mObjectParamsScript; - ScriptC mFragmentParamsScript; - ScriptC mVertexParamsScript; - ScriptC mCullScript; - ScriptC_transform mTransformScript; - ScriptC_export mExportScript; - - RenderScriptGL mRS; - Resources mRes; - Mesh mQuad; - int mWidth; - int mHeight; - - Scene mActiveScene; - private static SceneManager sSceneManager; - - private Allocation mDefault2D; - private Allocation mDefaultCube; - - private FragmentShader mColor; - private FragmentShader mTexture; - private VertexShader mDefaultVertex; - - private RenderState mDefaultState; - private Transform mDefaultTransform; - - private static Allocation getDefault(boolean isCube) { - final int dimension = 4; - final int bytesPerPixel = 4; - int arraySize = dimension * dimension * bytesPerPixel; - - RenderScriptGL rs = sSceneManager.mRS; - Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs)); - b.setX(dimension).setY(dimension); - if (isCube) { - b.setFaces(true); - arraySize *= 6; - } - Type bitmapType = b.create(); - - Allocation.MipmapControl mip = Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE; - int usage = Allocation.USAGE_GRAPHICS_TEXTURE; - Allocation defaultImage = Allocation.createTyped(rs, bitmapType, mip, usage); - - byte imageData[] = new byte[arraySize]; - defaultImage.copyFrom(imageData); - return defaultImage; - } - - static Allocation getDefaultTex2D() { - if (sSceneManager == null) { - return null; - } - if (sSceneManager.mDefault2D == null) { - sSceneManager.mDefault2D = getDefault(false); - } - return sSceneManager.mDefault2D; - } - - static Allocation getDefaultTexCube() { - if (sSceneManager == null) { - return null; - } - if (sSceneManager.mDefaultCube == null) { - sSceneManager.mDefaultCube = getDefault(true); - } - return sSceneManager.mDefaultCube; - } - - public static boolean isSDCardPath(String path) { - int sdCardIndex = path.indexOf("sdcard/"); - // We are looking for /sdcard/ or sdcard/ - if (sdCardIndex == 0 || sdCardIndex == 1) { - return true; - } - sdCardIndex = path.indexOf("mnt/sdcard/"); - if (sdCardIndex == 0 || sdCardIndex == 1) { - return true; - } - return false; - } - - static Bitmap loadBitmap(String name, Resources res) { - InputStream is = null; - boolean loadFromSD = isSDCardPath(name); - try { - if (!loadFromSD) { - is = res.getAssets().open(name); - } else { - File f = new File(name); - is = new BufferedInputStream(new FileInputStream(f)); - } - } catch (IOException e) { - Log.e("ImageLoaderTask", " Message: " + e.getMessage()); - return null; - } - - Bitmap b = BitmapFactory.decodeStream(is); - try { - is.close(); - } catch (IOException e) { - Log.e("ImageLoaderTask", " Message: " + e.getMessage()); - } - return b; - } - - static Allocation createFromBitmap(Bitmap b, RenderScriptGL rs, boolean isCube) { - if (b == null) { - return null; - } - MipmapControl mip = MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE; - int usage = Allocation.USAGE_GRAPHICS_TEXTURE; - if (isCube) { - return Allocation.createCubemapFromBitmap(rs, b, mip, usage); - } - return Allocation.createFromBitmap(rs, b, mip, usage); - } - - public static Allocation loadCubemap(String name, RenderScriptGL rs, Resources res) { - return createFromBitmap(loadBitmap(name, res), rs, true); - } - - public static Allocation loadCubemap(int id, RenderScriptGL rs, Resources res) { - return createFromBitmap(BitmapFactory.decodeResource(res, id), rs, true); - } - - public static Allocation loadTexture2D(String name, RenderScriptGL rs, Resources res) { - return createFromBitmap(loadBitmap(name, res), rs, false); - } - - public static Allocation loadTexture2D(int id, RenderScriptGL rs, Resources res) { - return createFromBitmap(BitmapFactory.decodeResource(res, id), rs, false); - } - - public static ProgramStore BLEND_ADD_DEPTH_NONE(RenderScript rs) { - ProgramStore.Builder builder = new ProgramStore.Builder(rs); - builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); - builder.setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ONE); - builder.setDitherEnabled(false); - builder.setDepthMaskEnabled(false); - return builder.create(); - } - - static Allocation getStringAsAllocation(RenderScript rs, String str) { - if (str == null) { - return null; - } - if (str.length() == 0) { - return null; - } - byte[] allocArray = null; - byte[] nullChar = new byte[1]; - nullChar[0] = 0; - try { - allocArray = str.getBytes("UTF-8"); - Allocation alloc = Allocation.createSized(rs, Element.U8(rs), - allocArray.length + 1, - Allocation.USAGE_SCRIPT); - alloc.copy1DRangeFrom(0, allocArray.length, allocArray); - alloc.copy1DRangeFrom(allocArray.length, 1, nullChar); - return alloc; - } - catch (Exception e) { - throw new RSRuntimeException("Could not convert string to utf-8."); - } - } - - static Allocation getCachedAlloc(String str) { - if (sSceneManager == null) { - throw new RuntimeException("Scene manager not initialized"); - } - return sSceneManager.mAllocationMap.get(str); - } - - static void cacheAlloc(String str, Allocation alloc) { - if (sSceneManager == null) { - throw new RuntimeException("Scene manager not initialized"); - } - sSceneManager.mAllocationMap.put(str, alloc); - } - - public static class SceneLoadedCallback implements Runnable { - public Scene mLoadedScene; - public String mName; - public void run() { - } - } - - public Scene getActiveScene() { - return mActiveScene; - } - - public void setActiveScene(Scene s) { - mActiveScene = s; - - if (mActiveScene == null) { - return; - } - - // Do some sanity checking - if (mActiveScene.getCameras().size() == 0) { - Matrix4f camPos = new Matrix4f(); - camPos.translate(0, 0, 10); - MatrixTransform cameraTransform = new MatrixTransform(); - cameraTransform.setName("_DefaultCameraTransform"); - cameraTransform.setMatrix(camPos); - mActiveScene.appendTransform(cameraTransform); - Camera cam = new Camera(); - cam.setName("_DefaultCamera"); - cam.setTransform(cameraTransform); - mActiveScene.appendCamera(cam); - } - - mActiveScene.appendShader(getDefaultVS()); - mActiveScene.appendTransform(getDefaultTransform()); - } - - static RenderScriptGL getRS() { - if (sSceneManager == null) { - return null; - } - return sSceneManager.mRS; - } - - static Resources getRes() { - if (sSceneManager == null) { - return null; - } - return sSceneManager.mRes; - } - - // Provides the folowing inputs to fragment shader - // Assigned by default if nothing is present - // vec3 varWorldPos; - // vec3 varWorldNormal; - // vec2 varTex0; - public static VertexShader getDefaultVS() { - if (sSceneManager == null) { - return null; - } - - if (sSceneManager.mDefaultVertex == null) { - RenderScriptGL rs = getRS(); - Element.Builder b = new Element.Builder(rs); - b.add(Element.MATRIX_4X4(rs), "model"); - Type.Builder objConstBuilder = new Type.Builder(rs, b.create()); - - b = new Element.Builder(rs); - b.add(Element.MATRIX_4X4(rs), "viewProj"); - Type.Builder shaderConstBuilder = new Type.Builder(rs, b.create()); - - b = new Element.Builder(rs); - b.add(Element.F32_4(rs), "position"); - b.add(Element.F32_2(rs), "texture0"); - b.add(Element.F32_3(rs), "normal"); - Element defaultIn = b.create(); - - final String code = "\n" + - "varying vec3 varWorldPos;\n" + - "varying vec3 varWorldNormal;\n" + - "varying vec2 varTex0;\n" + - "void main() {" + - " vec4 objPos = ATTRIB_position;\n" + - " vec4 worldPos = UNI_model * objPos;\n" + - " gl_Position = UNI_viewProj * worldPos;\n" + - " mat3 model3 = mat3(UNI_model[0].xyz, UNI_model[1].xyz, UNI_model[2].xyz);\n" + - " vec3 worldNorm = model3 * ATTRIB_normal;\n" + - " varWorldPos = worldPos.xyz;\n" + - " varWorldNormal = worldNorm;\n" + - " varTex0 = ATTRIB_texture0;\n" + - "}\n"; - - VertexShader.Builder sb = new VertexShader.Builder(rs); - sb.addInput(defaultIn); - sb.setObjectConst(objConstBuilder.setX(1).create()); - sb.setShaderConst(shaderConstBuilder.setX(1).create()); - sb.setShader(code); - sSceneManager.mDefaultVertex = sb.create(); - } - - return sSceneManager.mDefaultVertex; - } - - public static FragmentShader getColorFS() { - if (sSceneManager == null) { - return null; - } - if (sSceneManager.mColor == null) { - RenderScriptGL rs = getRS(); - Element.Builder b = new Element.Builder(rs); - b.add(Element.F32_4(rs), "color"); - Type.Builder objConstBuilder = new Type.Builder(rs, b.create()); - - final String code = "\n" + - "varying vec2 varTex0;\n" + - "void main() {\n" + - " lowp vec4 col = UNI_color;\n" + - " gl_FragColor = col;\n" + - "}\n"; - FragmentShader.Builder fb = new FragmentShader.Builder(rs); - fb.setShader(code); - fb.setObjectConst(objConstBuilder.create()); - sSceneManager.mColor = fb.create(); - } - - return sSceneManager.mColor; - } - - public static FragmentShader getTextureFS() { - if (sSceneManager == null) { - return null; - } - if (sSceneManager.mTexture == null) { - RenderScriptGL rs = getRS(); - - final String code = "\n" + - "varying vec2 varTex0;\n" + - "void main() {\n" + - " lowp vec4 col = texture2D(UNI_color, varTex0).rgba;\n" + - " gl_FragColor = col;\n" + - "}\n"; - - FragmentShader.Builder fb = new FragmentShader.Builder(rs); - fb.setShader(code); - fb.addTexture(Program.TextureType.TEXTURE_2D, "color"); - sSceneManager.mTexture = fb.create(); - sSceneManager.mTexture.mProgram.bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(rs), 0); - } - - return sSceneManager.mTexture; - } - - static RenderState getDefaultState() { - if (sSceneManager == null) { - return null; - } - if (sSceneManager.mDefaultState == null) { - sSceneManager.mDefaultState = new RenderState(getDefaultVS(), getColorFS(), null, null); - sSceneManager.mDefaultState.setName("__DefaultState"); - } - return sSceneManager.mDefaultState; - } - - static Transform getDefaultTransform() { - if (sSceneManager == null) { - return null; - } - if (sSceneManager.mDefaultTransform == null) { - sSceneManager.mDefaultTransform = new MatrixTransform(); - sSceneManager.mDefaultTransform.setName("__DefaultTransform"); - } - return sSceneManager.mDefaultTransform; - } - - public static SceneManager getInstance() { - if (sSceneManager == null) { - sSceneManager = new SceneManager(); - } - return sSceneManager; - } - - protected SceneManager() { - } - - public void loadModel(String name, SceneLoadedCallback cb) { - ColladaScene scene = new ColladaScene(name, cb); - scene.init(mRS, mRes); - } - - public Mesh getScreenAlignedQuad() { - if (mQuad != null) { - return mQuad; - } - - Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, - 3, Mesh.TriangleMeshBuilder.TEXTURE_0); - - tmb.setTexture(0.0f, 1.0f).addVertex(-1.0f, 1.0f, 1.0f); - tmb.setTexture(0.0f, 0.0f).addVertex(-1.0f, -1.0f, 1.0f); - tmb.setTexture(1.0f, 0.0f).addVertex(1.0f, -1.0f, 1.0f); - tmb.setTexture(1.0f, 1.0f).addVertex(1.0f, 1.0f, 1.0f); - - tmb.addTriangle(0, 1, 2); - tmb.addTriangle(2, 3, 0); - - mQuad = tmb.create(true); - return mQuad; - } - - public Renderable getRenderableQuad(String name, RenderState state) { - Renderable quad = new Renderable(); - quad.setTransform(new MatrixTransform()); - quad.setMesh(getScreenAlignedQuad()); - quad.setName(name); - quad.setRenderState(state); - quad.setCullType(1); - return quad; - } - - public void initRS(RenderScriptGL rs, Resources res, int w, int h) { - mRS = rs; - mRes = res; - mAllocationMap = new HashMap<String, Allocation>(); - - mQuad = null; - mDefault2D = null; - mDefaultCube = null; - mDefaultVertex = null; - mColor = null; - mTexture = null; - mDefaultState = null; - mDefaultTransform = null; - - mExportScript = new ScriptC_export(rs, res, R.raw.export); - - mTransformScript = new ScriptC_transform(rs, res, R.raw.transform); - mTransformScript.set_gTransformScript(mTransformScript); - - mCameraScript = new ScriptC_camera(rs, res, R.raw.camera); - mLightScript = new ScriptC_light(rs, res, R.raw.light); - mObjectParamsScript = new ScriptC_object_params(rs, res, R.raw.object_params); - mFragmentParamsScript = new ScriptC_object_params(rs, res, R.raw.fragment_params); - mVertexParamsScript = new ScriptC_object_params(rs, res, R.raw.vertex_params); - mCullScript = new ScriptC_cull(rs, res, R.raw.cull); - - mRenderLoop = new ScriptC_render(rs, res, R.raw.render); - mRenderLoop.set_gTransformScript(mTransformScript); - mRenderLoop.set_gCameraScript(mCameraScript); - mRenderLoop.set_gLightScript(mLightScript); - mRenderLoop.set_gObjectParamsScript(mObjectParamsScript); - mRenderLoop.set_gFragmentParamsScript(mFragmentParamsScript); - mRenderLoop.set_gVertexParamsScript(mVertexParamsScript); - mRenderLoop.set_gCullScript(mCullScript); - - mRenderLoop.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS)); - } - - public ScriptC getRenderLoop() { - return mRenderLoop; - } -} - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java deleted file mode 100644 index 497511437115..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Shader.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; -import java.util.HashMap; - -import com.android.scenegraph.SceneGraphBase; -import com.android.scenegraph.ShaderParam; - -import android.renderscript.*; -import android.renderscript.ProgramFragment.Builder; -import android.util.Log; - -/** - * @hide - */ -public abstract class Shader extends SceneGraphBase { - protected Type mPerObjConstants; - protected Type mPerShaderConstants; - - protected HashMap<String, ShaderParam> mSourceParams; - protected ArrayList<String> mShaderTextureNames; - protected ArrayList<Program.TextureType > mShaderTextureTypes; - protected ArrayList<String> mTextureNames; - protected ArrayList<Program.TextureType > mTextureTypes; - - protected Allocation mConstantBuffer; - protected ScriptField_ShaderParam_s mConstantBufferParams; - - public Shader() { - mSourceParams = new HashMap<String, ShaderParam>(); - mShaderTextureNames = new ArrayList<String>(); - mShaderTextureTypes = new ArrayList<Program.TextureType>(); - mTextureNames = new ArrayList<String>(); - mTextureTypes = new ArrayList<Program.TextureType>(); - } - - public void appendSourceParams(ShaderParam p) { - mSourceParams.put(p.getParamName(), p); - } - - public Type getObjectConstants() { - return mPerObjConstants; - } - - public Type getShaderConstants() { - return mPerObjConstants; - } - - void linkConstants(RenderScriptGL rs) { - if (mPerShaderConstants == null) { - return; - } - - Element constElem = mPerShaderConstants.getElement(); - mConstantBufferParams = ShaderParam.fillInParams(constElem, mSourceParams, null); - - mConstantBuffer = Allocation.createTyped(rs, mPerShaderConstants); - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java deleted file mode 100644 index 3dd41cabe4c5..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/ShaderParam.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; -import java.util.HashMap; - -import com.android.scenegraph.SceneManager; -import com.android.scenegraph.Transform; - -import android.renderscript.Element; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.renderscript.RenderScriptGL; -import android.util.Log; - -/** - * @hide - */ -public abstract class ShaderParam extends SceneGraphBase { - - static final String cameraPos = "cameraPos"; - static final String cameraDir = "cameraDir"; - - static final String lightColor = "lightColor"; - static final String lightPos = "lightPos"; - static final String lightDir = "lightDir"; - - static final String view = "view"; - static final String proj = "proj"; - static final String viewProj = "viewProj"; - static final String model = "model"; - static final String modelView = "modelView"; - static final String modelViewProj = "modelViewProj"; - - static final long sMaxTimeStamp = 0xffffffffL; - - ScriptField_ShaderParamData_s.Item mData; - ScriptField_ShaderParamData_s mField; - - String mParamName; - Camera mCamera; - - static ScriptField_ShaderParam_s fillInParams(Element constantElem, - HashMap<String, ShaderParam> sourceParams, - Transform transform) { - RenderScriptGL rs = SceneManager.getRS(); - ArrayList<ScriptField_ShaderParam_s.Item> paramList; - paramList = new ArrayList<ScriptField_ShaderParam_s.Item>(); - - int subElemCount = constantElem.getSubElementCount(); - for (int i = 0; i < subElemCount; i ++) { - String inputName = constantElem.getSubElementName(i); - int offset = constantElem.getSubElementOffsetBytes(i); - - ShaderParam matchingParam = sourceParams.get(inputName); - Element subElem = constantElem.getSubElement(i); - // Make one if it's not there - if (matchingParam == null) { - if (subElem.getDataType() == Element.DataType.FLOAT_32) { - matchingParam = new Float4Param(inputName, 0.5f, 0.5f, 0.5f, 0.5f); - } else if (subElem.getDataType() == Element.DataType.MATRIX_4X4) { - TransformParam trParam = new TransformParam(inputName); - trParam.setTransform(transform); - matchingParam = trParam; - } - } - ScriptField_ShaderParam_s.Item paramRS = new ScriptField_ShaderParam_s.Item(); - paramRS.bufferOffset = offset; - paramRS.transformTimestamp = 0; - paramRS.dataTimestamp = 0; - paramRS.data = matchingParam.getRSData().getAllocation(); - if (subElem.getDataType() == Element.DataType.FLOAT_32) { - paramRS.float_vecSize = subElem.getVectorSize(); - } - - paramList.add(paramRS); - } - - ScriptField_ShaderParam_s rsParams = null; - int paramCount = paramList.size(); - if (paramCount != 0) { - rsParams = new ScriptField_ShaderParam_s(rs, paramCount); - for (int i = 0; i < paramCount; i++) { - rsParams.set(paramList.get(i), i, false); - } - rsParams.copyAll(); - } - return rsParams; - } - - public ShaderParam(String name) { - mParamName = name; - mData = new ScriptField_ShaderParamData_s.Item(); - } - - public String getParamName() { - return mParamName; - } - - public void setCamera(Camera c) { - mCamera = c; - if (mField != null) { - mData.camera = mCamera.getRSData().getAllocation(); - mField.set_camera(0, mData.camera, true); - } - } - - protected void incTimestamp() { - if (mField != null) { - mData.timestamp ++; - mData.timestamp %= sMaxTimeStamp; - mField.set_timestamp(0, mData.timestamp, true); - } - } - - abstract void initLocalData(); - - public ScriptField_ShaderParamData_s getRSData() { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - mField = new ScriptField_ShaderParamData_s(rs, 1); - - if (mParamName != null) { - mData.paramName = SceneManager.getCachedAlloc(mParamName); - if (mData.paramName == null) { - mData.paramName = SceneManager.getStringAsAllocation(rs, mParamName); - SceneManager.cacheAlloc(mParamName, mData.paramName); - } - } - initLocalData(); - mData.timestamp = 1; - - mField.set(mData, 0, true); - return mField; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java deleted file mode 100644 index b53ab883708e..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Texture2D.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; - -import com.android.scenegraph.SceneManager; - -import android.content.res.Resources; -import android.renderscript.*; -import android.util.Log; - -/** - * @hide - */ -public class Texture2D extends TextureBase { - String mFileName; - String mFileDir; - int mResourceID; - - public Texture2D() { - super(ScriptC_export.const_TextureType_TEXTURE_2D); - } - - public Texture2D(Allocation tex) { - super(ScriptC_export.const_TextureType_TEXTURE_2D); - setTexture(tex); - } - - public Texture2D(String dir, String file) { - super(ScriptC_export.const_TextureType_TEXTURE_CUBE); - setFileDir(dir); - setFileName(file); - } - - public Texture2D(int resourceID) { - super(ScriptC_export.const_TextureType_TEXTURE_2D); - mResourceID = resourceID; - } - - public void setFileDir(String dir) { - mFileDir = dir; - } - - public void setFileName(String file) { - mFileName = file; - } - - public String getFileName() { - return mFileName; - } - - public void setTexture(Allocation tex) { - mData.texture = tex != null ? tex : SceneManager.getDefaultTex2D(); - if (mField != null) { - mField.set_texture(0, mData.texture, true); - } - } - - void load() { - RenderScriptGL rs = SceneManager.getRS(); - Resources res = SceneManager.getRes(); - if (mFileName != null && mFileName.length() > 0) { - String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1); - setTexture(SceneManager.loadTexture2D(mFileDir + shortName, rs, res)); - } else if (mResourceID != 0) { - setTexture(SceneManager.loadTexture2D(mResourceID, rs, res)); - } - } - - ScriptField_Texture_s getRsData(boolean loadNow) { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - Resources res = SceneManager.getRes(); - if (rs == null || res == null) { - return null; - } - - mField = new ScriptField_Texture_s(rs, 1); - - if (loadNow) { - load(); - } else { - mData.texture = SceneManager.getDefaultTex2D(); - new SingleImageLoaderTask().execute(this); - } - - mField.set(mData, 0, true); - return mField; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java deleted file mode 100644 index ba49d4e2cc0e..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureBase.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (C) 2012 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.scenegraph; - -import java.lang.Math; - -import com.android.scenegraph.SceneManager; -import android.os.AsyncTask; -import android.content.res.Resources; -import android.renderscript.*; -import android.util.Log; - -/** - * @hide - */ -public abstract class TextureBase extends SceneGraphBase { - - class SingleImageLoaderTask extends AsyncTask<TextureBase, Void, Boolean> { - protected Boolean doInBackground(TextureBase... objects) { - TextureBase tex = objects[0]; - tex.load(); - return new Boolean(true); - } - protected void onPostExecute(Boolean result) { - } - } - - ScriptField_Texture_s.Item mData; - ScriptField_Texture_s mField; - TextureBase(int type) { - mData = new ScriptField_Texture_s.Item(); - mData.type = type; - } - - protected Allocation mRsTexture; - abstract ScriptField_Texture_s getRsData(boolean loadNow); - abstract void load(); -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java deleted file mode 100644 index 1269e3caa06a..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureCube.java +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; - -import com.android.scenegraph.SceneManager; -import com.android.scenegraph.TextureBase; - -import android.content.res.Resources; -import android.renderscript.*; -import android.util.Log; - -/** - * @hide - */ -public class TextureCube extends TextureBase { - String mFileName; - String mFileDir; - int mResourceID; - - public TextureCube() { - super(ScriptC_export.const_TextureType_TEXTURE_CUBE); - } - - public TextureCube(Allocation tex) { - super(ScriptC_export.const_TextureType_TEXTURE_CUBE); - setTexture(tex); - } - - public TextureCube(String dir, String file) { - super(ScriptC_export.const_TextureType_TEXTURE_CUBE); - setFileDir(dir); - setFileName(file); - } - - public TextureCube(int resourceID) { - super(ScriptC_export.const_TextureType_TEXTURE_2D); - mResourceID = resourceID; - } - - public void setFileDir(String dir) { - mFileDir = dir; - } - - public void setFileName(String file) { - mFileName = file; - } - - public String getFileName() { - return mFileName; - } - - public void setTexture(Allocation tex) { - mData.texture = tex != null ? tex : SceneManager.getDefaultTexCube(); - if (mField != null) { - mField.set_texture(0, mData.texture, true); - } - } - - void load() { - RenderScriptGL rs = SceneManager.getRS(); - Resources res = SceneManager.getRes(); - if (mFileName != null && mFileName.length() > 0) { - String shortName = mFileName.substring(mFileName.lastIndexOf('/') + 1); - setTexture(SceneManager.loadCubemap(mFileDir + shortName, rs, res)); - } else if (mResourceID != 0) { - setTexture(SceneManager.loadCubemap(mResourceID , rs, res)); - } - } - - ScriptField_Texture_s getRsData(boolean loadNow) { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - Resources res = SceneManager.getRes(); - if (rs == null || res == null) { - return null; - } - - mField = new ScriptField_Texture_s(rs, 1); - - if (loadNow) { - load(); - } else { - mData.texture = SceneManager.getDefaultTexCube(); - new SingleImageLoaderTask().execute(this); - } - - mField.set(mData, 0, true); - return mField; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java deleted file mode 100644 index e656ed264409..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureParam.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import android.graphics.Camera; -import android.renderscript.RenderScriptGL; -import android.renderscript.Float4; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.renderscript.Element; -import android.util.Log; - -/** - * @hide - */ -public class TextureParam extends ShaderParam { - - TextureBase mTexture; - - public TextureParam(String name) { - super(name); - } - - public TextureParam(String name, TextureBase t) { - super(name); - setTexture(t); - } - - public void setTexture(TextureBase t) { - mTexture = t; - } - - public TextureBase getTexture() { - return mTexture; - } - - void initLocalData() { - mData.type = ScriptC_export.const_ShaderParam_TEXTURE; - if (mTexture != null) { - mData.texture = mTexture.getRsData(false).getAllocation(); - } - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java deleted file mode 100644 index 6aa29a53ecc4..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TextureRenderTarget.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2012 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.scenegraph; - -import java.lang.Math; - -import com.android.scenegraph.SceneManager; - -import android.content.res.Resources; -import android.renderscript.*; -import android.util.Log; - -/** - * @hide - */ -public class TextureRenderTarget extends TextureBase { - public TextureRenderTarget() { - super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET); - } - - public TextureRenderTarget(Allocation tex) { - super(ScriptC_export.const_TextureType_TEXTURE_RENDER_TARGET); - setTexture(tex); - } - - public void setTexture(Allocation tex) { - mData.texture = tex; - if (mField != null) { - mField.set_texture(0, mData.texture, true); - } - } - - void load() { - } - - ScriptField_Texture_s getRsData(boolean loadNow) { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - if (rs == null) { - return null; - } - - mField = new ScriptField_Texture_s(rs, 1); - mField.set(mData, 0, true); - return mField; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java deleted file mode 100644 index 8180bd071636..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/Transform.java +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import android.renderscript.*; -import android.renderscript.Matrix4f; -import android.util.Log; - -/** - * @hide - */ -public abstract class Transform extends SceneGraphBase { - Transform mParent; - ArrayList<Transform> mChildren; - - ScriptField_SgTransform mField; - ScriptField_SgTransform.Item mTransformData; - - public Transform() { - mChildren = new ArrayList<Transform>(); - mParent = null; - } - - public void appendChild(Transform t) { - mChildren.add(t); - t.mParent = this; - updateRSChildData(true); - } - - abstract void initLocalData(); - - void updateRSChildData(boolean copyData) { - if (mField == null) { - return; - } - RenderScriptGL rs = SceneManager.getRS(); - if (mChildren.size() != 0) { - Allocation childRSData = Allocation.createSized(rs, Element.ALLOCATION(rs), - mChildren.size()); - mTransformData.children = childRSData; - - Allocation[] childrenAllocs = new Allocation[mChildren.size()]; - for (int i = 0; i < mChildren.size(); i ++) { - Transform child = mChildren.get(i); - childrenAllocs[i] = child.getRSData().getAllocation(); - } - childRSData.copyFrom(childrenAllocs); - } - if (copyData) { - mField.set(mTransformData, 0, true); - } - } - - ScriptField_SgTransform getRSData() { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - if (rs == null) { - return null; - } - mField = new ScriptField_SgTransform(rs, 1); - - mTransformData = new ScriptField_SgTransform.Item(); - mTransformData.name = getNameAlloc(rs); - mTransformData.isDirty = 1; - mTransformData.timestamp = 1; - - initLocalData(); - updateRSChildData(false); - - mField.set(mTransformData, 0, true); - return mField; - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java deleted file mode 100644 index d120d5d9b97d..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/TransformParam.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import android.renderscript.RenderScriptGL; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.renderscript.Element; -import android.util.Log; - -/** - * @hide - */ -public class TransformParam extends ShaderParam { - - Transform mTransform; - LightBase mLight; - - public TransformParam(String name) { - super(name); - } - - public void setTransform(Transform t) { - mTransform = t; - if (mField != null && mTransform != null) { - mData.transform = mTransform.getRSData().getAllocation(); - } - incTimestamp(); - } - - int getTypeFromName() { - int paramType = ScriptC_export.const_ShaderParam_TRANSFORM_DATA; - if (mParamName.equalsIgnoreCase(view)) { - paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW; - } else if(mParamName.equalsIgnoreCase(proj)) { - paramType = ScriptC_export.const_ShaderParam_TRANSFORM_PROJ; - } else if(mParamName.equalsIgnoreCase(viewProj)) { - paramType = ScriptC_export.const_ShaderParam_TRANSFORM_VIEW_PROJ; - } else if(mParamName.equalsIgnoreCase(model)) { - paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL; - } else if(mParamName.equalsIgnoreCase(modelView)) { - paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW; - } else if(mParamName.equalsIgnoreCase(modelViewProj)) { - paramType = ScriptC_export.const_ShaderParam_TRANSFORM_MODEL_VIEW_PROJ; - } - return paramType; - } - - void initLocalData() { - mData.type = getTypeFromName(); - if (mTransform != null) { - mData.transform = mTransform.getRSData().getAllocation(); - } - if (mCamera != null) { - mData.camera = mCamera.getRSData().getAllocation(); - } - if (mLight != null) { - mData.light = mLight.getRSData().getAllocation(); - } - } -} - - - - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java deleted file mode 100644 index 4efaff7bbb12..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/VertexShader.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2011 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.scenegraph; - -import java.lang.Math; -import java.util.ArrayList; - -import android.content.res.Resources; -import android.renderscript.*; -import android.util.Log; - -/** - * @hide - */ -public class VertexShader extends Shader { - ProgramVertex mProgram; - ScriptField_VertexShader_s mField; - - public static class Builder { - VertexShader mShader; - ProgramVertex.Builder mBuilder; - - public Builder(RenderScriptGL rs) { - mShader = new VertexShader(); - mBuilder = new ProgramVertex.Builder(rs); - } - - public Builder setShader(Resources resources, int resourceID) { - mBuilder.setShader(resources, resourceID); - return this; - } - - public Builder setShader(String code) { - mBuilder.setShader(code); - return this; - } - - public Builder setObjectConst(Type type) { - mShader.mPerObjConstants = type; - return this; - } - - public Builder setShaderConst(Type type) { - mShader.mPerShaderConstants = type; - return this; - } - - public Builder addInput(Element e) { - mBuilder.addInput(e); - return this; - } - - public VertexShader create() { - if (mShader.mPerShaderConstants != null) { - mBuilder.addConstant(mShader.mPerShaderConstants); - } - if (mShader.mPerObjConstants != null) { - mBuilder.addConstant(mShader.mPerObjConstants); - } - mShader.mProgram = mBuilder.create(); - return mShader; - } - } - - public ProgramVertex getProgram() { - return mProgram; - } - - ScriptField_VertexShader_s getRSData() { - if (mField != null) { - return mField; - } - - RenderScriptGL rs = SceneManager.getRS(); - Resources res = SceneManager.getRes(); - if (rs == null || res == null) { - return null; - } - - ScriptField_VertexShader_s.Item item = new ScriptField_VertexShader_s.Item(); - item.program = mProgram; - - linkConstants(rs); - if (mPerShaderConstants != null) { - item.shaderConst = mConstantBuffer; - item.shaderConstParams = mConstantBufferParams.getAllocation(); - mProgram.bindConstants(item.shaderConst, 0); - } - - item.objectConstIndex = -1; - if (mPerObjConstants != null) { - item.objectConstIndex = mPerShaderConstants != null ? 1 : 0; - } - - mField = new ScriptField_VertexShader_s(rs, 1); - mField.set(item, 0, true); - return mField; - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs deleted file mode 100644 index dc0a885a685d..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/camera.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -//#define DEBUG_CAMERA -#include "scenegraph_objects.rsh" - -void root(const rs_allocation *v_in, rs_allocation *v_out, const float *usrData) { - - SgCamera *cam = (SgCamera *)rsGetElementAt(*v_in, 0); - float aspect = *usrData; - if (cam->aspect != aspect) { - cam->isDirty = 1; - cam->aspect = aspect; - } - if (cam->isDirty) { - rsMatrixLoadPerspective(&cam->proj, cam->horizontalFOV, cam->aspect, cam->near, cam->far); - } - - const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0); - //rsDebug("Camera stamp", cam->transformTimestamp); - //rsDebug("Transform stamp", camTransform->timestamp); - if (camTransform->timestamp != cam->transformTimestamp || cam->isDirty) { - cam->isDirty = 1; - rs_matrix4x4 camPosMatrix; - rsMatrixLoad(&camPosMatrix, &camTransform->globalMat); - float4 zero = {0.0f, 0.0f, 0.0f, 1.0f}; - cam->position = rsMatrixMultiply(&camPosMatrix, zero); - - rsMatrixInverse(&camPosMatrix); - rsMatrixLoad(&cam->view, &camPosMatrix); - - rsMatrixLoad(&cam->viewProj, &cam->proj); - rsMatrixMultiply(&cam->viewProj, &cam->view); - - rsExtractFrustumPlanes(&cam->viewProj, - &cam->frustumPlanes[0], &cam->frustumPlanes[1], - &cam->frustumPlanes[2], &cam->frustumPlanes[3], - &cam->frustumPlanes[3], &cam->frustumPlanes[4]); - } - - if (cam->isDirty) { - cam->timestamp ++; - } - - cam->isDirty = 0; - cam->transformTimestamp = camTransform->timestamp; - -#ifdef DEBUG_CAMERA - printCameraInfo(cam); -#endif //DEBUG_CAMERA -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs deleted file mode 100644 index 024e026b69df..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/cull.rs +++ /dev/null @@ -1,86 +0,0 @@ -// Copyright (C) 2012 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -#include "scenegraph_objects.rsh" - -static void getTransformedSphere(SgRenderable *obj) { - obj->worldBoundingSphere = obj->boundingSphere; - obj->worldBoundingSphere.w = 1.0f; - const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0); - obj->worldBoundingSphere = rsMatrixMultiply(&objTransform->globalMat, obj->worldBoundingSphere); - - const float4 unitVec = {0.57735f, 0.57735f, 0.57735f, 0.0f}; - float4 scaledVec = rsMatrixMultiply(&objTransform->globalMat, unitVec); - scaledVec.w = 0.0f; - obj->worldBoundingSphere.w = obj->boundingSphere.w * length(scaledVec); -} - -static bool frustumCulled(SgRenderable *obj, SgCamera *cam) { - if (!obj->bVolInitialized) { - float minX, minY, minZ, maxX, maxY, maxZ; - rsgMeshComputeBoundingBox(obj->mesh, - &minX, &minY, &minZ, - &maxX, &maxY, &maxZ); - //rsDebug("min", minX, minY, minZ); - //rsDebug("max", maxX, maxY, maxZ); - float4 sphere; - sphere.x = (maxX + minX) * 0.5f; - sphere.y = (maxY + minY) * 0.5f; - sphere.z = (maxZ + minZ) * 0.5f; - float3 radius; - radius.x = (maxX - sphere.x); - radius.y = (maxY - sphere.y); - radius.z = (maxZ - sphere.z); - - sphere.w = length(radius); - obj->boundingSphere = sphere; - obj->bVolInitialized = 1; - //rsDebug("Sphere", sphere); - } - - getTransformedSphere(obj); - - return !rsIsSphereInFrustum(&obj->worldBoundingSphere, - &cam->frustumPlanes[0], &cam->frustumPlanes[1], - &cam->frustumPlanes[2], &cam->frustumPlanes[3], - &cam->frustumPlanes[4], &cam->frustumPlanes[5]); -} - - -void root(rs_allocation *v_out, const void *usrData) { - - SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0); - const SgCamera *camera = (const SgCamera*)usrData; - - drawable->isVisible = 0; - // Not loaded yet - if (!rsIsObject(drawable->mesh) || drawable->cullType == CULL_ALWAYS) { - return; - } - - // check to see if we are culling this object and if it's - // outside the frustum - if (drawable->cullType == CULL_FRUSTUM && frustumCulled(drawable, (SgCamera*)camera)) { -#ifdef DEBUG_RENDERABLES - rsDebug("Culled", drawable); - printName(drawable->name); -#endif // DEBUG_RENDERABLES - return; - } - drawable->isVisible = 1; -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs deleted file mode 100644 index b438a43abaab..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/export.rs +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -// The sole purpose of this script is to have various structs exposed -// so that java reflected classes are generated -#include "scenegraph_objects.rsh" - -// Export our native constants to java so that we don't have parallel definitions -const int ShaderParam_FLOAT4_DATA = SHADER_PARAM_FLOAT4_DATA; -const int ShaderParam_TRANSFORM_DATA = SHADER_PARAM_TRANSFORM_DATA; -const int ShaderParam_TRANSFORM_MODEL = SHADER_PARAM_TRANSFORM_MODEL; - -const int ShaderParam_FLOAT4_CAMERA_POS = SHADER_PARAM_FLOAT4_CAMERA_POS; -const int ShaderParam_FLOAT4_CAMERA_DIR = SHADER_PARAM_FLOAT4_CAMERA_DIR; -const int ShaderParam_TRANSFORM_VIEW = SHADER_PARAM_TRANSFORM_VIEW; -const int ShaderParam_TRANSFORM_PROJ = SHADER_PARAM_TRANSFORM_PROJ; -const int ShaderParam_TRANSFORM_VIEW_PROJ = SHADER_PARAM_TRANSFORM_VIEW_PROJ; -const int ShaderParam_TRANSFORM_MODEL_VIEW = SHADER_PARAM_TRANSFORM_MODEL_VIEW; -const int ShaderParam_TRANSFORM_MODEL_VIEW_PROJ = SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ; - -const int ShaderParam_FLOAT4_LIGHT_COLOR = SHADER_PARAM_FLOAT4_LIGHT_COLOR; -const int ShaderParam_FLOAT4_LIGHT_POS = SHADER_PARAM_FLOAT4_LIGHT_POS; -const int ShaderParam_FLOAT4_LIGHT_DIR = SHADER_PARAM_FLOAT4_LIGHT_DIR; - -const int ShaderParam_TEXTURE = SHADER_PARAM_TEXTURE; - -const int Transform_TRANSLATE = TRANSFORM_TRANSLATE; -const int Transform_ROTATE = TRANSFORM_ROTATE; -const int Transform_SCALE = TRANSFORM_SCALE; - -const int TextureType_TEXTURE_2D = TEXTURE_2D; -const int TextureType_TEXTURE_CUBE = TEXTURE_CUBE; -const int TextureType_TEXTURE_RENDER_TARGET = TEXTURE_RENDER_TARGET; - -SgTransform *exportPtr; -SgTransformComponent *componentPtr; -SgRenderState *sExport; -SgRenderable *drExport; -SgRenderPass *pExport; -SgCamera *exportPtrCam; -SgLight *exportPtrLight; -SgShaderParam *spExport; -SgShaderParamData *spDataExport; -SgVertexShader *pvExport; -SgFragmentShader *pfExport; -SgTexture *texExport; diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs deleted file mode 100644 index 7202285c247e..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/fragment_params.rs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (C) 2012 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -#include "scenegraph_objects.rsh" - -//#define DEBUG_PARAMS - -#include "params.rsh" - -void root(rs_allocation *v_out, const void *usrData) { - SgFragmentShader *shader = (SgFragmentShader *)rsGetElementAt(*v_out, 0); - const SgCamera *camera = (const SgCamera*)usrData; - processAllParams(shader->shaderConst, shader->shaderConstParams, camera); - processTextureParams(shader); -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs deleted file mode 100644 index e11979f27ff8..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/light.rs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -//#define DEBUG_LIGHT -#include "scenegraph_objects.rsh" - -void root(const rs_allocation *v_in, rs_allocation *v_out) { - - SgLight *light = (SgLight *)rsGetElementAt(*v_in, 0); - const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0); - - float4 zero = {0.0f, 0.0f, 0.0f, 1.0f}; - light->position = rsMatrixMultiply(&lTransform->globalMat, zero); - -#ifdef DEBUG_LIGHT - printLightInfo(light); -#endif //DEBUG_LIGHT -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs deleted file mode 100644 index 0d524a663150..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/object_params.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright (C) 2012 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -#include "scenegraph_objects.rsh" - -//#define DEBUG_PARAMS - -#include "params.rsh" - -void root(rs_allocation *v_out, const void *usrData) { - - SgRenderable *drawable = (SgRenderable *)rsGetElementAt(*v_out, 0); - // Visibility flag was set earlier in the cull stage - if (!drawable->isVisible) { - return; - } - - const SgCamera *camera = (const SgCamera*)usrData; - processAllParams(drawable->pf_const, drawable->pf_constParams, camera); - processAllParams(drawable->pv_const, drawable->pv_constParams, camera); -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh deleted file mode 100644 index 00793c0ab301..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/params.rsh +++ /dev/null @@ -1,192 +0,0 @@ -// Copyright (C) 2012 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -#include "scenegraph_objects.rsh" - -//#define DEBUG_PARAMS -static inline void debugParam(SgShaderParam *p, SgShaderParamData *pData) { - rsDebug("____________ Param ____________", p); - printName(pData->paramName); - rsDebug("bufferOffset", p->bufferOffset); - rsDebug("type ", pData->type); - rsDebug("data timestamp ", pData->timestamp); - rsDebug("param timestamp", p->dataTimestamp); - - const SgTransform *pTransform = NULL; - if (rsIsObject(pData->transform)) { - pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0); - - rsDebug("transform", pTransform); - printName(pTransform->name); - rsDebug("timestamp", pTransform->timestamp); - rsDebug("param timestamp", p->transformTimestamp); - } - - const SgLight *pLight = NULL; - if (rsIsObject(pData->light)) { - pLight = (const SgLight *)rsGetElementAt(pData->light, 0); - printLightInfo(pLight); - } -} - -static inline void writeFloatData(float *ptr, const float4 *input, uint32_t vecSize) { -#ifdef DEBUG_PARAMS - rsDebug("Writing value ", *input); - rsDebug("Writing vec size ", vecSize); -#endif // DEBUG_PARAMS - - switch (vecSize) { - case 1: - *ptr = input->x; - break; - case 2: - *((float2*)ptr) = (*input).xy; - break; - case 3: - *((float3*)ptr) = (*input).xyz; - break; - case 4: - *((float4*)ptr) = *input; - break; - } -} - -static inline bool processParam(SgShaderParam *p, SgShaderParamData *pData, - uint8_t *constantBuffer, - const SgCamera *currentCam, - SgFragmentShader *shader) { - bool isDataOnly = (pData->type > SHADER_PARAM_DATA_ONLY); - const SgTransform *pTransform = NULL; - if (rsIsObject(pData->transform)) { - pTransform = (const SgTransform *)rsGetElementAt(pData->transform, 0); - } - - if (isDataOnly) { - // If we are a transform param and our transform is unchanged, nothing to do - if (pTransform) { - if (p->transformTimestamp == pTransform->timestamp) { - return false; - } - p->transformTimestamp = pTransform->timestamp; - } else { - if (p->dataTimestamp == pData->timestamp) { - return false; - } - p->dataTimestamp = pData->timestamp; - } - } - - const SgLight *pLight = NULL; - if (rsIsObject(pData->light)) { - pLight = (const SgLight *)rsGetElementAt(pData->light, 0); - } - - uint8_t *dataPtr = NULL; - const SgTexture *tex = NULL; - if (pData->type == SHADER_PARAM_TEXTURE) { - tex = rsGetElementAt(pData->texture, 0); - } else { - dataPtr = constantBuffer + p->bufferOffset; - } - - switch (pData->type) { - case SHADER_PARAM_TEXTURE: - rsgBindTexture(shader->program, p->bufferOffset, tex->texture); - break; - case SHADER_PARAM_FLOAT4_DATA: - writeFloatData((float*)dataPtr, &pData->float_value, p->float_vecSize); - break; - case SHADER_PARAM_FLOAT4_CAMERA_POS: - writeFloatData((float*)dataPtr, ¤tCam->position, p->float_vecSize); - break; - case SHADER_PARAM_FLOAT4_CAMERA_DIR: break; - case SHADER_PARAM_FLOAT4_LIGHT_COLOR: - writeFloatData((float*)dataPtr, &pLight->color, p->float_vecSize); - break; - case SHADER_PARAM_FLOAT4_LIGHT_POS: - writeFloatData((float*)dataPtr, &pLight->position, p->float_vecSize); - break; - case SHADER_PARAM_FLOAT4_LIGHT_DIR: break; - - case SHADER_PARAM_TRANSFORM_DATA: - rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat); - break; - case SHADER_PARAM_TRANSFORM_VIEW: - rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->view); - break; - case SHADER_PARAM_TRANSFORM_PROJ: - rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->proj); - break; - case SHADER_PARAM_TRANSFORM_VIEW_PROJ: - rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->viewProj); - break; - case SHADER_PARAM_TRANSFORM_MODEL: - rsMatrixLoad((rs_matrix4x4*)dataPtr, &pTransform->globalMat); - break; - case SHADER_PARAM_TRANSFORM_MODEL_VIEW: - rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->view); - rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr, - (rs_matrix4x4*)dataPtr, - &pTransform->globalMat); - break; - case SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ: - rsMatrixLoad((rs_matrix4x4*)dataPtr, ¤tCam->viewProj); - rsMatrixLoadMultiply((rs_matrix4x4*)dataPtr, - (rs_matrix4x4*)dataPtr, - &pTransform->globalMat); - break; - } - return true; -} - -static inline void processAllParams(rs_allocation shaderConst, - rs_allocation allParams, - const SgCamera *camera) { - if (rsIsObject(shaderConst)) { - uint8_t *constantBuffer = (uint8_t*)rsGetElementAt(shaderConst, 0); - - int numParams = 0; - if (rsIsObject(allParams)) { - numParams = rsAllocationGetDimX(allParams); - } - bool updated = false; - for (int i = 0; i < numParams; i ++) { - SgShaderParam *current = (SgShaderParam*)rsGetElementAt(allParams, i); - SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0); -#ifdef DEBUG_PARAMS - debugParam(current, currentData); -#endif // DEBUG_PARAMS - updated = processParam(current, currentData, constantBuffer, camera, NULL) || updated; - } - } -} - -static inline void processTextureParams(SgFragmentShader *shader) { - int numParams = 0; - if (rsIsObject(shader->shaderTextureParams)) { - numParams = rsAllocationGetDimX(shader->shaderTextureParams); - } - for (int i = 0; i < numParams; i ++) { - SgShaderParam *current = (SgShaderParam*)rsGetElementAt(shader->shaderTextureParams, i); - SgShaderParamData *currentData = (SgShaderParamData*)rsGetElementAt(current->data, 0); -#ifdef DEBUG_PARAMS - debugParam(current, currentData); -#endif // DEBUG_PARAMS - processParam(current, currentData, NULL, NULL, shader); - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs deleted file mode 100644 index 205b2cb8c767..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/render.rs +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright (C) 2011-2012 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -#include "rs_graphics.rsh" -#include "scenegraph_objects.rsh" - -rs_script gTransformScript; -rs_script gCameraScript; -rs_script gLightScript; -rs_script gObjectParamsScript; -rs_script gFragmentParamsScript; -rs_script gVertexParamsScript; -rs_script gCullScript; - -SgTransform *gRootNode; -rs_allocation gCameras; -rs_allocation gLights; -rs_allocation gFragmentShaders; -rs_allocation gVertexShaders; -rs_allocation gRenderableObjects; - -rs_allocation gRenderPasses; - -// Temporary shaders -rs_program_store gPFSBackground; - -uint32_t *gFrontToBack; -static uint32_t gFrontToBackCount = 0; -uint32_t *gBackToFront; -static uint32_t gBackToFrontCount = 0; - -static SgCamera *gActiveCamera = NULL; - -static rs_allocation nullAlloc; - -// #define DEBUG_RENDERABLES -static void draw(SgRenderable *obj) { -#ifdef DEBUG_RENDERABLES - const SgTransform *objTransform = (const SgTransform *)rsGetElementAt(obj->transformMatrix, 0); - rsDebug("**** Drawing object with transform", obj); - printName(objTransform->name); - rsDebug("Model matrix: ", &objTransform->globalMat); - printName(obj->name); -#endif //DEBUG_RENDERABLES - - const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0); - const SgVertexShader *pv = (const SgVertexShader *)rsGetElementAt(renderState->pv, 0); - const SgFragmentShader *pf = (const SgFragmentShader *)rsGetElementAt(renderState->pf, 0); - - if (pv->objectConstIndex != -1) { - rsgBindConstant(pv->program, pv->objectConstIndex, obj->pv_const); - } - if (pf->objectConstIndex != -1) { - rsgBindConstant(pf->program, pf->objectConstIndex, obj->pf_const); - } - - if (rsIsObject(renderState->ps)) { - rsgBindProgramStore(renderState->ps); - } else { - rsgBindProgramStore(gPFSBackground); - } - - if (rsIsObject(renderState->pr)) { - rsgBindProgramRaster(renderState->pr); - } else { - rs_program_raster pr = {0}; - rsgBindProgramRaster(pr); - } - - rsgBindProgramVertex(pv->program); - rsgBindProgramFragment(pf->program); - - for (uint32_t i = 0; i < obj->pf_num_textures; i ++) { - const SgTexture *tex = rsGetElementAt(obj->pf_textures[i], 0); - rsgBindTexture(pf->program, i, tex->texture); - } - - rsgDrawMesh(obj->mesh, obj->meshIndex); -} - -static void sortToBucket(SgRenderable *obj) { - const SgRenderState *renderState = (const SgRenderState *)rsGetElementAt(obj->render_state, 0); - if (rsIsObject(renderState->ps)) { - bool isOpaque = false; - if (isOpaque) { - gFrontToBack[gFrontToBackCount++] = (uint32_t)obj; - } else { - gBackToFront[gBackToFrontCount++] = (uint32_t)obj; - } - } else { - gFrontToBack[gFrontToBackCount++] = (uint32_t)obj; - } -} - -static void updateActiveCamera(rs_allocation cam) { - gActiveCamera = (SgCamera *)rsGetElementAt(cam, 0); -} - -static void prepareCameras() { - // now compute all the camera matrices - if (rsIsObject(gCameras)) { - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsForEach(gCameraScript, gCameras, nullAlloc, &aspect, sizeof(aspect)); - } -} - -static void prepareLights() { - if (rsIsObject(gLights)) { - rsForEach(gLightScript, gLights, nullAlloc); - } -} - -static void drawSorted() { - for (int i = 0; i < gFrontToBackCount; i ++) { - SgRenderable *current = (SgRenderable*)gFrontToBack[i]; - draw(current); - } - - for (int i = 0; i < gBackToFrontCount; i ++) { - SgRenderable *current = (SgRenderable*)gBackToFront[i]; - draw(current); - } -} - -static void drawAllObjects(rs_allocation allObj) { - if (!rsIsObject(allObj)) { - return; - } - - if (rsIsObject(gVertexShaders)) { - rsForEach(gVertexParamsScript, nullAlloc, gVertexShaders, - gActiveCamera, sizeof(gActiveCamera)); - } - if (rsIsObject(gFragmentShaders)) { - rsForEach(gFragmentParamsScript, nullAlloc, gFragmentShaders, - gActiveCamera, sizeof(gActiveCamera)); - } - - // Run the params and cull script - rsForEach(gCullScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera)); - rsForEach(gObjectParamsScript, nullAlloc, allObj, gActiveCamera, sizeof(gActiveCamera)); - - int numRenderables = rsAllocationGetDimX(allObj); - for (int i = 0; i < numRenderables; i ++) { - rs_allocation *drawAlloc = (rs_allocation*)rsGetElementAt(allObj, i); - SgRenderable *current = (SgRenderable*)rsGetElementAt(*drawAlloc, 0); - if (current->isVisible) { - sortToBucket(current); - } - } - drawSorted(); -} - -int root(void) { -#ifdef DEBUG_RENDERABLES - rsDebug("=============================================================================", 0); -#endif // DEBUG_RENDERABLES - - // first step is to update the transform hierachy - if (gRootNode && rsIsObject(gRootNode->children)) { - rsForEach(gTransformScript, gRootNode->children, nullAlloc, 0, 0); - } - - prepareCameras(); - prepareLights(); - - if (rsIsObject(gRenderPasses)) { - rsgClearDepth(1.0f); - int numPasses = rsAllocationGetDimX(gRenderPasses); - for (uint i = 0; i < numPasses; i ++) { - gFrontToBackCount = 0; - gBackToFrontCount = 0; - SgRenderPass *pass = (SgRenderPass*)rsGetElementAt(gRenderPasses, i); - if (rsIsObject(pass->color_target)) { - rsgBindColorTarget(pass->color_target, 0); - } - if (rsIsObject(pass->depth_target)) { - rsgBindDepthTarget(pass->depth_target); - } - if (!rsIsObject(pass->color_target) && - !rsIsObject(pass->depth_target)) { - rsgClearAllRenderTargets(); - } - updateActiveCamera(pass->camera); - if (pass->should_clear_color) { - rsgClearColor(pass->clear_color.x, pass->clear_color.y, - pass->clear_color.z, pass->clear_color.w); - } - if (pass->should_clear_depth) { - rsgClearDepth(pass->clear_depth); - } - drawAllObjects(pass->objects); - } - } else { - gFrontToBackCount = 0; - gBackToFrontCount = 0; - rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgClearDepth(1.0f); - - if (rsIsObject(gCameras)) { - rs_allocation *camAlloc = (rs_allocation*)rsGetElementAt(gCameras, 0); - updateActiveCamera(*camAlloc); - } - drawAllObjects(gRenderableObjects); - } - return 10; -} - -// Search through sorted and culled objects -void pick(int screenX, int screenY) { - float3 pnt, vec; - getCameraRay(gActiveCamera, screenX, screenY, &pnt, &vec); - - for (int i = 0; i < gFrontToBackCount; i ++) { - SgRenderable *current = (SgRenderable*)gFrontToBack[i]; - bool isPicked = intersect(current, pnt, vec); - if (isPicked) { - current->cullType = CULL_ALWAYS; - } - } - - for (int i = 0; i < gBackToFrontCount; i ++) { - SgRenderable *current = (SgRenderable*)gBackToFront[i]; - bool isPicked = intersect(current, pnt, vec); - if (isPicked) { - current->cullType = CULL_ALWAYS; - } - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh deleted file mode 100644 index 90ae2129d6e7..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/scenegraph_objects.rsh +++ /dev/null @@ -1,323 +0,0 @@ -// Copyright (C) 2011-2012 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -#ifndef _TRANSFORM_DEF_ -#define _TRANSFORM_DEF_ - -#include "rs_graphics.rsh" - -#define TRANSFORM_NONE 0 -#define TRANSFORM_TRANSLATE 1 -#define TRANSFORM_ROTATE 2 -#define TRANSFORM_SCALE 3 - -#define CULL_FRUSTUM 0 -#define CULL_ALWAYS 2 - -#define LIGHT_POINT 0 -#define LIGHT_DIRECTIONAL 1 - -// Shader params that involve only data -#define SHADER_PARAM_DATA_ONLY 10000 -#define SHADER_PARAM_FLOAT4_DATA 10001 -#define SHADER_PARAM_TRANSFORM_DATA 10002 -#define SHADER_PARAM_TRANSFORM_MODEL 10003 - -// Shader params that involve camera -#define SHADER_PARAM_CAMERA 1000 -#define SHADER_PARAM_FLOAT4_CAMERA_POS 1001 -#define SHADER_PARAM_FLOAT4_CAMERA_DIR 1002 -#define SHADER_PARAM_TRANSFORM_VIEW 1003 -#define SHADER_PARAM_TRANSFORM_PROJ 1004 -#define SHADER_PARAM_TRANSFORM_VIEW_PROJ 1005 -#define SHADER_PARAM_TRANSFORM_MODEL_VIEW 1006 -#define SHADER_PARAM_TRANSFORM_MODEL_VIEW_PROJ 1007 - -// Shader Params that only involve lights -#define SHADER_PARAM_LIGHT 100 -#define SHADER_PARAM_FLOAT4_LIGHT_COLOR 103 -#define SHADER_PARAM_FLOAT4_LIGHT_POS 104 -#define SHADER_PARAM_FLOAT4_LIGHT_DIR 105 - -#define SHADER_PARAM_TEXTURE 10 - -#define TEXTURE_NONE 0 -#define TEXTURE_2D 1 -#define TEXTURE_CUBE 2 -#define TEXTURE_RENDER_TARGET 3 - -typedef struct TransformComponent_s { - float4 value; - int type; - rs_allocation name; -} SgTransformComponent; - -typedef struct __attribute__((packed, aligned(4))) SgTransform { - rs_matrix4x4 globalMat; - rs_matrix4x4 localMat; - - rs_allocation components; - int isDirty; - - rs_allocation children; - rs_allocation name; - - // Used to check whether transform params need to be updated - uint32_t timestamp; -} SgTransform; - -typedef struct VertexShader_s { - rs_program_vertex program; - // Buffer with vertex constant data - rs_allocation shaderConst; - // ShaderParam's that populate data - rs_allocation shaderConstParams; - // location of the per object constants on the buffer - int objectConstIndex; -} SgVertexShader; - -typedef struct FragmentShader_s { - rs_program_fragment program; - // Buffer with vertex constant data - rs_allocation shaderConst; - // ShaderParam's that populate data - rs_allocation shaderConstParams; - // ShaderParam's that set textures - rs_allocation shaderTextureParams; - // location of the per object constants on the buffer - int objectConstIndex; -} SgFragmentShader; - -typedef struct RenderState_s { - rs_allocation pv; // VertexShader struct - rs_allocation pf; // FragmentShader struct - rs_program_store ps; - rs_program_raster pr; -} SgRenderState; - -typedef struct Renderable_s { - rs_allocation render_state; - // Buffer with vertex constant data - rs_allocation pv_const; - // ShaderParam's that populate data - rs_allocation pv_constParams; - // Buffer with fragment constant data - rs_allocation pf_const; - // ShaderParam's that populate data - rs_allocation pf_constParams; - rs_allocation pf_textures[8]; - int pf_num_textures; - rs_mesh mesh; - int meshIndex; - rs_allocation transformMatrix; - rs_allocation name; - float4 boundingSphere; - float4 worldBoundingSphere; - int bVolInitialized; - int cullType; // specifies whether to frustum cull - int isVisible; -} SgRenderable; - -typedef struct RenderPass_s { - rs_allocation color_target; - rs_allocation depth_target; - rs_allocation camera; - rs_allocation objects; - - float4 clear_color; - float clear_depth; - bool should_clear_color; - bool should_clear_depth; -} SgRenderPass; - -typedef struct Camera_s { - rs_matrix4x4 proj; - rs_matrix4x4 view; - rs_matrix4x4 viewProj; - float4 position; - float near; - float far; - float horizontalFOV; - float aspect; - rs_allocation name; - rs_allocation transformMatrix; - float4 frustumPlanes[6]; - - int isDirty; - // Timestamp of the camera itself to signal params if anything changes - uint32_t timestamp; - // Timestamp of our transform - uint32_t transformTimestamp; -} SgCamera; - -typedef struct Light_s { - float4 position; - float4 color; - float intensity; - int type; - rs_allocation name; - rs_allocation transformMatrix; -} SgLight; - -// This represents the shader parameter data needed to set a float or transform data -typedef struct ShaderParamData_s { - int type; - float4 float_value; - uint32_t timestamp; - rs_allocation paramName; - rs_allocation camera; - rs_allocation light; - rs_allocation transform; - rs_allocation texture; -} SgShaderParamData; - -// This represents a shader parameter that knows how to update itself for a given -// renderable or shader and contains a timestamp for the last time this buffer was updated -typedef struct ShaderParam_s { - // Used to check whether transform params need to be updated - uint32_t transformTimestamp; - // Used to check whether data params need to be updated - // These are used when somebody set the matrix of float value directly in java - uint32_t dataTimestamp; - // Specifies where in the constant buffer data gets written to - int bufferOffset; - // An instance of SgShaderParamData that could be shared by multiple objects - rs_allocation data; - // How many components of the vector we need to write - int float_vecSize; -} SgShaderParam; - -// This represents a texture object -typedef struct Texture_s { - uint32_t type; - rs_allocation texture; -} SgTexture; - -static inline void printName(rs_allocation name) { - if (!rsIsObject(name)) { - rsDebug("no name", 0); - return; - } - - rsDebug((const char*)rsGetElementAt(name, 0), 0); -} - -static inline void printCameraInfo(const SgCamera *cam) { - rsDebug("***** Camera information. ptr:", cam); - printName(cam->name); - const SgTransform *camTransform = (const SgTransform *)rsGetElementAt(cam->transformMatrix, 0); - rsDebug("Transform name:", camTransform); - printName(camTransform->name); - - rsDebug("Aspect: ", cam->aspect); - rsDebug("Near: ", cam->near); - rsDebug("Far: ", cam->far); - rsDebug("Fov: ", cam->horizontalFOV); - rsDebug("Position: ", cam->position); - rsDebug("Proj: ", &cam->proj); - rsDebug("View: ", &cam->view); -} - -static inline void printLightInfo(const SgLight *light) { - rsDebug("***** Light information. ptr:", light); - printName(light->name); - const SgTransform *lTransform = (const SgTransform *)rsGetElementAt(light->transformMatrix, 0); - rsDebug("Transform name:", lTransform); - printName(lTransform->name); - - rsDebug("Position: ", light->position); - rsDebug("Color : ", light->color); - rsDebug("Intensity: ", light->intensity); - rsDebug("Type: ", light->type); -} - -static inline void getCameraRay(const SgCamera *cam, int screenX, int screenY, float3 *pnt, float3 *vec) { - rsDebug("=================================", screenX); - rsDebug("Point X", screenX); - rsDebug("Point Y", screenY); - - rs_matrix4x4 mvpInv; - rsMatrixLoad(&mvpInv, &cam->viewProj); - rsMatrixInverse(&mvpInv); - - float width = (float)rsgGetWidth(); - float height = (float)rsgGetHeight(); - - float4 pos = {(float)screenX, height - (float)screenY, 0.0f, 1.0f}; - - pos.x /= width; - pos.y /= height; - - rsDebug("Pre Norm X", pos.x); - rsDebug("Pre Norm Y", pos.y); - - pos.xy = pos.xy * 2.0f - 1.0f; - - rsDebug("Norm X", pos.x); - rsDebug("Norm Y", pos.y); - - pos = rsMatrixMultiply(&mvpInv, pos); - float oneOverW = 1.0f / pos.w; - pos.xyz *= oneOverW; - - rsDebug("World X", pos.x); - rsDebug("World Y", pos.y); - rsDebug("World Z", pos.z); - - rsDebug("Cam X", cam->position.x); - rsDebug("Cam Y", cam->position.y); - rsDebug("Cam Z", cam->position.z); - - *vec = normalize(pos.xyz - cam->position.xyz); - rsDebug("Vec X", vec->x); - rsDebug("Vec Y", vec->y); - rsDebug("Vec Z", vec->z); - *pnt = cam->position.xyz; -} - -static inline bool intersect(const SgRenderable *obj, float3 pnt, float3 vec) { - // Solving for t^2 + Bt + C = 0 - float3 originMinusCenter = pnt - obj->worldBoundingSphere.xyz; - float B = dot(originMinusCenter, vec) * 2.0f; - float C = dot(originMinusCenter, originMinusCenter) - - obj->worldBoundingSphere.w * obj->worldBoundingSphere.w; - - float discriminant = B * B - 4.0f * C; - if (discriminant < 0.0f) { - return false; - } - discriminant = sqrt(discriminant); - - float t0 = (-B - discriminant) * 0.5f; - float t1 = (-B + discriminant) * 0.5f; - - if (t0 > t1) { - float temp = t0; - t0 = t1; - t1 = temp; - } - - // The sphere is behind us - if (t1 < 0.0f) { - return false; - } - return true; -} - - -#endif // _TRANSFORM_DEF_ diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs deleted file mode 100644 index 1d0b5be73722..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/transform.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.modelviewer) - -#include "scenegraph_objects.rsh" - -rs_script gTransformScript; - -typedef struct { - int changed; - rs_matrix4x4 *mat; -} ParentData; - -//#define DEBUG_TRANSFORMS -/* Unused function: -static void debugTransform(SgTransform *data, const ParentData *parent) { - rsDebug("****** <Transform> ******", (int)data); - printName(data->name); - rsDebug("isDirty", data->isDirty); - rsDebug("parent", (int)parent); - rsDebug("child ", rsIsObject(data->children)); - - // Refresh matrices if dirty - if (data->isDirty && rsIsObject(data->components)) { - uint32_t numComponenets = rsAllocationGetDimX(data->components); - for (int i = 0; i < numComponenets; i ++) { - const SgTransformComponent *comp = NULL; - comp = (const SgTransformComponent *)rsGetElementAt(data->components, i); - - if (rsIsObject(comp->name)) { - rsDebug((const char*)rsGetElementAt(comp->name, 0), comp->value); - rsDebug("Type", comp->type); - } else { - rsDebug("no name", comp->value); - rsDebug("Type", comp->type); - } - } - } - - rsDebug("timestamp", data->timestamp); - rsDebug("****** </Transform> ******", (int)data); -} -*/ - -static void appendTransformation(int type, float4 data, rs_matrix4x4 *mat) { - rs_matrix4x4 temp; - - switch (type) { - case TRANSFORM_TRANSLATE: - rsMatrixLoadTranslate(&temp, data.x, data.y, data.z); - break; - case TRANSFORM_ROTATE: - rsMatrixLoadRotate(&temp, data.w, data.x, data.y, data.z); - break; - case TRANSFORM_SCALE: - rsMatrixLoadScale(&temp, data.x, data.y, data.z); - break; - } - rsMatrixMultiply(mat, &temp); -} - -void root(const rs_allocation *v_in, rs_allocation *v_out, const void *usrData) { - - SgTransform *data = (SgTransform *)rsGetElementAt(*v_in, 0); - const ParentData *parent = (const ParentData *)usrData; - -#ifdef DEBUG_TRANSFORMS - debugTransform(data, parent); -#endif //DEBUG_TRANSFORMS - - rs_matrix4x4 *localMat = &data->localMat; - rs_matrix4x4 *globalMat = &data->globalMat; - - // Refresh matrices if dirty - if (data->isDirty && rsIsObject(data->components)) { - bool resetLocal = false; - uint32_t numComponenets = rsAllocationGetDimX(data->components); - for (int i = 0; i < numComponenets; i ++) { - if (!resetLocal) { - // Reset our local matrix only for component transforms - rsMatrixLoadIdentity(localMat); - resetLocal = true; - } - const SgTransformComponent *comp = NULL; - comp = (const SgTransformComponent *)rsGetElementAt(data->components, i); - appendTransformation(comp->type, comp->value, localMat); - } - } - - if (parent) { - data->isDirty = (parent->changed || data->isDirty) ? 1 : 0; - if (data->isDirty) { - rsMatrixLoad(globalMat, parent->mat); - rsMatrixMultiply(globalMat, localMat); - } - } else if (data->isDirty) { - rsMatrixLoad(globalMat, localMat); - } - - ParentData toChild; - toChild.changed = 0; - toChild.mat = globalMat; - - if (data->isDirty) { - toChild.changed = 1; - data->timestamp ++; - } - - if (rsIsObject(data->children)) { - rs_allocation nullAlloc = {0}; - rsForEach(gTransformScript, data->children, nullAlloc, &toChild, sizeof(toChild)); - } - - data->isDirty = 0; -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs deleted file mode 100644 index 88955a88ffdd..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/vertex_params.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Copyright (C) 2012 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 version(1) - -#pragma rs java_package_name(com.android.scenegraph) - -#include "scenegraph_objects.rsh" - -//#define DEBUG_PARAMS - -#include "params.rsh" - -void root(rs_allocation *v_out, const void *usrData) { - SgVertexShader *shader = (SgVertexShader *)rsGetElementAt(*v_out, 0); - const SgCamera *camera = (const SgCamera*)usrData; - processAllParams(shader->shaderConst, shader->shaderConstParams, camera); -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java deleted file mode 100644 index 420e1330d88a..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FileSelector.java +++ /dev/null @@ -1,110 +0,0 @@ -/* - * Copyright (C) 2011 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.testapp; - -import java.io.File; -import java.io.FileFilter; -import java.util.ArrayList; -import java.util.List; - -import android.app.ListActivity; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.view.View; -import android.widget.ArrayAdapter; -import android.widget.ListView; - -/** - * A list view where the last item the user clicked is placed in - * the "activated" state, causing its background to highlight. - */ -public class FileSelector extends ListActivity { - - File[] mCurrentSubList; - File mCurrentFile; - - class DAEFilter implements FileFilter { - public boolean accept(File file) { - if (file.isDirectory()) { - return true; - } - return file.getName().endsWith(".dae"); - } - } - - private void populateList(File file) { - - mCurrentFile = file; - setTitle(mCurrentFile.getAbsolutePath() + "/*.dae"); - List<String> names = new ArrayList<String>(); - names.add(".."); - - mCurrentSubList = mCurrentFile.listFiles(new DAEFilter()); - - if (mCurrentSubList != null) { - for (int i = 0; i < mCurrentSubList.length; i ++) { - String fileName = mCurrentSubList[i].getName(); - if (mCurrentSubList[i].isDirectory()) { - fileName = "/" + fileName; - } - names.add(fileName); - } - } - - // Use the built-in layout for showing a list item with a single - // line of text whose background is changes when activated. - setListAdapter(new ArrayAdapter<String>(this, - android.R.layout.simple_list_item_activated_1, names)); - getListView().setTextFilterEnabled(true); - - // Tell the list view to show one checked/activated item at a time. - getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - populateList(new File("/sdcard/")); - } - - @Override - protected void onListItemClick(ListView l, View v, int position, long id) { - if (position == 0) { - File parent = mCurrentFile.getParentFile(); - if (parent == null) { - return; - } - populateList(parent); - return; - } - - // the first thing in list is parent directory - File selectedFile = mCurrentSubList[position - 1]; - if (selectedFile.isDirectory()) { - populateList(selectedFile); - return; - } - - Intent resultIntent = new Intent(); - resultIntent.setData(Uri.fromFile(selectedFile)); - setResult(RESULT_OK, resultIntent); - finish(); - } - -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java deleted file mode 100644 index 28f916c864c7..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/FullscreenBlur.java +++ /dev/null @@ -1,192 +0,0 @@ -/*
- * Copyright (C) 2011 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.testapp;
-
-import java.util.ArrayList;
-
-import com.android.scenegraph.*;
-
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.os.AsyncTask;
-import android.renderscript.*;
-import android.renderscript.Allocation.MipmapControl;
-import android.renderscript.Element.Builder;
-import android.renderscript.Font.Style;
-import android.renderscript.Program.TextureType;
-import android.renderscript.ProgramStore.DepthFunc;
-import android.util.Log;
-
-class FullscreenBlur {
-
- static TextureRenderTarget sRenderTargetBlur0Color;
- static TextureRenderTarget sRenderTargetBlur0Depth;
- static TextureRenderTarget sRenderTargetBlur1Color;
- static TextureRenderTarget sRenderTargetBlur1Depth;
- static TextureRenderTarget sRenderTargetBlur2Color;
- static TextureRenderTarget sRenderTargetBlur2Depth;
-
- static FragmentShader mPF_BlurH;
- static FragmentShader mPF_BlurV;
- static FragmentShader mPF_SelectColor;
- static FragmentShader mPF_Texture;
- static VertexShader mPV_Paint;
- static VertexShader mPV_Blur;
-
- static int targetWidth;
- static int targetHeight;
-
- // This is only used when full screen blur is enabled
- // Basically, it's the offscreen render targets
- static void createRenderTargets(RenderScriptGL rs, int w, int h) {
- targetWidth = w/8;
- targetHeight = h/8;
- Type.Builder b = new Type.Builder(rs, Element.RGBA_8888(rs));
- Type renderType = b.setX(targetWidth).setY(targetHeight).create();
- int usage = Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET;
- sRenderTargetBlur0Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
- sRenderTargetBlur1Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
- sRenderTargetBlur2Color = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
-
- b = new Type.Builder(rs, Element.createPixel(rs, Element.DataType.UNSIGNED_16,
- Element.DataKind.PIXEL_DEPTH));
- renderType = b.setX(targetWidth).setY(targetHeight).create();
- usage = Allocation.USAGE_GRAPHICS_RENDER_TARGET;
- sRenderTargetBlur0Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
- sRenderTargetBlur1Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
- sRenderTargetBlur2Depth = new TextureRenderTarget(Allocation.createTyped(rs, renderType, usage));
- }
-
- static void addOffsets(Renderable quad, float advance) {
- quad.appendSourceParams(new Float4Param("blurOffset0", - advance * 2.5f));
- quad.appendSourceParams(new Float4Param("blurOffset1", - advance * 0.5f));
- quad.appendSourceParams(new Float4Param("blurOffset2", advance * 1.5f));
- quad.appendSourceParams(new Float4Param("blurOffset3", advance * 3.5f));
- }
-
- static RenderPass addPass(Scene scene, Camera cam, TextureRenderTarget color, TextureRenderTarget depth) {
- RenderPass pass = new RenderPass();
- pass.setColorTarget(color);
- pass.setDepthTarget(depth);
- pass.setShouldClearColor(false);
- pass.setShouldClearDepth(false);
- pass.setCamera(cam);
- scene.appendRenderPass(pass);
- return pass;
- }
-
- static void addBlurPasses(Scene scene, RenderScriptGL rs, Camera cam) {
- SceneManager sceneManager = SceneManager.getInstance();
- ArrayList<RenderableBase> allDraw = scene.getRenderables();
- int numDraw = allDraw.size();
-
- ProgramRaster cullNone = ProgramRaster.CULL_NONE(rs);
- ProgramStore blendAdd = SceneManager.BLEND_ADD_DEPTH_NONE(rs);
- ProgramStore blendNone = ProgramStore.BLEND_NONE_DEPTH_NONE(rs);
-
- RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture, blendAdd, cullNone);
- RenderState selectCol = new RenderState(mPV_Blur, mPF_SelectColor, blendNone, cullNone);
- RenderState hBlur = new RenderState(mPV_Blur, mPF_BlurH, blendNone, cullNone);
- RenderState vBlur = new RenderState(mPV_Blur, mPF_BlurV, blendNone, cullNone);
-
- // Renders the scene off screen
- RenderPass blurSourcePass = addPass(scene, cam,
- sRenderTargetBlur0Color,
- sRenderTargetBlur0Depth);
- blurSourcePass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f));
- blurSourcePass.setShouldClearColor(true);
- blurSourcePass.setClearDepth(1.0f);
- blurSourcePass.setShouldClearDepth(true);
- for (int i = 0; i < numDraw; i ++) {
- blurSourcePass.appendRenderable((Renderable)allDraw.get(i));
- }
-
- // Pass for selecting bright colors
- RenderPass selectColorPass = addPass(scene, cam,
- sRenderTargetBlur2Color,
- sRenderTargetBlur2Depth);
- Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadS", selectCol);
- quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur0Color));
- selectColorPass.appendRenderable(quad);
-
- // Horizontal blur
- RenderPass horizontalBlurPass = addPass(scene, cam,
- sRenderTargetBlur1Color,
- sRenderTargetBlur1Depth);
- quad = sceneManager.getRenderableQuad("ScreenAlignedQuadH", hBlur);
- quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));
- addOffsets(quad, 1.0f / (float)targetWidth);
- horizontalBlurPass.appendRenderable(quad);
-
- // Vertical Blur
- RenderPass verticalBlurPass = addPass(scene, cam,
- sRenderTargetBlur2Color,
- sRenderTargetBlur2Depth);
- quad = sceneManager.getRenderableQuad("ScreenAlignedQuadV", vBlur);
- quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur1Color));
- addOffsets(quad, 1.0f / (float)targetHeight);
- verticalBlurPass.appendRenderable(quad);
- }
-
- // Additively renders the blurred colors on top of the scene
- static void addCompositePass(Scene scene, RenderScriptGL rs, Camera cam) {
- SceneManager sceneManager = SceneManager.getInstance();
- RenderState drawTex = new RenderState(mPV_Blur, mPF_Texture,
- SceneManager.BLEND_ADD_DEPTH_NONE(rs),
- ProgramRaster.CULL_NONE(rs));
-
- RenderPass compositePass = addPass(scene, cam, null, null);
- Renderable quad = sceneManager.getRenderableQuad("ScreenAlignedQuadComposite", drawTex);
- quad.appendSourceParams(new TextureParam("color", sRenderTargetBlur2Color));
- compositePass.appendRenderable(quad);
- }
-
- static private FragmentShader getShader(Resources res, RenderScriptGL rs,
- int resID, Type constants) {
- FragmentShader.Builder fb = new FragmentShader.Builder(rs);
- fb.setShader(res, resID);
- fb.addTexture(TextureType.TEXTURE_2D, "color");
- if (constants != null) {
- fb.setObjectConst(constants);
- }
- FragmentShader prog = fb.create();
- prog.getProgram().bindSampler(Sampler.CLAMP_LINEAR(rs), 0);
- return prog;
- }
-
- static void initShaders(Resources res, RenderScriptGL rs) {
- ScriptField_BlurOffsets blurConst = new ScriptField_BlurOffsets(rs, 1);
- VertexShader.Builder vb = new VertexShader.Builder(rs);
- vb.addInput(ScriptField_VertexShaderInputs.createElement(rs));
- vb.setShader(res, R.raw.blur_vertex);
- mPV_Blur = vb.create();
-
- mPF_Texture = getShader(res, rs, R.raw.texture, null);
- mPF_Texture.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(rs), 0);
- mPF_BlurH = getShader(res, rs, R.raw.blur_h, blurConst.getAllocation().getType());
- mPF_BlurV = getShader(res, rs, R.raw.blur_v, blurConst.getAllocation().getType());
- mPF_SelectColor = getShader(res, rs, R.raw.select_color, null);
- }
-
-}
-
-
-
-
-
diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleApp.java deleted file mode 100644 index 314db80f2a31..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleApp.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2012 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.testapp; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.os.Bundle; -import android.util.Log; -import android.view.View; -import android.view.Window; -import android.view.Window; -import android.net.Uri; - -import java.lang.Runtime; - -public class SimpleApp extends Activity { - - private SimpleAppView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new SimpleAppView(this); - setContentView(mView); - } -} - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppRS.java deleted file mode 100644 index fff6f3407a92..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppRS.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2012 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.testapp; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Vector; - -import com.android.scenegraph.*; -import com.android.scenegraph.SceneManager.SceneLoadedCallback; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.renderscript.*; -import android.renderscript.Program.TextureType; -import android.util.Log; - -// This is where the scenegraph and the rendered objects are initialized and used -public class SimpleAppRS { - SceneManager mSceneManager; - - RenderScriptGL mRS; - Resources mRes; - - Scene mScene; - Mesh mSimpleMesh; - Mesh mSphereMesh; - Mesh mCubeMesh; - - public void init(RenderScriptGL rs, Resources res, int width, int height) { - mRS = rs; - mRes = res; - mSceneManager = SceneManager.getInstance(); - mSceneManager.initRS(mRS, mRes, width, height); - - mScene = new Scene(); - - setupGeometry(); - setupColoredQuad(); - setupTexturedQuad(); - setupShadedGeometry(); - setupCamera(); - setupRenderPass(); - - mSceneManager.setActiveScene(mScene); - - mScene.initRS(); - mRS.bindRootScript(mSceneManager.getRenderLoop()); - } - - private void setupGeometry() { - Mesh.TriangleMeshBuilder tmb = new Mesh.TriangleMeshBuilder(mRS, 3, - Mesh.TriangleMeshBuilder.TEXTURE_0); - - // Create four vertices with texture coordinates - tmb.setTexture(0.0f, 1.0f).addVertex(-1.0f, 1.0f, 0.0f); - tmb.setTexture(0.0f, 0.0f).addVertex(-1.0f, -1.0f, 0.0f); - tmb.setTexture(1.0f, 0.0f).addVertex(1.0f, -1.0f, 0.0f); - tmb.setTexture(1.0f, 1.0f).addVertex(1.0f, 1.0f, 0.0f); - - tmb.addTriangle(0, 1, 2); - tmb.addTriangle(2, 3, 0); - mSimpleMesh = tmb.create(true); - - // Load a file that constains two pieces of geometry, a sphere and a cube - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.unit_obj); - for (int i = 0; i < model.getIndexEntryCount(); i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getName().equals("CubeMesh")) { - mCubeMesh = entry.getMesh(); - } else if (entry != null && entry.getName().equals("SphereMesh")) { - mSphereMesh = entry.getMesh(); - } - } - } - - private void setupColoredQuad() { - // Built-in shader that provides position, texcoord and normal - VertexShader genericV = SceneManager.getDefaultVS(); - // Built-in shader that displays a color - FragmentShader colorF = SceneManager.getColorFS(); - RenderState colorRS = new RenderState(genericV, colorF, null, null); - - // Draw a simple colored quad - Renderable quad = mScene.appendNewRenderable(); - quad.setMesh(mSimpleMesh); - // Our shader has a constant input called "color" - // This tells the scenegraph to assign the following float3 to that input - quad.appendSourceParams(new Float4Param("color", 0.2f, 0.3f, 0.4f)); - quad.setRenderState(colorRS); - } - - private void setupTexturedQuad() { - // Built-in shader that provides position, texcoord and normal - VertexShader genericV = SceneManager.getDefaultVS(); - // Built-in shader that displays a texture - FragmentShader textureF = SceneManager.getTextureFS(); - // We want to use transparency based on the alpha channel of the texture - ProgramStore alphaBlend = ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS); - RenderState texRS = new RenderState(genericV, textureF, alphaBlend, null); - - // Draw a textured quad - Renderable quad = mScene.appendNewRenderable(); - quad.setMesh(mSimpleMesh); - // Make a transform to position the quad - CompoundTransform t = mScene.appendNewCompoundTransform(); - t.addTranslate("position", new Float3(2, 2, 0)); - quad.setTransform(t); - // Our fragment shader has a constant texture input called "color" - // This will assign an icon from drawables to that input - quad.appendSourceParams(new TextureParam("color", new Texture2D(R.drawable.icon))); - quad.setRenderState(texRS); - } - - private FragmentShader createLambertShader() { - // Describe what constant inputs our shader wants - Element.Builder b = new Element.Builder(mRS); - b.add(Element.F32_4(mRS), "cameraPos"); - - // Create a shader from a text file in resources - FragmentShader.Builder fb = new FragmentShader.Builder(mRS); - // Tell the shader what constants we want - fb.setShaderConst(new Type.Builder(mRS, b.create()).setX(1).create()); - // Shader code location - fb.setShader(mRes, R.raw.diffuse); - // We want a texture called diffuse on our shader - fb.addTexture(TextureType.TEXTURE_2D, "diffuse"); - FragmentShader shader = fb.create(); - mScene.appendShader(shader); - return shader; - } - - private void setupShadedGeometry() { - // Built-in shader that provides position, texcoord and normal - VertexShader genericV = SceneManager.getDefaultVS(); - // Custom shader - FragmentShader diffuseF = createLambertShader(); - RenderState diffuseRS = new RenderState(genericV, diffuseF, null, null); - - // Draw a sphere - Renderable sphere = mScene.appendNewRenderable(); - // Use the sphere geometry loaded earlier - sphere.setMesh(mSphereMesh); - // Make a transform to position the sphere - CompoundTransform t = mScene.appendNewCompoundTransform(); - t.addTranslate("position", new Float3(-1, 2, 3)); - t.addScale("scale", new Float3(1.4f, 1.4f, 1.4f)); - sphere.setTransform(t); - // Tell the renderable which texture to use when we draw - // This will mean a texture param in the shader called "diffuse" - // will be assigned a texture called red.jpg - sphere.appendSourceParams(new TextureParam("diffuse", new Texture2D("", "red.jpg"))); - sphere.setRenderState(diffuseRS); - - // Draw a cube - Renderable cube = mScene.appendNewRenderable(); - cube.setMesh(mCubeMesh); - t = mScene.appendNewCompoundTransform(); - t.addTranslate("position", new Float3(-2, -2.1f, 0)); - t.addRotate("rotateX", new Float3(1, 0, 0), 30); - t.addRotate("rotateY", new Float3(0, 1, 0), 30); - t.addScale("scale", new Float3(2, 2, 2)); - cube.setTransform(t); - cube.appendSourceParams(new TextureParam("diffuse", new Texture2D("", "orange.jpg"))); - cube.setRenderState(diffuseRS); - } - - private void setupCamera() { - Camera camera = mScene.appendNewCamera(); - camera.setFar(200); - camera.setNear(0.1f); - camera.setFOV(60); - CompoundTransform cameraTransform = mScene.appendNewCompoundTransform(); - cameraTransform.addTranslate("camera", new Float3(0, 0, 10)); - camera.setTransform(cameraTransform); - } - - private void setupRenderPass() { - RenderPass mainPass = mScene.appendNewRenderPass(); - mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f)); - mainPass.setShouldClearColor(true); - mainPass.setClearDepth(1.0f); - mainPass.setShouldClearDepth(true); - mainPass.setCamera(mScene.getCameras().get(0)); - ArrayList<RenderableBase> allRender = mScene.getRenderables(); - for (RenderableBase renderable : allRender) { - mainPass.appendRenderable((Renderable)renderable); - } - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppView.java deleted file mode 100644 index 21121815c67d..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/SimpleAppView.java +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (C) 2012 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.testapp; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.content.res.Resources; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; - -public class SimpleAppView extends RSSurfaceView { - - public SimpleAppView(Context context) { - super(context); - } - - private RenderScriptGL mRS; - SimpleAppRS mRender; - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - sc.setSamples(1, 2, 1); - mRS = createRenderScriptGL(sc); - mRS.setSurface(holder, w, h); - mRender = new SimpleAppRS(); - mRender.init(mRS, getResources(), w, h); - } - } - - @Override - protected void onDetachedFromWindow() { - if (mRS != null) { - mRender = null; - mRS = null; - destroyRenderScriptGL(); - } - } -} - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java deleted file mode 100644 index 385a7ab37d11..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestApp.java +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (C) 2011 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.testapp; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; - -import android.app.Activity; -import android.content.res.Configuration; -import android.content.Intent; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.provider.Settings.System; -import android.util.Log; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.Window; -import android.widget.Button; -import android.widget.ListView; -import android.view.MenuInflater; -import android.view.Window; -import android.net.Uri; - -import java.lang.Runtime; - -public class TestApp extends Activity { - - private TestAppView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - // Create our Preview view and set it as the content of our - // Activity - mView = new TestAppView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - // Ideally a game should implement onResume() and onPause() - // to take appropriate action when the activity looses focus - super.onPause(); - mView.pause(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - MenuInflater inflater = getMenuInflater(); - inflater.inflate(R.menu.loader_menu, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle item selection - switch (item.getItemId()) { - case R.id.load_model: - loadModel(); - return true; - case R.id.use_blur: - mView.mRender.toggleBlur(); - return true; - default: - return super.onOptionsItemSelected(item); - } - } - - private static final int FIND_DAE_MODEL = 10; - public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (resultCode == RESULT_OK) { - if (requestCode == FIND_DAE_MODEL) { - Uri selectedImageUri = data.getData(); - Log.e("Selected Path: ", selectedImageUri.getPath()); - mView.mRender.loadModel(selectedImageUri.getPath()); - } - } - } - - public void loadModel() { - Intent intent = new Intent(); - intent.setAction(Intent.ACTION_PICK); - intent.setClassName("com.android.testapp", - "com.android.testapp.FileSelector"); - startActivityForResult(intent, FIND_DAE_MODEL); - } - -} - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java deleted file mode 100644 index 5bd8f0bccf16..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppLoadingScreen.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (C) 2012 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.testapp; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Vector; - -import com.android.scenegraph.SceneManager; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.renderscript.*; -import android.renderscript.Allocation.MipmapControl; -import android.renderscript.Element.Builder; -import android.renderscript.Font.Style; -import android.renderscript.Program.TextureType; -import android.renderscript.ProgramStore.DepthFunc; -import android.util.Log; - -// This is where the scenegraph and the rendered objects are initialized and used -public class TestAppLoadingScreen { - - private static String TAG = "TestAppLoadingScreen"; - - private Resources mRes; - private RenderScriptGL mRS; - private ScriptC_test_app mScript; - - public TestAppLoadingScreen(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - // Shows the loading screen with some text - renderLoading(); - // Adds a little 3D bugdroid model to the laoding screen asynchronously. - new LoadingScreenLoaderTask().execute(); - } - - public void showLoadingScreen(boolean show) { - if (show) { - mRS.bindRootScript(mScript); - } else { - mRS.bindRootScript(SceneManager.getInstance().getRenderLoop()); - } - } - - // The loading screen has some elements that shouldn't be loaded on the UI thread - private class LoadingScreenLoaderTask extends AsyncTask<String, Void, Boolean> { - Allocation robotTex; - Mesh robotMesh; - protected Boolean doInBackground(String... names) { - long start = System.currentTimeMillis(); - robotTex = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, - MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); - FileA3D.IndexEntry entry = model.getIndexEntry(0); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - robotMesh = entry.getMesh(); - } - - mScript.set_gPFSBackground(ProgramStore.BLEND_NONE_DEPTH_TEST(mRS)); - - ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); - b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - ProgramFragment pfDefault = b.create(); - pfDefault.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); - mScript.set_gPFBackground(pfDefault); - - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - ProgramVertexFixedFunction pvDefault = pvb.create(); - ProgramVertexFixedFunction.Constants va = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction)pvDefault).bindConstants(va); - mScript.set_gPVBackground(pvDefault); - - long end = System.currentTimeMillis(); - Log.v("TIMER", "Loading load time: " + (end - start)); - return new Boolean(true); - } - - protected void onPostExecute(Boolean result) { - mScript.set_gRobotTex(robotTex); - mScript.set_gRobotMesh(robotMesh); - } - } - - // Creates a simple script to show a loding screen until everything is initialized - // Could also be used to do some custom renderscript work before handing things over - // to the scenegraph - void renderLoading() { - mScript = new ScriptC_test_app(mRS, mRes, R.raw.test_app); - mRS.bindRootScript(mScript); - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java deleted file mode 100644 index 3aa80f4cad19..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppRS.java +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (C) 2011-2012 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.testapp; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; -import java.util.Vector; - -import com.android.scenegraph.*; -import com.android.scenegraph.SceneManager.SceneLoadedCallback; - -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.os.AsyncTask; -import android.renderscript.*; -import android.renderscript.Program.TextureType; -import android.util.Log; - -// This is where the scenegraph and the rendered objects are initialized and used -public class TestAppRS { - - private static String modelName = "orientation_test.dae"; - private static String TAG = "TestAppRS"; - private static String mFilePath = ""; - - int mWidth; - int mHeight; - - boolean mUseBlur; - - TestAppLoadingScreen mLoadingScreen; - - // Used to asynchronously load scene elements like meshes and transform hierarchies - SceneLoadedCallback mLoadedCallback = new SceneLoadedCallback() { - public void run() { - prepareToRender(mLoadedScene); - } - }; - - // Top level class that initializes all the elements needed to use the scene graph - SceneManager mSceneManager; - - // Used to move the camera around in the 3D world - TouchHandler mTouchHandler; - - private Resources mRes; - private RenderScriptGL mRS; - - // Shaders - private FragmentShader mPaintF; - private FragmentShader mLightsF; - private FragmentShader mLightsDiffF; - private FragmentShader mAluminumF; - private FragmentShader mPlasticF; - private FragmentShader mDiffuseF; - private FragmentShader mTextureF; - private VertexShader mGenericV; - - Scene mActiveScene; - - // This is a part of the test app, it's used to tests multiple render passes and is toggled - // on and off in the menu, off by default - void toggleBlur() { - mUseBlur = !mUseBlur; - - mActiveScene.clearRenderPasses(); - initRenderPasses(); - mActiveScene.initRenderPassRS(mRS, mSceneManager); - - // This is just a hardcoded object in the scene that gets turned on and off for the demo - // to make things look a bit better. This could be deleted in the cleanup - Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1"); - if (plane != null) { - plane.setVisible(!mUseBlur); - } - } - - public void init(RenderScriptGL rs, Resources res, int width, int height) { - mUseBlur = false; - mRS = rs; - mRes = res; - mWidth = width; - mHeight = height; - - mTouchHandler = new TouchHandler(); - - mSceneManager = SceneManager.getInstance(); - // Initializes all the RS specific scenegraph elements - mSceneManager.initRS(mRS, mRes, mWidth, mHeight); - - mLoadingScreen = new TestAppLoadingScreen(mRS, mRes); - - // Initi renderscript stuff specific to the app. This will need to be abstracted out later. - FullscreenBlur.createRenderTargets(mRS, mWidth, mHeight); - initPaintShaders(); - - // Load a scene to render - mSceneManager.loadModel(mFilePath + modelName, mLoadedCallback); - } - - // When a new model file is selected from the UI, this function gets called to init everything - void loadModel(String path) { - mLoadingScreen.showLoadingScreen(true); - mActiveScene.destroyRS(); - mSceneManager.loadModel(path, mLoadedCallback); - } - - public void onActionDown(float x, float y) { - mTouchHandler.onActionDown(x, y); - } - - public void onActionScale(float scale) { - mTouchHandler.onActionScale(scale); - } - - public void onActionMove(float x, float y) { - mTouchHandler.onActionMove(x, y); - } - - FragmentShader createFromResource(int id, boolean addCubemap, Type constType) { - FragmentShader.Builder fb = new FragmentShader.Builder(mRS); - fb.setShaderConst(constType); - fb.setShader(mRes, id); - fb.addTexture(TextureType.TEXTURE_2D, "diffuse"); - if (addCubemap) { - fb.addShaderTexture(TextureType.TEXTURE_CUBE, "reflection"); - } - FragmentShader pf = fb.create(); - pf.getProgram().bindSampler(Sampler.WRAP_LINEAR_MIP_LINEAR(mRS), 0); - if (addCubemap) { - pf.getProgram().bindSampler(Sampler.CLAMP_LINEAR_MIP_LINEAR(mRS), 1); - } - return pf; - } - - private void initPaintShaders() { - mGenericV = SceneManager.getDefaultVS(); - - ScriptField_CameraParams camParams = new ScriptField_CameraParams(mRS, 1); - Type camParamType = camParams.getAllocation().getType(); - ScriptField_LightParams lightParams = new ScriptField_LightParams(mRS, 1); - - mPaintF = createFromResource(R.raw.paintf, true, camParamType); - // Assign a reflection map - TextureCube envCube = new TextureCube("sdcard/scenegraph/", "cube_env.png"); - mPaintF.appendSourceParams(new TextureParam("reflection", envCube)); - - mAluminumF = createFromResource(R.raw.metal, true, camParamType); - TextureCube diffCube = new TextureCube("sdcard/scenegraph/", "cube_spec.png"); - mAluminumF.appendSourceParams(new TextureParam("reflection", diffCube)); - - mPlasticF = createFromResource(R.raw.plastic, false, camParamType); - mDiffuseF = createFromResource(R.raw.diffuse, false, camParamType); - mTextureF = SceneManager.getTextureFS(); - - FragmentShader.Builder fb = new FragmentShader.Builder(mRS); - fb.setObjectConst(lightParams.getAllocation().getType()); - fb.setShader(mRes, R.raw.plastic_lights); - mLightsF = fb.create(); - - fb = new FragmentShader.Builder(mRS); - fb.setObjectConst(lightParams.getAllocation().getType()); - fb.setShader(mRes, R.raw.diffuse_lights); - mLightsDiffF = fb.create(); - - FullscreenBlur.initShaders(mRes, mRS); - } - - void initRenderPasses() { - ArrayList<RenderableBase> allDraw = mActiveScene.getRenderables(); - int numDraw = allDraw.size(); - - if (mUseBlur) { - FullscreenBlur.addBlurPasses(mActiveScene, mRS, mTouchHandler.getCamera()); - } - - RenderPass mainPass = new RenderPass(); - mainPass.setClearColor(new Float4(1.0f, 1.0f, 1.0f, 1.0f)); - mainPass.setShouldClearColor(true); - mainPass.setClearDepth(1.0f); - mainPass.setShouldClearDepth(true); - mainPass.setCamera(mTouchHandler.getCamera()); - for (int i = 0; i < numDraw; i ++) { - mainPass.appendRenderable((Renderable)allDraw.get(i)); - } - mActiveScene.appendRenderPass(mainPass); - - if (mUseBlur) { - FullscreenBlur.addCompositePass(mActiveScene, mRS, mTouchHandler.getCamera()); - } - } - - private void addShadersToScene() { - mActiveScene.appendShader(mPaintF); - mActiveScene.appendShader(mLightsF); - mActiveScene.appendShader(mLightsDiffF); - mActiveScene.appendShader(mAluminumF); - mActiveScene.appendShader(mPlasticF); - mActiveScene.appendShader(mDiffuseF); - mActiveScene.appendShader(mTextureF); - } - - public void prepareToRender(Scene s) { - mSceneManager.setActiveScene(s); - mActiveScene = s; - mTouchHandler.init(mActiveScene); - addShadersToScene(); - RenderState plastic = new RenderState(mGenericV, mPlasticF, null, null); - RenderState diffuse = new RenderState(mGenericV, mDiffuseF, null, null); - RenderState paint = new RenderState(mGenericV, mPaintF, null, null); - RenderState aluminum = new RenderState(mGenericV, mAluminumF, null, null); - RenderState lights = new RenderState(mGenericV, mLightsF, null, null); - RenderState diff_lights = new RenderState(mGenericV, mLightsDiffF, null, null); - RenderState diff_lights_no_cull = new RenderState(mGenericV, mLightsDiffF, null, - ProgramRaster.CULL_NONE(mRS)); - RenderState glassTransp = new RenderState(mGenericV, mPaintF, - ProgramStore.BLEND_ALPHA_DEPTH_TEST(mRS), null); - RenderState texState = new RenderState(mGenericV, mTextureF, null, null); - - initRenderPasses(); - - mActiveScene.assignRenderState(plastic); - - mActiveScene.assignRenderStateToMaterial(diffuse, "lambert2$"); - - mActiveScene.assignRenderStateToMaterial(paint, "^Paint"); - mActiveScene.assignRenderStateToMaterial(paint, "^Carbon"); - mActiveScene.assignRenderStateToMaterial(paint, "^Glass"); - mActiveScene.assignRenderStateToMaterial(paint, "^MainGlass"); - - mActiveScene.assignRenderStateToMaterial(aluminum, "^Metal"); - mActiveScene.assignRenderStateToMaterial(aluminum, "^Brake"); - - mActiveScene.assignRenderStateToMaterial(glassTransp, "^GlassLight"); - - mActiveScene.assignRenderStateToMaterial(lights, "^LightBlinn"); - mActiveScene.assignRenderStateToMaterial(diff_lights, "^LightLambert"); - mActiveScene.assignRenderStateToMaterial(diff_lights_no_cull, "^LightLambertNoCull"); - mActiveScene.assignRenderStateToMaterial(texState, "^TextureOnly"); - - Renderable plane = (Renderable)mActiveScene.getRenderableByName("pPlaneShape1"); - if (plane != null) { - plane.setRenderState(texState); - plane.setVisible(!mUseBlur); - } - - long start = System.currentTimeMillis(); - mActiveScene.initRS(); - long end = System.currentTimeMillis(); - Log.v("TIMER", "Scene init time: " + (end - start)); - - mLoadingScreen.showLoadingScreen(false); - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java deleted file mode 100644 index 33ca1b85a70b..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TestAppView.java +++ /dev/null @@ -1,153 +0,0 @@ -/* - * Copyright (C) 2011 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.testapp; - -import java.io.Writer; -import java.util.ArrayList; -import java.util.concurrent.Semaphore; - -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScript; -import android.renderscript.RenderScriptGL; - -import android.content.Context; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.os.Handler; -import android.os.Message; -import android.util.AttributeSet; -import android.util.Log; -import android.view.Surface; -import android.view.SurfaceHolder; -import android.view.SurfaceView; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.ScaleGestureDetector; - -public class TestAppView extends RSSurfaceView { - - public TestAppView(Context context) { - super(context); - mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); - } - - private RenderScriptGL mRS; - TestAppRS mRender; - - private ScaleGestureDetector mScaleDetector; - private static final int INVALID_POINTER_ID = -1; - private int mActivePointerId = INVALID_POINTER_ID; - - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - sc.setSamples(1, 2, 1); - mRS = createRenderScriptGL(sc); - mRS.setSurface(holder, w, h); - mRender = new TestAppRS(); - mRender.init(mRS, getResources(), w, h); - } - } - - @Override - protected void onDetachedFromWindow() { - if (mRS != null) { - mRender = null; - mRS = null; - destroyRenderScriptGL(); - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) - { - // break point at here - // this method doesn't work when 'extends View' include 'extends ScrollView'. - return super.onKeyDown(keyCode, event); - } - - - @Override - public boolean onTouchEvent(MotionEvent ev) { - mScaleDetector.onTouchEvent(ev); - - boolean ret = false; - float x = ev.getX(); - float y = ev.getY(); - - final int action = ev.getAction(); - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(0); - ret = true; - break; - } - case MotionEvent.ACTION_MOVE: { - if (!mScaleDetector.isInProgress()) { - mRender.onActionMove(x, y); - } - mRender.onActionDown(x, y); - ret = true; - break; - } - - case MotionEvent.ACTION_UP: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_CANCEL: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_POINTER_UP: { - final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - final int pointerId = ev.getPointerId(pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - x = ev.getX(newPointerIndex); - y = ev.getY(newPointerIndex); - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(newPointerIndex); - } - break; - } - } - - return ret; - } - - private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - @Override - public boolean onScale(ScaleGestureDetector detector) { - mRender.onActionScale(detector.getScaleFactor()); - return true; - } - } -} - - diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java deleted file mode 100644 index d0f979734c9e..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/TouchHandler.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2011 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.testapp; - -import android.util.Log; -import android.renderscript.Float3; -import com.android.scenegraph.*; -import com.android.scenegraph.CompoundTransform.RotateComponent; -import com.android.scenegraph.CompoundTransform.TranslateComponent; - -public class TouchHandler { - private static String TAG = "TouchHandler"; - - float mLastX; - float mLastY; - - float mRotateXValue; - float mRotateYValue; - Float3 mDistValue; - Float3 mPosValue; - - CompoundTransform mCameraRig; - RotateComponent mRotateX; - RotateComponent mRotateY; - TranslateComponent mDist; - TranslateComponent mPosition; - Camera mCamera; - - public void init(Scene scene) { - // Some initial values for camera position - mRotateXValue = -20; - mRotateYValue = 0; - mDistValue = new Float3(0, 0, 45); - mPosValue = new Float3(0, 4, 0); - - // Make a camera transform we can manipulate - mCameraRig = scene.appendNewCompoundTransform(); - mCameraRig.setName("CameraRig"); - - mPosition = mCameraRig.addTranslate("Position", mPosValue); - mRotateY = mCameraRig.addRotate("RotateY", new Float3(0, 1, 0), mRotateYValue); - mRotateX = mCameraRig.addRotate("RotateX", new Float3(1, 0, 0), mRotateXValue); - mDist = mCameraRig.addTranslate("Distance", mDistValue); - - mCamera = scene.appendNewCamera(); - mCamera.setTransform(mCameraRig); - } - - public Camera getCamera() { - return mCamera; - } - - public void onActionDown(float x, float y) { - mLastX = x; - mLastY = y; - } - - public void onActionScale(float scale) { - if (mDist == null) { - return; - } - mDistValue.z *= 1.0f / scale; - mDistValue.z = Math.max(10.0f, Math.min(mDistValue.z, 150.0f)); - mDist.setValue(mDistValue); - } - - public void onActionMove(float x, float y) { - if (mRotateX == null) { - return; - } - - float dx = mLastX - x; - float dy = mLastY - y; - - if (Math.abs(dy) <= 2.0f) { - dy = 0.0f; - } - if (Math.abs(dx) <= 2.0f) { - dx = 0.0f; - } - - mRotateYValue += dx * 0.25f; - mRotateYValue %= 360.0f; - - mRotateXValue += dy * 0.25f; - mRotateXValue = Math.max(mRotateXValue , -80.0f); - mRotateXValue = Math.min(mRotateXValue , 0.0f); - - mRotateX.setAngle(mRotateXValue); - mRotateY.setAngle(mRotateYValue); - - mLastX = x; - mLastY = y; - } -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs deleted file mode 100644 index d94da52cca64..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rs +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.testapp) - -#include "rs_graphics.rsh" -#include "test_app.rsh" - -// Making sure these get reflected -FBlurOffsets *blurExport; -VShaderInputs *iExport; -FShaderParams *fConst; -FShaderLightParams *fConts2; -VSParams *vConst2; -VObjectParams *vConst3; - -rs_program_vertex gPVBackground; -rs_program_fragment gPFBackground; - -rs_allocation gRobotTex; -rs_mesh gRobotMesh; - -rs_program_store gPFSBackground; - -float gRotate; - -void init() { - gRotate = 0.0f; -} - -static float gRotateY = 120.0f; -static float gZoom = 50.0f; -static void displayLoading() { - if (rsIsObject(gRobotTex) && rsIsObject(gRobotMesh)) { - rsgBindProgramVertex(gPVBackground); - rs_matrix4x4 proj; - float aspect = (float)rsgGetWidth() / (float)rsgGetHeight(); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 100.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rsgBindProgramFragment(gPFBackground); - rsgBindProgramStore(gPFSBackground); - rsgBindTexture(gPFBackground, 0, gRobotTex); - - rs_matrix4x4 matrix; - rsMatrixLoadIdentity(&matrix); - // Position our models on the screen - gRotateY += rsGetDt()*100; - rsMatrixTranslate(&matrix, 0, 0, -gZoom); - rsMatrixRotate(&matrix, 20.0f, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - rsMatrixScale(&matrix, 0.2f, 0.2f, 0.2f); - rsgProgramVertexLoadModelMatrix(&matrix); - rsgDrawMesh(gRobotMesh); - } - - uint width = rsgGetWidth(); - uint height = rsgGetHeight(); - int left = 0, right = 0, top = 0, bottom = 0; - const char* text = "Initializing..."; - rsgMeasureText(text, &left, &right, &top, &bottom); - int centeredPos = width / 2 - (right - left) / 2; - rsgDrawText(text, centeredPos, height / 2 + height / 10); -} - -int root(void) { - rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgClearDepth(1.0f); - displayLoading(); - return 30; -} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh b/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh deleted file mode 100644 index 5fbcbb2ebb69..000000000000 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/testapp/test_app.rsh +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright (C) 2012 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 version(1) - -#pragma rs java_package_name(com.android.testapp) - -// Helpers -typedef struct ViewProjParams { - rs_matrix4x4 viewProj; -} VSParams; - -typedef struct ModelParams { - rs_matrix4x4 model; -} VObjectParams; - -typedef struct CameraParams { - float4 cameraPos; -} FShaderParams; - -typedef struct LightParams { - float4 lightPos_0; - float4 lightColor_0; - float4 lightPos_1; - float4 lightColor_1; - float4 cameraPos; - float4 diffuse; -} FShaderLightParams; - -typedef struct BlurOffsets { - float blurOffset0; - float blurOffset1; - float blurOffset2; - float blurOffset3; -} FBlurOffsets; - -typedef struct VertexShaderInputs { - float4 position; - float3 normal; - float2 texture0; -} VShaderInputs; diff --git a/tests/RenderScriptTests/ShadersTest/Android.mk b/tests/RenderScriptTests/ShadersTest/Android.mk deleted file mode 100644 index fb6356e4d81a..000000000000 --- a/tests/RenderScriptTests/ShadersTest/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2011 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_TAGS := tests - -LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src) - -LOCAL_SDK_VERSION := 17 - -LOCAL_PACKAGE_NAME := ShadersTest - -include $(BUILD_PACKAGE) diff --git a/tests/RenderScriptTests/ShadersTest/AndroidManifest.xml b/tests/RenderScriptTests/ShadersTest/AndroidManifest.xml deleted file mode 100644 index 871200da6ad6..000000000000 --- a/tests/RenderScriptTests/ShadersTest/AndroidManifest.xml +++ /dev/null @@ -1,32 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2011 The Android Open Source Project - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. ---> - -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="com.android.shaderstest"> - - <uses-permission android:name="android.permission.INTERNET" /> - - <application android:label="_ShadersTest"> - <activity android:name="ShadersTest" - android:label="_ShadersTest" - android:theme="@android:style/Theme.Black.NoTitleBar"> - <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> - </intent-filter> - </activity> - </application> -</manifest> diff --git a/tests/RenderScriptTests/ShadersTest/res/drawable-nodpi/robot.png b/tests/RenderScriptTests/ShadersTest/res/drawable-nodpi/robot.png Binary files differdeleted file mode 100644 index f7353fd61c5b..000000000000 --- a/tests/RenderScriptTests/ShadersTest/res/drawable-nodpi/robot.png +++ /dev/null diff --git a/tests/RenderScriptTests/ShadersTest/res/raw/depth_fs.glsl b/tests/RenderScriptTests/ShadersTest/res/raw/depth_fs.glsl deleted file mode 100644 index 096843b1bb44..000000000000 --- a/tests/RenderScriptTests/ShadersTest/res/raw/depth_fs.glsl +++ /dev/null @@ -1,13 +0,0 @@ -void main() { - // Non-linear depth value - float z = gl_FragCoord.z; - // Near and far planes from the projection - // In practice, these values can be used to tweak - // the focus range - float n = UNI_near; - float f = UNI_far; - // Linear depth value - z = (2.0 * n) / (f + n - z * (f - n)); - - gl_FragColor = vec4(z, z, z, 1.0); -} diff --git a/tests/RenderScriptTests/ShadersTest/res/raw/robot.a3d b/tests/RenderScriptTests/ShadersTest/res/raw/robot.a3d Binary files differdeleted file mode 100644 index f48895cd8451..000000000000 --- a/tests/RenderScriptTests/ShadersTest/res/raw/robot.a3d +++ /dev/null diff --git a/tests/RenderScriptTests/ShadersTest/res/raw/vignette_fs.glsl b/tests/RenderScriptTests/ShadersTest/res/raw/vignette_fs.glsl deleted file mode 100644 index 2dc1ea31b9d6..000000000000 --- a/tests/RenderScriptTests/ShadersTest/res/raw/vignette_fs.glsl +++ /dev/null @@ -1,31 +0,0 @@ -#define CRT_MASK - -varying vec2 varTex0; - -void main() { - lowp vec4 color = texture2D(UNI_Tex0, varTex0); - - vec2 powers = pow(abs((gl_FragCoord.xy / vec2(UNI_width, UNI_height)) - 0.5), vec2(2.0)); - float gradient = smoothstep(UNI_size - UNI_feather, UNI_size + UNI_feather, - powers.x + powers.y); - - color = vec4(mix(color.rgb, vec3(0.0), gradient), 1.0); - -#ifdef CRT_MASK - float vShift = gl_FragCoord.y; - if (mod(gl_FragCoord.x, 6.0) >= 3.0) { - vShift += 2.0; - } - - lowp vec3 r = vec3(0.95, 0.0, 0.2); - lowp vec3 g = vec3(0.2, 0.95, 0.0); - lowp vec3 b = vec3(0.0, 0.2, 0.95); - int channel = int(floor(mod(gl_FragCoord.x, 3.0))); - lowp vec4 crt = vec4(r[channel], g[channel], b[channel], 1.0); - crt *= clamp(floor(mod(vShift, 4.0)), 0.0, 1.0); - - color = (crt * color * 1.25) + 0.05; -#endif - - gl_FragColor = color; -} diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTest.java b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTest.java deleted file mode 100644 index 6803fbbf4016..000000000000 --- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTest.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2011 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.shaderstest; - -import android.app.Activity; -import android.os.Bundle; - -@SuppressWarnings({"UnusedDeclaration"}) -public class ShadersTest extends Activity { - - private ShadersTestView mView; - - @Override - public void onCreate(Bundle icicle) { - super.onCreate(icicle); - - mView = new ShadersTestView(this); - setContentView(mView); - } - - @Override - protected void onResume() { - super.onResume(); - mView.resume(); - } - - @Override - protected void onPause() { - super.onPause(); - mView.pause(); - } -} diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestRS.java b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestRS.java deleted file mode 100644 index dad97e20417d..000000000000 --- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestRS.java +++ /dev/null @@ -1,202 +0,0 @@ -/* - * Copyright (C) 2011 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.shaderstest; - -import android.content.res.Resources; -import android.renderscript.Allocation; -import android.renderscript.Element; -import android.renderscript.Element.DataKind; -import android.renderscript.Element.DataType; -import android.renderscript.FileA3D; -import android.renderscript.Mesh; -import android.renderscript.Program; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramFragmentFixedFunction; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramStore.DepthFunc; -import android.renderscript.ProgramVertex; -import android.renderscript.ProgramVertexFixedFunction; -import android.renderscript.RSRuntimeException; -import android.renderscript.RenderScriptGL; -import android.renderscript.Sampler; -import android.renderscript.Type.Builder; - -@SuppressWarnings({"FieldCanBeLocal"}) -public class ShadersTestRS { - public ShadersTestRS() { - } - - public void init(RenderScriptGL rs, Resources res) { - mRS = rs; - mRes = res; - initRS(); - } - - public void surfaceChanged() { - initBuffers(mRS.getWidth(), mRS.getHeight()); - } - - private Resources mRes; - private RenderScriptGL mRS; - private Sampler mLinearClamp; - private Sampler mNearestClamp; - private ProgramStore mPSBackground; - private ProgramFragment mPFBackground; - private ProgramVertex mPVBackground; - private ProgramVertexFixedFunction.Constants mPVA; - - private ProgramFragment mPFVignette; - private ScriptField_VignetteConstants_s mFSVignetteConst; - - private Allocation mMeshTexture; - private Allocation mScreen; - private Allocation mScreenDepth; - - private ScriptField_MeshInfo mMeshes; - private ScriptC_shaderstest mScript; - - - public void onActionDown(float x, float y) { - mScript.invoke_onActionDown(x, y); - } - - public void onActionScale(float scale) { - mScript.invoke_onActionScale(scale); - } - - public void onActionMove(float x, float y) { - mScript.invoke_onActionMove(x, y); - } - - private void initPFS() { - ProgramStore.Builder b = new ProgramStore.Builder(mRS); - - b.setDepthFunc(DepthFunc.LESS); - b.setDitherEnabled(false); - b.setDepthMaskEnabled(true); - mPSBackground = b.create(); - - mScript.set_gPFSBackground(mPSBackground); - } - - private void initPF() { - mLinearClamp = Sampler.CLAMP_LINEAR(mRS); - mScript.set_gLinear(mLinearClamp); - - mNearestClamp = Sampler.CLAMP_NEAREST(mRS); - mScript.set_gNearest(mNearestClamp); - - ProgramFragmentFixedFunction.Builder b = new ProgramFragmentFixedFunction.Builder(mRS); - b.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE, - ProgramFragmentFixedFunction.Builder.Format.RGBA, 0); - mPFBackground = b.create(); - mPFBackground.bindSampler(mLinearClamp, 0); - mScript.set_gPFBackground(mPFBackground); - - mFSVignetteConst = new ScriptField_VignetteConstants_s(mRS, 1); - mScript.bind_gFSVignetteConstants(mFSVignetteConst); - - ProgramFragment.Builder fs; - - fs = new ProgramFragment.Builder(mRS); - fs.setShader(mRes, R.raw.vignette_fs); - fs.addConstant(mFSVignetteConst.getAllocation().getType()); - fs.addTexture(Program.TextureType.TEXTURE_2D); - mPFVignette = fs.create(); - mPFVignette.bindConstants(mFSVignetteConst.getAllocation(), 0); - mScript.set_gPFVignette(mPFVignette); - } - - private void initPV() { - ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); - mPVBackground = pvb.create(); - - mPVA = new ProgramVertexFixedFunction.Constants(mRS); - ((ProgramVertexFixedFunction) mPVBackground).bindConstants(mPVA); - - mScript.set_gPVBackground(mPVBackground); - } - - private void loadImage() { - mMeshTexture = Allocation.createFromBitmapResource(mRS, mRes, R.drawable.robot, - Allocation.MipmapControl.MIPMAP_ON_SYNC_TO_TEXTURE, - Allocation.USAGE_GRAPHICS_TEXTURE); - mScript.set_gTMesh(mMeshTexture); - } - - private void initMeshes(FileA3D model) { - int numEntries = model.getIndexEntryCount(); - int numMeshes = 0; - for (int i = 0; i < numEntries; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - numMeshes ++; - } - } - - if (numMeshes > 0) { - mMeshes = new ScriptField_MeshInfo(mRS, numMeshes); - - for (int i = 0; i < numEntries; i ++) { - FileA3D.IndexEntry entry = model.getIndexEntry(i); - if (entry != null && entry.getEntryType() == FileA3D.EntryType.MESH) { - Mesh mesh = entry.getMesh(); - mMeshes.set_mMesh(i, mesh, false); - mMeshes.set_mNumIndexSets(i, mesh.getPrimitiveCount(), false); - } - } - mMeshes.copyAll(); - } else { - throw new RSRuntimeException("No valid meshes in file"); - } - - mScript.bind_gMeshes(mMeshes); - mScript.invoke_updateMeshInfo(); - } - - private void initRS() { - mScript = new ScriptC_shaderstest(mRS, mRes, R.raw.shaderstest); - - initPFS(); - initPF(); - initPV(); - - loadImage(); - - initBuffers(1, 1); - - FileA3D model = FileA3D.createFromResource(mRS, mRes, R.raw.robot); - initMeshes(model); - - mRS.bindRootScript(mScript); - } - - private void initBuffers(int width, int height) { - Builder b; - b = new Builder(mRS, Element.RGBA_8888(mRS)); - b.setX(width).setY(height); - mScreen = Allocation.createTyped(mRS, b.create(), - Allocation.USAGE_GRAPHICS_TEXTURE | Allocation.USAGE_GRAPHICS_RENDER_TARGET); - mScript.set_gScreen(mScreen); - - b = new Builder(mRS, Element.createPixel(mRS, DataType.UNSIGNED_16, DataKind.PIXEL_DEPTH)); - b.setX(width).setY(height); - mScreenDepth = Allocation.createTyped(mRS, b.create(), - Allocation.USAGE_GRAPHICS_RENDER_TARGET); - mScript.set_gScreenDepth(mScreenDepth); - } -} diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestView.java b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestView.java deleted file mode 100644 index e0a540fb8c87..000000000000 --- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/ShadersTestView.java +++ /dev/null @@ -1,138 +0,0 @@ -/* - * Copyright (C) 2011 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.shaderstest; - -import android.content.Context; -import android.renderscript.RSSurfaceView; -import android.renderscript.RenderScriptGL; -import android.view.MotionEvent; -import android.view.ScaleGestureDetector; -import android.view.SurfaceHolder; - -public class ShadersTestView extends RSSurfaceView { - - private RenderScriptGL mRS; - private ShadersTestRS mRender; - - private ScaleGestureDetector mScaleDetector; - - private static final int INVALID_POINTER_ID = -1; - private int mActivePointerId = INVALID_POINTER_ID; - - public ShadersTestView(Context context) { - super(context); - ensureRenderScript(); - mScaleDetector = new ScaleGestureDetector(context, new ScaleListener()); - } - - private void ensureRenderScript() { - if (mRS == null) { - RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig(); - sc.setDepth(16, 24); - mRS = createRenderScriptGL(sc); - mRender = new ShadersTestRS(); - mRender.init(mRS, getResources()); - } - } - - @Override - protected void onAttachedToWindow() { - super.onAttachedToWindow(); - ensureRenderScript(); - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - super.surfaceChanged(holder, format, w, h); - mRender.surfaceChanged(); - } - - @Override - protected void onDetachedFromWindow() { - mRender = null; - if (mRS != null) { - mRS = null; - destroyRenderScriptGL(); - } - } - - @Override - public boolean onTouchEvent(MotionEvent ev) { - mScaleDetector.onTouchEvent(ev); - - boolean ret = false; - float x = ev.getX(); - float y = ev.getY(); - - final int action = ev.getAction(); - - switch (action & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: { - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(0); - ret = true; - break; - } - case MotionEvent.ACTION_MOVE: { - if (!mScaleDetector.isInProgress()) { - mRender.onActionMove(x, y); - } - mRender.onActionDown(x, y); - ret = true; - break; - } - - case MotionEvent.ACTION_UP: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_CANCEL: { - mActivePointerId = INVALID_POINTER_ID; - break; - } - - case MotionEvent.ACTION_POINTER_UP: { - final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) - >> MotionEvent.ACTION_POINTER_INDEX_SHIFT; - final int pointerId = ev.getPointerId(pointerIndex); - if (pointerId == mActivePointerId) { - // This was our active pointer going up. Choose a new - // active pointer and adjust accordingly. - final int newPointerIndex = pointerIndex == 0 ? 1 : 0; - x = ev.getX(newPointerIndex); - y = ev.getY(newPointerIndex); - mRender.onActionDown(x, y); - mActivePointerId = ev.getPointerId(newPointerIndex); - } - break; - } - } - - return ret; - } - - private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - @Override - public boolean onScale(ScaleGestureDetector detector) { - mRender.onActionScale(detector.getScaleFactor()); - return true; - } - } -} - - diff --git a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs b/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs deleted file mode 100644 index 735f6b911884..000000000000 --- a/tests/RenderScriptTests/ShadersTest/src/com/android/shaderstest/shaderstest.rs +++ /dev/null @@ -1,200 +0,0 @@ -// Copyright (C) 2011 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 version(1) - -#pragma rs java_package_name(com.android.shaderstest) - -#include "rs_graphics.rsh" - -rs_program_vertex gPVBackground; -rs_program_fragment gPFBackground; - -typedef struct VignetteConstants_s { - float size; - float feather; - float width; - float height; -} VignetteConstants; -VignetteConstants *gFSVignetteConstants; -rs_program_fragment gPFVignette; - -rs_allocation gTMesh; - -rs_sampler gLinear; -rs_sampler gNearest; - -rs_program_store gPFSBackground; - -rs_allocation gScreenDepth; -rs_allocation gScreen; - -typedef struct MeshInfo { - rs_mesh mMesh; - int mNumIndexSets; - float3 bBoxMin; - float3 bBoxMax; -} MeshInfo_t; -MeshInfo_t *gMeshes; - -static float3 gLookAt; - -static float gRotateX; -static float gRotateY; -static float gZoom; - -static float gLastX; -static float gLastY; - -static float3 toFloat3(float x, float y, float z) { - float3 f; - f.x = x; - f.y = y; - f.z = z; - return f; -} - -void onActionDown(float x, float y) { - gLastX = x; - gLastY = y; -} - -void onActionScale(float scale) { - - gZoom *= 1.0f / scale; - gZoom = max(0.1f, min(gZoom, 500.0f)); -} - -void onActionMove(float x, float y) { - float dx = gLastX - x; - float dy = gLastY - y; - - if (fabs(dy) <= 2.0f) { - dy = 0.0f; - } - if (fabs(dx) <= 2.0f) { - dx = 0.0f; - } - - gRotateY -= dx; - if (gRotateY > 360) { - gRotateY -= 360; - } - if (gRotateY < 0) { - gRotateY += 360; - } - - gRotateX -= dy; - gRotateX = min(gRotateX, 80.0f); - gRotateX = max(gRotateX, -80.0f); - - gLastX = x; - gLastY = y; -} - -void init() { - gRotateX = 0.0f; - gRotateY = 0.0f; - gZoom = 50.0f; - gLookAt = 0.0f; -} - -void updateMeshInfo() { - rs_allocation allMeshes = rsGetAllocation(gMeshes); - int size = rsAllocationGetDimX(allMeshes); - gLookAt = 0.0f; - float minX, minY, minZ, maxX, maxY, maxZ; - for (int i = 0; i < size; i++) { - MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); - rsgMeshComputeBoundingBox(info->mMesh, - &minX, &minY, &minZ, - &maxX, &maxY, &maxZ); - info->bBoxMin = toFloat3(minX, minY, minZ); - info->bBoxMax = toFloat3(maxX, maxY, maxZ); - gLookAt += (info->bBoxMin + info->bBoxMax)*0.5f; - } - gLookAt = gLookAt / (float)size; -} - -static void renderAllMeshes() { - rs_allocation allMeshes = rsGetAllocation(gMeshes); - int size = rsAllocationGetDimX(allMeshes); - gLookAt = 0.0f; - for (int i = 0; i < size; i++) { - MeshInfo_t *info = (MeshInfo_t*)rsGetElementAt(allMeshes, i); - rsgDrawMesh(info->mMesh); - } -} - -static void renderOffscreen() { - rsgBindProgramVertex(gPVBackground); - rs_matrix4x4 proj; - float aspect = (float) rsAllocationGetDimX(gScreen) / (float) rsAllocationGetDimY(gScreen); - rsMatrixLoadPerspective(&proj, 30.0f, aspect, 1.0f, 1000.0f); - rsgProgramVertexLoadProjectionMatrix(&proj); - - rsgBindProgramFragment(gPFBackground); - rsgBindTexture(gPFBackground, 0, gTMesh); - - rs_matrix4x4 matrix; - - rsMatrixLoadIdentity(&matrix); - rsMatrixTranslate(&matrix, gLookAt.x, gLookAt.y, gLookAt.z - gZoom); - rsMatrixRotate(&matrix, gRotateX, 1.0f, 0.0f, 0.0f); - rsMatrixRotate(&matrix, gRotateY, 0.0f, 1.0f, 0.0f); - rsgProgramVertexLoadModelMatrix(&matrix); - - renderAllMeshes(); -} - -static void drawOffscreenResult(int posX, int posY, float width, float height) { - // display the result d - rs_matrix4x4 proj, matrix; - rsMatrixLoadOrtho(&proj, 0, width, height, 0, -500, 500); - rsgProgramVertexLoadProjectionMatrix(&proj); - rsMatrixLoadIdentity(&matrix); - rsgProgramVertexLoadModelMatrix(&matrix); - float startX = posX, startY = posY; - rsgDrawQuadTexCoords(startX, startY, 0, 0, 1, - startX, startY + height, 0, 0, 0, - startX + width, startY + height, 0, 1, 0, - startX + width, startY, 0, 1, 1); -} - -int root(void) { - gFSVignetteConstants->size = 0.58f * 0.58f; - gFSVignetteConstants->feather = 0.2f; - gFSVignetteConstants->width = (float) rsAllocationGetDimX(gScreen); - gFSVignetteConstants->height = (float) rsAllocationGetDimY(gScreen); - - rsgBindProgramStore(gPFSBackground); - - // Render scene to fullscreenbuffer - rsgBindColorTarget(gScreen, 0); - rsgBindDepthTarget(gScreenDepth); - rsgClearDepth(1.0f); - rsgClearColor(1.0f, 1.0f, 1.0f, 0.0f); - renderOffscreen(); - - // Render on screen - rsgClearAllRenderTargets(); - rsgClearColor(1.0f, 1.0f, 1.0f, 1.0f); - rsgClearDepth(1.0f); - - rsgBindProgramFragment(gPFVignette); - rsgBindTexture(gPFVignette, 0, gScreen); - drawOffscreenResult(0, 0, rsgGetWidth(), rsgGetHeight()); - - return 0; -} diff --git a/tools/aapt/Images.cpp b/tools/aapt/Images.cpp index e4738f5eda7d..5ad337949bee 100644 --- a/tools/aapt/Images.cpp +++ b/tools/aapt/Images.cpp @@ -1095,13 +1095,6 @@ static void write_png(const char* imageName, analyze_image(imageName, imageInfo, grayscaleTolerance, rgbPalette, alphaPalette, &paletteEntries, &hasTransparency, &color_type, outRows); - // If the image is a 9-patch, we need to preserve it as a ARGB file to make - // sure the pixels will not be pre-dithered/clamped until we decide they are - if (imageInfo.is9Patch && (color_type == PNG_COLOR_TYPE_RGB || - color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_PALETTE)) { - color_type = PNG_COLOR_TYPE_RGB_ALPHA; - } - if (kIsDebug) { switch (color_type) { case PNG_COLOR_TYPE_PALETTE: @@ -1180,18 +1173,11 @@ static void write_png(const char* imageName, } for (int i = 0; i < chunk_count; i++) { - unknowns[i].location = PNG_HAVE_PLTE; + unknowns[i].location = PNG_HAVE_IHDR; } png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, chunk_names, chunk_count); png_set_unknown_chunks(write_ptr, write_info, unknowns, chunk_count); -#if PNG_LIBPNG_VER < 10600 - /* Deal with unknown chunk location bug in 1.5.x and earlier */ - png_set_unknown_chunk_location(write_ptr, write_info, 0, PNG_HAVE_PLTE); - if (imageInfo.haveLayoutBounds) { - png_set_unknown_chunk_location(write_ptr, write_info, 1, PNG_HAVE_PLTE); - } -#endif } diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk index 0f839801ff81..a4f4ba928855 100644 --- a/tools/aapt2/Android.mk +++ b/tools/aapt2/Android.mk @@ -27,6 +27,8 @@ main := Main.cpp sources := \ compile/IdAssigner.cpp \ compile/Png.cpp \ + compile/PseudolocaleGenerator.cpp \ + compile/Pseudolocalizer.cpp \ compile/XmlIdCollector.cpp \ flatten/Archive.cpp \ flatten/TableFlattener.cpp \ @@ -66,6 +68,8 @@ sources := \ testSources := \ compile/IdAssigner_test.cpp \ + compile/PseudolocaleGenerator_test.cpp \ + compile/Pseudolocalizer_test.cpp \ compile/XmlIdCollector_test.cpp \ flatten/FileExportWriter_test.cpp \ flatten/TableFlattener_test.cpp \ diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp index d864f664f9db..5fce2c16f630 100644 --- a/tools/aapt2/Debug.cpp +++ b/tools/aapt2/Debug.cpp @@ -52,13 +52,17 @@ struct PrintVisitor : public ValueVisitor { void visit(Style* style) override { std::cout << "(style)"; if (style->parent) { + const Reference& parentRef = style->parent.value(); std::cout << " parent="; - if (style->parent.value().name) { - std::cout << style->parent.value().name.value() << " "; + if (parentRef.name) { + if (parentRef.privateReference) { + std::cout << "*"; + } + std::cout << parentRef.name.value() << " "; } - if (style->parent.value().id) { - std::cout << style->parent.value().id.value(); + if (parentRef.id) { + std::cout << parentRef.id.value(); } } diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp index d4c536f61c45..e1f9642d27d7 100644 --- a/tools/aapt2/ResourceParser.cpp +++ b/tools/aapt2/ResourceParser.cpp @@ -19,9 +19,12 @@ #include "ResourceUtils.h" #include "ResourceValues.h" #include "ValueVisitor.h" +#include "util/Comparators.h" +#include "util/ImmutableMap.h" #include "util/Util.h" #include "xml/XmlPullParser.h" +#include <functional> #include <sstream> namespace aapt { @@ -35,6 +38,111 @@ static bool shouldIgnoreElement(const StringPiece16& ns, const StringPiece16& na return ns.empty() && (name == u"skip" || name == u"eat-comment"); } +static uint32_t parseFormatType(const StringPiece16& piece) { + if (piece == u"reference") return android::ResTable_map::TYPE_REFERENCE; + else if (piece == u"string") return android::ResTable_map::TYPE_STRING; + else if (piece == u"integer") return android::ResTable_map::TYPE_INTEGER; + else if (piece == u"boolean") return android::ResTable_map::TYPE_BOOLEAN; + else if (piece == u"color") return android::ResTable_map::TYPE_COLOR; + else if (piece == u"float") return android::ResTable_map::TYPE_FLOAT; + else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION; + else if (piece == u"fraction") return android::ResTable_map::TYPE_FRACTION; + else if (piece == u"enum") return android::ResTable_map::TYPE_ENUM; + else if (piece == u"flags") return android::ResTable_map::TYPE_FLAGS; + return 0; +} + +static uint32_t parseFormatAttribute(const StringPiece16& str) { + uint32_t mask = 0; + for (StringPiece16 part : util::tokenize(str, u'|')) { + StringPiece16 trimmedPart = util::trimWhitespace(part); + uint32_t type = parseFormatType(trimmedPart); + if (type == 0) { + return 0; + } + mask |= type; + } + return mask; +} + +/** + * A parsed resource ready to be added to the ResourceTable. + */ +struct ParsedResource { + ResourceName name; + Source source; + ResourceId id; + Maybe<SymbolState> symbolState; + std::u16string comment; + std::unique_ptr<Value> value; + std::list<ParsedResource> childResources; +}; + +bool ResourceParser::shouldStripResource(const ResourceNameRef& name, + const Maybe<std::u16string>& product) const { + if (product) { + for (const std::u16string& productToMatch : mOptions.products) { + if (product.value() == productToMatch) { + // We specified a product, and it is in the list, so don't strip. + return false; + } + } + } + + // Nothing matched, try 'default'. Default only matches if we didn't already use another + // product variant. + if (!product || product.value() == u"default") { + if (Maybe<ResourceTable::SearchResult> result = mTable->findResource(name)) { + const ResourceEntry* entry = result.value().entry; + auto iter = std::lower_bound(entry->values.begin(), entry->values.end(), mConfig, + cmp::lessThanConfig); + if (iter != entry->values.end() && iter->config == mConfig && !iter->value->isWeak()) { + // We have a value for this config already, and it is not weak, + // so filter out this default. + return true; + } + } + return false; + } + return true; +} + +// Recursively adds resources to the ResourceTable. +static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config, + IDiagnostics* diag, ParsedResource* res) { + if (res->symbolState) { + Symbol symbol; + symbol.state = res->symbolState.value(); + symbol.source = res->source; + symbol.comment = res->comment; + if (!table->setSymbolState(res->name, res->id, symbol, diag)) { + return false; + } + } + + if (res->value) { + // Attach the comment, source and config to the value. + res->value->setComment(std::move(res->comment)); + res->value->setSource(std::move(res->source)); + + if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) { + return false; + } + } + + bool error = false; + for (ParsedResource& child : res->childResources) { + error |= !addResourcesToTable(table, config, diag, &child); + } + return !error; +} + +// Convenient aliases for more readable function calls. +enum { + kAllowRawString = true, + kNoRawString = false +}; + ResourceParser::ResourceParser(IDiagnostics* diag, ResourceTable* table, const Source& source, const ConfigDescription& config, const ResourceParserOptions& options) : @@ -146,69 +254,6 @@ bool ResourceParser::parse(xml::XmlPullParser* parser) { return !error; } -static bool shouldStripResource(const xml::XmlPullParser* parser, - const Maybe<std::u16string> productToMatch) { - assert(parser->getEvent() == xml::XmlPullParser::Event::kStartElement); - - if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) { - if (!productToMatch) { - if (maybeProduct.value() != u"default" && maybeProduct.value() != u"phone") { - // We didn't specify a product and this is not a default product, so skip. - return true; - } - } else { - if (productToMatch && maybeProduct.value() != productToMatch.value()) { - // We specified a product, but they don't match. - return true; - } - } - } - return false; -} - -/** - * A parsed resource ready to be added to the ResourceTable. - */ -struct ParsedResource { - ResourceName name; - Source source; - ResourceId id; - Maybe<SymbolState> symbolState; - std::u16string comment; - std::unique_ptr<Value> value; - std::list<ParsedResource> childResources; -}; - -// Recursively adds resources to the ResourceTable. -static bool addResourcesToTable(ResourceTable* table, const ConfigDescription& config, - IDiagnostics* diag, ParsedResource* res) { - if (res->symbolState) { - Symbol symbol; - symbol.state = res->symbolState.value(); - symbol.source = res->source; - symbol.comment = res->comment; - if (!table->setSymbolState(res->name, res->id, symbol, diag)) { - return false; - } - } - - if (res->value) { - // Attach the comment, source and config to the value. - res->value->setComment(std::move(res->comment)); - res->value->setSource(std::move(res->source)); - - if (!table->addResource(res->name, res->id, config, std::move(res->value), diag)) { - return false; - } - } - - bool error = false; - for (ParsedResource& child : res->childResources) { - error |= !addResourcesToTable(table, config, diag, &child); - } - return !error; -} - bool ResourceParser::parseResources(xml::XmlPullParser* parser) { std::set<ResourceName> strippedResources; @@ -244,118 +289,28 @@ bool ResourceParser::parseResources(xml::XmlPullParser* parser) { continue; } - if (elementName == u"item") { - // Items simply have their type encoded in the type attribute. - if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) { - elementName = maybeType.value().toString(); - } else { - mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) - << "<item> must have a 'type' attribute"); - error = true; - continue; - } - } - ParsedResource parsedResource; parsedResource.source = mSource.withLine(parser->getLineNumber()); parsedResource.comment = std::move(comment); - if (Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name")) { - parsedResource.name.entry = maybeName.value().toString(); + // Extract the product name if it exists. + Maybe<std::u16string> product; + if (Maybe<StringPiece16> maybeProduct = xml::findNonEmptyAttribute(parser, u"product")) { + product = maybeProduct.value().toString(); + } - } else if (elementName != u"public-group") { - mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) - << "<" << elementName << "> tag must have a 'name' attribute"); + // Parse the resource regardless of product. + if (!parseResource(parser, &parsedResource)) { error = true; continue; } - // Check if we should skip this product. - const bool stripResource = shouldStripResource(parser, mOptions.product); - - bool result = true; - if (elementName == u"id") { - parsedResource.name.type = ResourceType::kId; - parsedResource.value = util::make_unique<Id>(); - } else if (elementName == u"string") { - parsedResource.name.type = ResourceType::kString; - result = parseString(parser, &parsedResource); - } else if (elementName == u"color") { - parsedResource.name.type = ResourceType::kColor; - result = parseColor(parser, &parsedResource); - } else if (elementName == u"drawable") { - parsedResource.name.type = ResourceType::kDrawable; - result = parseColor(parser, &parsedResource); - } else if (elementName == u"bool") { - parsedResource.name.type = ResourceType::kBool; - result = parsePrimitive(parser, &parsedResource); - } else if (elementName == u"integer") { - parsedResource.name.type = ResourceType::kInteger; - result = parsePrimitive(parser, &parsedResource); - } else if (elementName == u"dimen") { - parsedResource.name.type = ResourceType::kDimen; - result = parsePrimitive(parser, &parsedResource); - } else if (elementName == u"fraction") { - parsedResource.name.type = ResourceType::kFraction; - result = parsePrimitive(parser, &parsedResource); - } else if (elementName == u"style") { - parsedResource.name.type = ResourceType::kStyle; - result = parseStyle(parser, &parsedResource); - } else if (elementName == u"plurals") { - parsedResource.name.type = ResourceType::kPlurals; - result = parsePlural(parser, &parsedResource); - } else if (elementName == u"array") { - parsedResource.name.type = ResourceType::kArray; - result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_ANY); - } else if (elementName == u"string-array") { - parsedResource.name.type = ResourceType::kArray; - result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_STRING); - } else if (elementName == u"integer-array") { - parsedResource.name.type = ResourceType::kArray; - result = parseArray(parser, &parsedResource, android::ResTable_map::TYPE_INTEGER); - } else if (elementName == u"declare-styleable") { - parsedResource.name.type = ResourceType::kStyleable; - result = parseDeclareStyleable(parser, &parsedResource); - } else if (elementName == u"attr") { - parsedResource.name.type = ResourceType::kAttr; - result = parseAttr(parser, &parsedResource); - } else if (elementName == u"public") { - result = parsePublic(parser, &parsedResource); - } else if (elementName == u"java-symbol" || elementName == u"symbol") { - result = parseSymbol(parser, &parsedResource); - } else if (elementName == u"public-group") { - result = parsePublicGroup(parser, &parsedResource); - } else if (elementName == u"add-resource") { - result = parseAddResource(parser, &parsedResource); - } else { - // Try parsing the elementName (or type) as a resource. These shall only be - // resources like 'layout' or 'xml' and they can only be references. - if (const ResourceType* type = parseResourceType(elementName)) { - parsedResource.name.type = *type; - parsedResource.value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE, - false); - if (!parsedResource.value) { - mDiag->error(DiagMessage(parsedResource.source) << "invalid value for type '" - << *type << "'. Expected a reference"); - result = false; - } - } else { - mDiag->warn(DiagMessage(mSource.withLine(parser->getLineNumber())) - << "unknown resource type '" << elementName << "'"); - } - } - - if (result) { - // We successfully parsed the resource. - - if (stripResource) { - // Record that we stripped out this resource name. - // We will check that at least one variant of this resource was included. - strippedResources.insert(parsedResource.name); - } else { - error |= !addResourcesToTable(mTable, mConfig, mDiag, &parsedResource); - } - } else { + // We successfully parsed the resource. Check if we should include it or strip it. + if (shouldStripResource(parsedResource.name, product)) { + // Record that we stripped out this resource name. + // We will check that at least one variant of this resource was included. + strippedResources.insert(parsedResource.name); + } else if (!addResourcesToTable(mTable, mConfig, mDiag, &parsedResource)) { error = true; } } @@ -373,10 +328,173 @@ bool ResourceParser::parseResources(xml::XmlPullParser* parser) { return !error; } -enum { - kAllowRawString = true, - kNoRawString = false -}; + +bool ResourceParser::parseResource(xml::XmlPullParser* parser, ParsedResource* outResource) { + struct ItemTypeFormat { + ResourceType type; + uint32_t format; + }; + + using BagParseFunc = std::function<bool(ResourceParser*, xml::XmlPullParser*, ParsedResource*)>; + + static const auto elToItemMap = ImmutableMap<std::u16string, ItemTypeFormat>::createPreSorted({ + { u"bool", { ResourceType::kBool, android::ResTable_map::TYPE_BOOLEAN } }, + { u"color", { ResourceType::kColor, android::ResTable_map::TYPE_COLOR } }, + { u"dimen", { ResourceType::kDimen, android::ResTable_map::TYPE_FLOAT + | android::ResTable_map::TYPE_FRACTION + | android::ResTable_map::TYPE_DIMENSION } }, + { u"drawable", { ResourceType::kDrawable, android::ResTable_map::TYPE_COLOR } }, + { u"fraction", { ResourceType::kFraction, android::ResTable_map::TYPE_FLOAT + | android::ResTable_map::TYPE_FRACTION + | android::ResTable_map::TYPE_DIMENSION } }, + { u"integer", { ResourceType::kInteger, android::ResTable_map::TYPE_INTEGER } }, + { u"string", { ResourceType::kString, android::ResTable_map::TYPE_STRING } }, + }); + + static const auto elToBagMap = ImmutableMap<std::u16string, BagParseFunc>::createPreSorted({ + { u"add-resource", std::mem_fn(&ResourceParser::parseAddResource) }, + { u"array", std::mem_fn(&ResourceParser::parseArray) }, + { u"attr", std::mem_fn(&ResourceParser::parseAttr) }, + { u"declare-styleable", std::mem_fn(&ResourceParser::parseDeclareStyleable) }, + { u"integer-array", std::mem_fn(&ResourceParser::parseIntegerArray) }, + { u"java-symbol", std::mem_fn(&ResourceParser::parseSymbol) }, + { u"plurals", std::mem_fn(&ResourceParser::parsePlural) }, + { u"public", std::mem_fn(&ResourceParser::parsePublic) }, + { u"public-group", std::mem_fn(&ResourceParser::parsePublicGroup) }, + { u"string-array", std::mem_fn(&ResourceParser::parseStringArray) }, + { u"style", std::mem_fn(&ResourceParser::parseStyle) }, + { u"symbol", std::mem_fn(&ResourceParser::parseSymbol) }, + }); + + std::u16string resourceType = parser->getElementName(); + + // The value format accepted for this resource. + uint32_t resourceFormat = 0u; + + if (resourceType == u"item") { + // Items have their type encoded in the type attribute. + if (Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type")) { + resourceType = maybeType.value().toString(); + } else { + mDiag->error(DiagMessage(mSource.withLine(parser->getLineNumber())) + << "<item> must have a 'type' attribute"); + return false; + } + + if (Maybe<StringPiece16> maybeFormat = xml::findNonEmptyAttribute(parser, u"format")) { + // An explicit format for this resource was specified. The resource will retain + // its type in its name, but the accepted value for this type is overridden. + resourceFormat = parseFormatType(maybeFormat.value()); + if (!resourceFormat) { + mDiag->error(DiagMessage(outResource->source) + << "'" << maybeFormat.value() << "' is an invalid format"); + return false; + } + } + } + + // Get the name of the resource. This will be checked later, because not all + // XML elements require a name. + Maybe<StringPiece16> maybeName = xml::findNonEmptyAttribute(parser, u"name"); + + if (resourceType == u"id") { + if (!maybeName) { + mDiag->error(DiagMessage(outResource->source) + << "<" << parser->getElementName() << "> missing 'name' attribute"); + return false; + } + + outResource->name.type = ResourceType::kId; + outResource->name.entry = maybeName.value().toString(); + outResource->value = util::make_unique<Id>(); + return true; + } + + const auto itemIter = elToItemMap.find(resourceType); + if (itemIter != elToItemMap.end()) { + // This is an item, record its type and format and start parsing. + + if (!maybeName) { + mDiag->error(DiagMessage(outResource->source) + << "<" << parser->getElementName() << "> missing 'name' attribute"); + return false; + } + + outResource->name.type = itemIter->second.type; + outResource->name.entry = maybeName.value().toString(); + + // Only use the implicit format for this type if it wasn't overridden. + if (!resourceFormat) { + resourceFormat = itemIter->second.format; + } + + if (!parseItem(parser, outResource, resourceFormat)) { + return false; + } + return true; + } + + // This might be a bag or something. + const auto bagIter = elToBagMap.find(resourceType); + if (bagIter != elToBagMap.end()) { + // Ensure we have a name (unless this is a <public-group>). + if (resourceType != u"public-group") { + if (!maybeName) { + mDiag->error(DiagMessage(outResource->source) + << "<" << parser->getElementName() << "> missing 'name' attribute"); + return false; + } + + outResource->name.entry = maybeName.value().toString(); + } + + // Call the associated parse method. The type will be filled in by the + // parse func. + if (!bagIter->second(this, parser, outResource)) { + return false; + } + return true; + } + + // Try parsing the elementName (or type) as a resource. These shall only be + // resources like 'layout' or 'xml' and they can only be references. + const ResourceType* parsedType = parseResourceType(resourceType); + if (parsedType) { + if (!maybeName) { + mDiag->error(DiagMessage(outResource->source) + << "<" << parser->getElementName() << "> missing 'name' attribute"); + return false; + } + + outResource->name.type = *parsedType; + outResource->name.entry = maybeName.value().toString(); + outResource->value = parseXml(parser, android::ResTable_map::TYPE_REFERENCE, kNoRawString); + if (!outResource->value) { + mDiag->error(DiagMessage(outResource->source) + << "invalid value for type '" << *parsedType << "'. Expected a reference"); + return false; + } + return true; + } + + mDiag->warn(DiagMessage(outResource->source) + << "unknown resource type '" << parser->getElementName() << "'"); + return false; +} + +bool ResourceParser::parseItem(xml::XmlPullParser* parser, ParsedResource* outResource, + const uint32_t format) { + if (format == android::ResTable_map::TYPE_STRING) { + return parseString(parser, outResource); + } + + outResource->value = parseXml(parser, format, kNoRawString); + if (!outResource->value) { + mDiag->error(DiagMessage(outResource->source) << "invalid " << outResource->name.type); + return false; + } + return true; +} /** * Reads the entire XML subtree and attempts to parse it as some Item, @@ -431,17 +549,15 @@ std::unique_ptr<Item> ResourceParser::parseXml(xml::XmlPullParser* parser, const return util::make_unique<RawString>( mTable->stringPool.makeRef(rawValue, StringPool::Context{ 1, mConfig })); } - return {}; } bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); - bool formatted = true; if (Maybe<StringPiece16> formattedAttr = xml::findAttribute(parser, u"formatted")) { if (!ResourceUtils::tryParseBool(formattedAttr.value(), &formatted)) { - mDiag->error(DiagMessage(source) << "invalid value for 'formatted'. Must be a boolean"); + mDiag->error(DiagMessage(outResource->source) + << "invalid value for 'formatted'. Must be a boolean"); return false; } } @@ -449,7 +565,7 @@ bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* out bool translateable = mOptions.translatable; if (Maybe<StringPiece16> translateableAttr = xml::findAttribute(parser, u"translatable")) { if (!ResourceUtils::tryParseBool(translateableAttr.value(), &translateable)) { - mDiag->error(DiagMessage(source) + mDiag->error(DiagMessage(outResource->source) << "invalid value for 'translatable'. Must be a boolean"); return false; } @@ -457,81 +573,39 @@ bool ResourceParser::parseString(xml::XmlPullParser* parser, ParsedResource* out outResource->value = parseXml(parser, android::ResTable_map::TYPE_STRING, kNoRawString); if (!outResource->value) { - mDiag->error(DiagMessage(source) << "not a valid string"); + mDiag->error(DiagMessage(outResource->source) << "not a valid string"); return false; } - if (formatted && translateable) { - if (String* stringValue = valueCast<String>(outResource->value.get())) { + if (String* stringValue = valueCast<String>(outResource->value.get())) { + stringValue->setTranslateable(translateable); + + if (formatted && translateable) { if (!util::verifyJavaStringFormat(*stringValue->value)) { - mDiag->error(DiagMessage(source) + mDiag->error(DiagMessage(outResource->source) << "multiple substitutions specified in non-positional format; " "did you mean to add the formatted=\"false\" attribute?"); return false; } } - } - return true; -} - -bool ResourceParser::parseColor(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); - - outResource->value = parseXml(parser, android::ResTable_map::TYPE_COLOR, kNoRawString); - if (!outResource->value) { - mDiag->error(DiagMessage(source) << "invalid color"); - return false; - } - return true; -} - -bool ResourceParser::parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); - - uint32_t typeMask = 0; - switch (outResource->name.type) { - case ResourceType::kInteger: - typeMask |= android::ResTable_map::TYPE_INTEGER; - break; - - case ResourceType::kFraction: - // fallthrough - case ResourceType::kDimen: - typeMask |= android::ResTable_map::TYPE_DIMENSION - | android::ResTable_map::TYPE_FLOAT - | android::ResTable_map::TYPE_FRACTION; - break; - - case ResourceType::kBool: - typeMask |= android::ResTable_map::TYPE_BOOLEAN; - break; - - default: - assert(false); - break; - } - outResource->value = parseXml(parser, typeMask, kNoRawString); - if (!outResource->value) { - mDiag->error(DiagMessage(source) << "invalid " << outResource->name.type); - return false; + } else if (StyledString* stringValue = valueCast<StyledString>(outResource->value.get())) { + stringValue->setTranslateable(translateable); } return true; } bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); - Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type"); if (!maybeType) { - mDiag->error(DiagMessage(source) << "<public> must have a 'type' attribute"); + mDiag->error(DiagMessage(outResource->source) << "<public> must have a 'type' attribute"); return false; } const ResourceType* parsedType = parseResourceType(maybeType.value()); if (!parsedType) { - mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value() - << "' in <public>"); + mDiag->error(DiagMessage(outResource->source) + << "invalid resource type '" << maybeType.value() << "' in <public>"); return false; } @@ -543,8 +617,8 @@ bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* out maybeId.value().size(), &val); ResourceId resourceId(val.data); if (!result || !resourceId.isValid()) { - mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value() - << "' in <public>"); + mDiag->error(DiagMessage(outResource->source) + << "invalid resource ID '" << maybeId.value() << "' in <public>"); return false; } outResource->id = resourceId; @@ -560,24 +634,24 @@ bool ResourceParser::parsePublic(xml::XmlPullParser* parser, ParsedResource* out } bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); - Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type"); if (!maybeType) { - mDiag->error(DiagMessage(source) << "<public-group> must have a 'type' attribute"); + mDiag->error(DiagMessage(outResource->source) + << "<public-group> must have a 'type' attribute"); return false; } const ResourceType* parsedType = parseResourceType(maybeType.value()); if (!parsedType) { - mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value() - << "' in <public-group>"); + mDiag->error(DiagMessage(outResource->source) + << "invalid resource type '" << maybeType.value() << "' in <public-group>"); return false; } Maybe<StringPiece16> maybeId = xml::findNonEmptyAttribute(parser, u"first-id"); if (!maybeId) { - mDiag->error(DiagMessage(source) << "<public-group> must have a 'first-id' attribute"); + mDiag->error(DiagMessage(outResource->source) + << "<public-group> must have a 'first-id' attribute"); return false; } @@ -586,8 +660,8 @@ bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource maybeId.value().size(), &val); ResourceId nextId(val.data); if (!result || !nextId.isValid()) { - mDiag->error(DiagMessage(source) << "invalid resource ID '" << maybeId.value() - << "' in <public-group>"); + mDiag->error(DiagMessage(outResource->source) + << "invalid resource ID '" << maybeId.value() << "' in <public-group>"); return false; } @@ -646,18 +720,17 @@ bool ResourceParser::parsePublicGroup(xml::XmlPullParser* parser, ParsedResource } bool ResourceParser::parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); - Maybe<StringPiece16> maybeType = xml::findNonEmptyAttribute(parser, u"type"); if (!maybeType) { - mDiag->error(DiagMessage(source) << "<" << parser->getElementName() << "> must have a " - "'type' attribute"); + mDiag->error(DiagMessage(outResource->source) + << "<" << parser->getElementName() << "> must have a 'type' attribute"); return false; } const ResourceType* parsedType = parseResourceType(maybeType.value()); if (!parsedType) { - mDiag->error(DiagMessage(source) << "invalid resource type '" << maybeType.value() + mDiag->error(DiagMessage(outResource->source) + << "invalid resource type '" << maybeType.value() << "' in <" << parser->getElementName() << ">"); return false; } @@ -682,40 +755,15 @@ bool ResourceParser::parseAddResource(xml::XmlPullParser* parser, ParsedResource return false; } -static uint32_t parseFormatType(const StringPiece16& piece) { - if (piece == u"reference") return android::ResTable_map::TYPE_REFERENCE; - else if (piece == u"string") return android::ResTable_map::TYPE_STRING; - else if (piece == u"integer") return android::ResTable_map::TYPE_INTEGER; - else if (piece == u"boolean") return android::ResTable_map::TYPE_BOOLEAN; - else if (piece == u"color") return android::ResTable_map::TYPE_COLOR; - else if (piece == u"float") return android::ResTable_map::TYPE_FLOAT; - else if (piece == u"dimension") return android::ResTable_map::TYPE_DIMENSION; - else if (piece == u"fraction") return android::ResTable_map::TYPE_FRACTION; - else if (piece == u"enum") return android::ResTable_map::TYPE_ENUM; - else if (piece == u"flags") return android::ResTable_map::TYPE_FLAGS; - return 0; -} - -static uint32_t parseFormatAttribute(const StringPiece16& str) { - uint32_t mask = 0; - for (StringPiece16 part : util::tokenize(str, u'|')) { - StringPiece16 trimmedPart = util::trimWhitespace(part); - uint32_t type = parseFormatType(trimmedPart); - if (type == 0) { - return 0; - } - mask |= type; - } - return mask; -} bool ResourceParser::parseAttr(xml::XmlPullParser* parser, ParsedResource* outResource) { - outResource->source = mSource.withLine(parser->getLineNumber()); return parseAttrImpl(parser, outResource, false); } bool ResourceParser::parseAttrImpl(xml::XmlPullParser* parser, ParsedResource* outResource, bool weak) { + outResource->name.type = ResourceType::kAttr; + uint32_t typeMask = 0; Maybe<StringPiece16> maybeFormat = xml::findAttribute(parser, u"format"); @@ -949,7 +997,8 @@ bool ResourceParser::parseStyleItem(xml::XmlPullParser* parser, Style* style) { } bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); + outResource->name.type = ResourceType::kStyle; + std::unique_ptr<Style> style = util::make_unique<Style>(); Maybe<StringPiece16> maybeParent = xml::findAttribute(parser, u"parent"); @@ -959,7 +1008,7 @@ bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outR std::string errStr; style->parent = ResourceUtils::parseStyleParentReference(maybeParent.value(), &errStr); if (!style->parent) { - mDiag->error(DiagMessage(source) << errStr); + mDiag->error(DiagMessage(outResource->source) << errStr); return false; } @@ -1007,9 +1056,22 @@ bool ResourceParser::parseStyle(xml::XmlPullParser* parser, ParsedResource* outR return true; } -bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource, - uint32_t typeMask) { - const Source source = mSource.withLine(parser->getLineNumber()); +bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outResource) { + return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_ANY); +} + +bool ResourceParser::parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource) { + return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_INTEGER); +} + +bool ResourceParser::parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource) { + return parseArrayImpl(parser, outResource, android::ResTable_map::TYPE_STRING); +} + +bool ResourceParser::parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource, + const uint32_t typeMask) { + outResource->name.type = ResourceType::kArray; + std::unique_ptr<Array> array = util::make_unique<Array>(); bool error = false; @@ -1049,7 +1111,8 @@ bool ResourceParser::parseArray(xml::XmlPullParser* parser, ParsedResource* outR } bool ResourceParser::parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); + outResource->name.type = ResourceType::kPlurals; + std::unique_ptr<Plural> plural = util::make_unique<Plural>(); bool error = false; @@ -1123,12 +1186,13 @@ bool ResourceParser::parsePlural(xml::XmlPullParser* parser, ParsedResource* out } bool ResourceParser::parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource) { - const Source source = mSource.withLine(parser->getLineNumber()); - std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); + outResource->name.type = ResourceType::kStyleable; // Declare-styleable is kPrivate by default, because it technically only exists in R.java. outResource->symbolState = SymbolState::kPublic; + std::unique_ptr<Styleable> styleable = util::make_unique<Styleable>(); + std::u16string comment; bool error = false; const size_t depth = parser->getDepth(); diff --git a/tools/aapt2/ResourceParser.h b/tools/aapt2/ResourceParser.h index 04db5778a456..9ad749e27dbc 100644 --- a/tools/aapt2/ResourceParser.h +++ b/tools/aapt2/ResourceParser.h @@ -34,11 +34,11 @@ struct ParsedResource; struct ResourceParserOptions { /** - * Optional product name by which to filter resources. + * Optional product names by which to filter resources. * This is like a preprocessor definition in that we strip out resources * that don't match before we compile them. */ - Maybe<std::u16string> product; + std::vector<std::u16string> products; /** * Whether the default setting for this parser is to allow translation. @@ -78,9 +78,11 @@ private: const bool allowRawValue); bool parseResources(xml::XmlPullParser* parser); + bool parseResource(xml::XmlPullParser* parser, ParsedResource* outResource); + + bool parseItem(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t format); bool parseString(xml::XmlPullParser* parser, ParsedResource* outResource); - bool parseColor(xml::XmlPullParser* parser, ParsedResource* outResource); - bool parsePrimitive(xml::XmlPullParser* parser, ParsedResource* outResource); + bool parsePublic(xml::XmlPullParser* parser, ParsedResource* outResource); bool parsePublicGroup(xml::XmlPullParser* parser, ParsedResource* outResource); bool parseSymbolImpl(xml::XmlPullParser* parser, ParsedResource* outResource); @@ -93,9 +95,15 @@ private: bool parseStyle(xml::XmlPullParser* parser, ParsedResource* outResource); bool parseStyleItem(xml::XmlPullParser* parser, Style* style); bool parseDeclareStyleable(xml::XmlPullParser* parser, ParsedResource* outResource); - bool parseArray(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t typeMask); + bool parseArray(xml::XmlPullParser* parser, ParsedResource* outResource); + bool parseIntegerArray(xml::XmlPullParser* parser, ParsedResource* outResource); + bool parseStringArray(xml::XmlPullParser* parser, ParsedResource* outResource); + bool parseArrayImpl(xml::XmlPullParser* parser, ParsedResource* outResource, uint32_t typeMask); bool parsePlural(xml::XmlPullParser* parser, ParsedResource* outResource); + bool shouldStripResource(const ResourceNameRef& name, + const Maybe<std::u16string>& product) const; + IDiagnostics* mDiag; ResourceTable* mTable; Source mSource; diff --git a/tools/aapt2/ResourceParser_test.cpp b/tools/aapt2/ResourceParser_test.cpp index 84f67c6be005..8d10ba14924b 100644 --- a/tools/aapt2/ResourceParser_test.cpp +++ b/tools/aapt2/ResourceParser_test.cpp @@ -48,11 +48,11 @@ struct ResourceParserTest : public ::testing::Test { } ::testing::AssertionResult testParse(const StringPiece& str, - Maybe<std::u16string> product = {}) { + std::initializer_list<std::u16string> products = {}) { std::stringstream input(kXmlPreamble); input << "<resources>\n" << str << "\n</resources>" << std::endl; ResourceParserOptions parserOptions; - parserOptions.product = product; + parserOptions.products = products; ResourceParser parser(mContext->getDiagnostics(), &mTable, Source{ "test" }, {}, parserOptions); xml::XmlPullParser xmlParser(input); @@ -215,7 +215,7 @@ TEST_F(ResourceParserTest, ParseFlagAttr) { ASSERT_TRUE(testParse(input)); Attribute* flagAttr = test::getValue<Attribute>(&mTable, u"@attr/foo"); - ASSERT_NE(flagAttr, nullptr); + ASSERT_NE(nullptr, flagAttr); EXPECT_EQ(flagAttr->typeMask, android::ResTable_map::TYPE_FLAGS); ASSERT_EQ(flagAttr->symbols.size(), 3u); @@ -233,7 +233,7 @@ TEST_F(ResourceParserTest, ParseFlagAttr) { std::unique_ptr<BinaryPrimitive> flagValue = ResourceUtils::tryParseFlagSymbol(flagAttr, u"baz|bat"); - ASSERT_NE(flagValue, nullptr); + ASSERT_NE(nullptr, flagValue); EXPECT_EQ(flagValue->value.data, 1u | 2u); } @@ -255,7 +255,7 @@ TEST_F(ResourceParserTest, ParseStyle) { ASSERT_TRUE(testParse(input)); Style* style = test::getValue<Style>(&mTable, u"@style/foo"); - ASSERT_NE(style, nullptr); + ASSERT_NE(nullptr, style); AAPT_ASSERT_TRUE(style->parent); AAPT_ASSERT_TRUE(style->parent.value().name); EXPECT_EQ(test::parseNameOrDie(u"@style/fu"), style->parent.value().name.value()); @@ -276,7 +276,7 @@ TEST_F(ResourceParserTest, ParseStyleWithShorthandParent) { ASSERT_TRUE(testParse(input)); Style* style = test::getValue<Style>(&mTable, u"@style/foo"); - ASSERT_NE(style, nullptr); + ASSERT_NE(nullptr, style); AAPT_ASSERT_TRUE(style->parent); AAPT_ASSERT_TRUE(style->parent.value().name); EXPECT_EQ(test::parseNameOrDie(u"@com.app:style/Theme"), style->parent.value().name.value()); @@ -288,7 +288,7 @@ TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedParent) { ASSERT_TRUE(testParse(input)); Style* style = test::getValue<Style>(&mTable, u"@style/foo"); - ASSERT_NE(style, nullptr); + ASSERT_NE(nullptr, style); AAPT_ASSERT_TRUE(style->parent); AAPT_ASSERT_TRUE(style->parent.value().name); EXPECT_EQ(test::parseNameOrDie(u"@android:style/Theme"), style->parent.value().name.value()); @@ -302,7 +302,7 @@ TEST_F(ResourceParserTest, ParseStyleWithPackageAliasedItems) { ASSERT_TRUE(testParse(input)); Style* style = test::getValue<Style>(&mTable, u"@style/foo"); - ASSERT_NE(style, nullptr); + ASSERT_NE(nullptr, style); ASSERT_EQ(1u, style->entries.size()); EXPECT_EQ(test::parseNameOrDie(u"@android:attr/bar"), style->entries[0].key.name.value()); } @@ -312,7 +312,7 @@ TEST_F(ResourceParserTest, ParseStyleWithInferredParent) { ASSERT_TRUE(testParse(input)); Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar"); - ASSERT_NE(style, nullptr); + ASSERT_NE(nullptr, style); AAPT_ASSERT_TRUE(style->parent); AAPT_ASSERT_TRUE(style->parent.value().name); EXPECT_EQ(style->parent.value().name.value(), test::parseNameOrDie(u"@style/foo")); @@ -324,11 +324,21 @@ TEST_F(ResourceParserTest, ParseStyleWithInferredParentOverridenByEmptyParentAtt ASSERT_TRUE(testParse(input)); Style* style = test::getValue<Style>(&mTable, u"@style/foo.bar"); - ASSERT_NE(style, nullptr); + ASSERT_NE(nullptr, style); AAPT_EXPECT_FALSE(style->parent); EXPECT_FALSE(style->parentInferred); } +TEST_F(ResourceParserTest, ParseStyleWithPrivateParentReference) { + std::string input = R"EOF(<style name="foo" parent="*android:style/bar" />)EOF"; + ASSERT_TRUE(testParse(input)); + + Style* style = test::getValue<Style>(&mTable, u"@style/foo"); + ASSERT_NE(nullptr, style); + AAPT_ASSERT_TRUE(style->parent); + EXPECT_TRUE(style->parent.value().privateReference); +} + TEST_F(ResourceParserTest, ParseAutoGeneratedIdReference) { std::string input = "<string name=\"foo\">@+id/bar</string>"; ASSERT_TRUE(testParse(input)); @@ -504,11 +514,15 @@ TEST_F(ResourceParserTest, ParsePublicIdAsDefinition) { } TEST_F(ResourceParserTest, FilterProductsThatDontMatch) { - std::string input = "<string name=\"foo\" product=\"phone\">hi</string>\n" - "<string name=\"foo\" product=\"no-sdcard\">ho</string>\n" - "<string name=\"bar\" product=\"\">wee</string>\n" - "<string name=\"baz\">woo</string>\n"; - ASSERT_TRUE(testParse(input, std::u16string(u"no-sdcard"))); + std::string input = R"EOF( + <string name="foo" product="phone">hi</string> + <string name="foo" product="no-sdcard">ho</string> + <string name="bar" product="">wee</string> + <string name="baz">woo</string> + <string name="bit" product="phablet">hoot</string> + <string name="bot" product="default">yes</string> + )EOF"; + ASSERT_TRUE(testParse(input, { std::u16string(u"no-sdcard"), std::u16string(u"phablet") })); String* fooStr = test::getValue<String>(&mTable, u"@string/foo"); ASSERT_NE(nullptr, fooStr); @@ -516,11 +530,25 @@ TEST_F(ResourceParserTest, FilterProductsThatDontMatch) { EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bar")); EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/baz")); + EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bit")); + EXPECT_NE(nullptr, test::getValue<String>(&mTable, u"@string/bot")); +} + +TEST_F(ResourceParserTest, FilterProductsThatBothMatchInOrder) { + std::string input = R"EOF( + <string name="foo" product="phone">phone</string> + <string name="foo" product="default">default</string> + )EOF"; + ASSERT_TRUE(testParse(input, { std::u16string(u"phone") })); + + String* foo = test::getValue<String>(&mTable, u"@string/foo"); + ASSERT_NE(nullptr, foo); + EXPECT_EQ(std::u16string(u"phone"), *foo->value); } TEST_F(ResourceParserTest, FailWhenProductFilterStripsOutAllVersionsOfResource) { std::string input = "<string name=\"foo\" product=\"tablet\">hello</string>\n"; - ASSERT_FALSE(testParse(input, std::u16string(u"phone"))); + ASSERT_FALSE(testParse(input, { std::u16string(u"phone") })); } TEST_F(ResourceParserTest, AutoIncrementIdsInPublicGroup) { @@ -575,4 +603,14 @@ TEST_F(ResourceParserTest, AddResourcesElementShouldAddEntryWithUndefinedSymbol) EXPECT_EQ(SymbolState::kUndefined, entry->symbolStatus.state); } +TEST_F(ResourceParserTest, ParseItemElementWithFormat) { + std::string input = R"EOF(<item name="foo" type="integer" format="float">0.3</item>)EOF"; + ASSERT_TRUE(testParse(input)); + + BinaryPrimitive* val = test::getValue<BinaryPrimitive>(&mTable, u"@integer/foo"); + ASSERT_NE(nullptr, val); + + EXPECT_EQ(uint32_t(android::Res_value::TYPE_FLOAT), val->value.dataType); +} + } // namespace aapt diff --git a/tools/aapt2/ResourceUtils.cpp b/tools/aapt2/ResourceUtils.cpp index 36c3e702574e..1dc123e45949 100644 --- a/tools/aapt2/ResourceUtils.cpp +++ b/tools/aapt2/ResourceUtils.cpp @@ -176,10 +176,10 @@ bool isAttributeReference(const StringPiece16& str) { /* * Style parent's are a bit different. We accept the following formats: * - * @[package:]style/<entry> - * ?[package:]style/<entry> - * <package>:[style/]<entry> - * [package:style/]<entry> + * @[[*]package:]style/<entry> + * ?[[*]package:]style/<entry> + * <[*]package>:[style/]<entry> + * [[*]package:style/]<entry> */ Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string* outError) { if (str.empty()) { @@ -195,10 +195,11 @@ Maybe<Reference> parseStyleParentReference(const StringPiece16& str, std::string if (name.data()[0] == u'@' || name.data()[0] == u'?') { hasLeadingIdentifiers = true; name = name.substr(1, name.size() - 1); - if (name.data()[0] == u'*') { - privateRef = true; - name = name.substr(1, name.size() - 1); - } + } + + if (name.data()[0] == u'*') { + privateRef = true; + name = name.substr(1, name.size() - 1); } ResourceNameRef ref; diff --git a/tools/aapt2/ResourceUtils_test.cpp b/tools/aapt2/ResourceUtils_test.cpp index 4bbfc32b9b37..88efa6779021 100644 --- a/tools/aapt2/ResourceUtils_test.cpp +++ b/tools/aapt2/ResourceUtils_test.cpp @@ -157,6 +157,11 @@ TEST(ResourceUtilsTest, ParseStyleParentReference) { ref = ResourceUtils::parseStyleParentReference(u"foo", &errStr); AAPT_ASSERT_TRUE(ref); EXPECT_EQ(ref.value().name.value(), kStyleFooName); + + ref = ResourceUtils::parseStyleParentReference(u"*android:style/foo", &errStr); + AAPT_ASSERT_TRUE(ref); + EXPECT_EQ(ref.value().name.value(), kAndroidStyleFooName); + EXPECT_TRUE(ref.value().privateReference); } } // namespace aapt diff --git a/tools/aapt2/ResourceValues.cpp b/tools/aapt2/ResourceValues.cpp index 04c375f5f974..b93e6d889ad0 100644 --- a/tools/aapt2/ResourceValues.cpp +++ b/tools/aapt2/ResourceValues.cpp @@ -36,10 +36,6 @@ void BaseItem<Derived>::accept(RawValueVisitor* visitor) { visitor->visit(static_cast<Derived*>(this)); } -bool Value::isWeak() const { - return false; -} - RawString::RawString(const StringPool::Ref& ref) : value(ref) { } @@ -101,10 +97,6 @@ void Reference::print(std::ostream* out) const { } } -bool Id::isWeak() const { - return true; -} - bool Id::flatten(android::Res_value* out) const { out->dataType = android::Res_value::TYPE_INT_BOOLEAN; out->data = util::hostToDevice32(0); @@ -119,7 +111,15 @@ 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), mTranslateable(true) { +} + +void String::setTranslateable(bool val) { + mTranslateable = val; +} + +bool String::isTranslateable() const { + return mTranslateable; } bool String::flatten(android::Res_value* outValue) const { @@ -144,7 +144,15 @@ void String::print(std::ostream* out) const { *out << "(string) \"" << *value << "\""; } -StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref) { +StyledString::StyledString(const StringPool::StyleRef& ref) : value(ref), mTranslateable(true) { +} + +void StyledString::setTranslateable(bool val) { + mTranslateable = val; +} + +bool StyledString::isTranslateable() const { + return mTranslateable; } bool StyledString::flatten(android::Res_value* outValue) const { @@ -238,13 +246,10 @@ void BinaryPrimitive::print(std::ostream* out) const { } Attribute::Attribute(bool w, uint32_t t) : - weak(w), typeMask(t), + typeMask(t), minInt(std::numeric_limits<int32_t>::min()), maxInt(std::numeric_limits<int32_t>::max()) { -} - -bool Attribute::isWeak() const { - return weak; + mWeak = w; } Attribute* Attribute::clone(StringPool* /*newPool*/) const { @@ -359,7 +364,7 @@ void Attribute::print(std::ostream* out) const { << "]"; } - if (weak) { + if (isWeak()) { *out << " [weak]"; } } @@ -457,6 +462,9 @@ Style* Style::clone(StringPool* newPool) const { void Style::print(std::ostream* out) const { *out << "(style) "; if (parent && parent.value().name) { + if (parent.value().privateReference) { + *out << "*"; + } *out << parent.value().name.value(); } *out << " [" diff --git a/tools/aapt2/ResourceValues.h b/tools/aapt2/ResourceValues.h index a03828206c91..8e317dbcd1b1 100644 --- a/tools/aapt2/ResourceValues.h +++ b/tools/aapt2/ResourceValues.h @@ -43,9 +43,15 @@ struct Value { /** * Whether this value is weak and can be overridden without - * warning or error. Default for base class is false. + * warning or error. Default is false. */ - virtual bool isWeak() const; + bool isWeak() const { + return mWeak; + } + + void setWeak(bool val) { + mWeak = val; + } /** * Returns the source where this value was defined. @@ -95,6 +101,7 @@ struct Value { protected: Source mSource; std::u16string mComment; + bool mWeak = false; }; /** @@ -159,7 +166,7 @@ struct Reference : public BaseItem<Reference> { * An ID resource. Has no real value, just a place holder. */ struct Id : public BaseItem<Id> { - bool isWeak() const override; + Id() { mWeak = true; } bool flatten(android::Res_value* out) const override; Id* clone(StringPool* newPool) const override; void print(std::ostream* out) const override; @@ -185,9 +192,17 @@ struct String : public BaseItem<String> { String(const StringPool::Ref& ref); + // Whether the string is marked as translateable. This does not persist when flattened. + // It is only used during compilation phase. + void setTranslateable(bool val); + bool isTranslateable() const; + bool flatten(android::Res_value* outValue) const override; String* clone(StringPool* newPool) const override; void print(std::ostream* out) const override; + +private: + bool mTranslateable; }; struct StyledString : public BaseItem<StyledString> { @@ -195,9 +210,17 @@ struct StyledString : public BaseItem<StyledString> { StyledString(const StringPool::StyleRef& ref); + // Whether the string is marked as translateable. This does not persist when flattened. + // It is only used during compilation phase. + void setTranslateable(bool val); + bool isTranslateable() const; + bool flatten(android::Res_value* outValue) const override; StyledString* clone(StringPool* newPool) const override; void print(std::ostream* out) const override; + +private: + bool mTranslateable; }; struct FileReference : public BaseItem<FileReference> { @@ -232,7 +255,6 @@ struct Attribute : public BaseValue<Attribute> { uint32_t value; }; - bool weak; uint32_t typeMask; int32_t minInt; int32_t maxInt; @@ -240,7 +262,6 @@ struct Attribute : public BaseValue<Attribute> { Attribute(bool w, uint32_t t = 0u); - bool isWeak() const override; Attribute* clone(StringPool* newPool) const override; void printMask(std::ostream* out) const; void print(std::ostream* out) const override; diff --git a/tools/aapt2/compile/Compile.cpp b/tools/aapt2/compile/Compile.cpp index 90e35d52788c..b3b0f65e54da 100644 --- a/tools/aapt2/compile/Compile.cpp +++ b/tools/aapt2/compile/Compile.cpp @@ -21,6 +21,7 @@ #include "ResourceTable.h" #include "compile/IdAssigner.h" #include "compile/Png.h" +#include "compile/PseudolocaleGenerator.h" #include "compile/XmlIdCollector.h" #include "flatten/Archive.h" #include "flatten/FileExportWriter.h" @@ -104,7 +105,8 @@ static Maybe<ResourcePathData> extractResourcePathData(const std::string& path, struct CompileOptions { std::string outputPath; Maybe<std::string> resDir; - Maybe<std::u16string> product; + std::vector<std::u16string> products; + bool pseudolocalize = false; bool verbose = false; }; @@ -189,7 +191,7 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options, xml::XmlPullParser xmlParser(fin); ResourceParserOptions parserOptions; - parserOptions.product = options.product; + parserOptions.products = options.products; // If the filename includes donottranslate, then the default translatable is false. parserOptions.translatable = pathData.name.find(u"donottranslate") == std::string::npos; @@ -203,6 +205,16 @@ static bool compileTable(IAaptContext* context, const CompileOptions& options, fin.close(); } + if (options.pseudolocalize) { + // Generate pseudo-localized strings (en-XA and ar-XB). + // These are created as weak symbols, and are only generated from default configuration + // strings and plurals. + PseudolocaleGenerator pseudolocaleGenerator; + if (!pseudolocaleGenerator.consume(context, &table)) { + return false; + } + } + // Ensure we have the compilation package at least. table.createPackage(context->getCompilationPackage()); @@ -418,18 +430,23 @@ public: int compile(const std::vector<StringPiece>& args) { CompileOptions options; - Maybe<std::string> product; + Maybe<std::string> productList; Flags flags = Flags() .requiredFlag("-o", "Output path", &options.outputPath) - .optionalFlag("--product", "Product type to compile", &product) + .optionalFlag("--product", "Comma separated list of product types to compile", + &productList) .optionalFlag("--dir", "Directory to scan for resources", &options.resDir) + .optionalSwitch("--pseudo-localize", "Generate resources for pseudo-locales " + "(en-XA and ar-XB)", &options.pseudolocalize) .optionalSwitch("-v", "Enables verbose logging", &options.verbose); if (!flags.parse("aapt2 compile", args, &std::cerr)) { return 1; } - if (product) { - options.product = util::utf8ToUtf16(product.value()); + if (productList) { + for (StringPiece part : util::tokenize<char>(productList.value(), ',')) { + options.products.push_back(util::utf8ToUtf16(part)); + } } CompileContext context; diff --git a/tools/aapt2/compile/PseudolocaleGenerator.cpp b/tools/aapt2/compile/PseudolocaleGenerator.cpp new file mode 100644 index 000000000000..2963d135cbca --- /dev/null +++ b/tools/aapt2/compile/PseudolocaleGenerator.cpp @@ -0,0 +1,261 @@ +/* + * 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. + */ + +#include "ResourceTable.h" +#include "ResourceValues.h" +#include "ValueVisitor.h" +#include "compile/PseudolocaleGenerator.h" +#include "compile/Pseudolocalizer.h" +#include "util/Comparators.h" + +namespace aapt { + +std::unique_ptr<StyledString> pseudolocalizeStyledString(StyledString* string, + Pseudolocalizer::Method method, + StringPool* pool) { + Pseudolocalizer localizer(method); + + const StringPiece16 originalText = *string->value->str; + + StyleString localized; + + // Copy the spans. We will update their offsets when we localize. + localized.spans.reserve(string->value->spans.size()); + for (const StringPool::Span& span : string->value->spans) { + localized.spans.push_back(Span{ *span.name, span.firstChar, span.lastChar }); + } + + // The ranges are all represented with a single value. This is the start of one range and + // end of another. + struct Range { + size_t start; + + // Once the new string is localized, these are the pointers to the spans to adjust. + // Since this struct represents the start of one range and end of another, we have + // the two pointers respectively. + uint32_t* updateStart; + uint32_t* updateEnd; + }; + + auto cmp = [](const Range& r, size_t index) -> bool { + return r.start < index; + }; + + // Construct the ranges. The ranges are represented like so: [0, 2, 5, 7] + // The ranges are the spaces in between. In this example, with a total string length of 9, + // the vector represents: (0,1], (2,4], (5,6], (7,9] + // + std::vector<Range> ranges; + ranges.push_back(Range{ 0 }); + ranges.push_back(Range{ originalText.size() - 1 }); + for (size_t i = 0; i < string->value->spans.size(); i++) { + const StringPool::Span& span = string->value->spans[i]; + + // Insert or update the Range marker for the start of this span. + auto iter = std::lower_bound(ranges.begin(), ranges.end(), span.firstChar, cmp); + if (iter != ranges.end() && iter->start == span.firstChar) { + iter->updateStart = &localized.spans[i].firstChar; + } else { + ranges.insert(iter, + Range{ span.firstChar, &localized.spans[i].firstChar, nullptr }); + } + + // Insert or update the Range marker for the end of this span. + iter = std::lower_bound(ranges.begin(), ranges.end(), span.lastChar, cmp); + if (iter != ranges.end() && iter->start == span.lastChar) { + iter->updateEnd = &localized.spans[i].lastChar; + } else { + ranges.insert(iter, + Range{ span.lastChar, nullptr, &localized.spans[i].lastChar }); + } + } + + localized.str += localizer.start(); + + // Iterate over the ranges and localize each section. + for (size_t i = 0; i < ranges.size(); i++) { + const size_t start = ranges[i].start; + size_t len = originalText.size() - start; + if (i + 1 < ranges.size()) { + len = ranges[i + 1].start - start; + } + + if (ranges[i].updateStart) { + *ranges[i].updateStart = localized.str.size(); + } + + if (ranges[i].updateEnd) { + *ranges[i].updateEnd = localized.str.size(); + } + + localized.str += localizer.text(originalText.substr(start, len)); + } + + localized.str += localizer.end(); + + std::unique_ptr<StyledString> localizedString = util::make_unique<StyledString>( + pool->makeRef(localized)); + localizedString->setSource(string->getSource()); + return localizedString; +} + +namespace { + +struct Visitor : public RawValueVisitor { + StringPool* mPool; + Pseudolocalizer::Method mMethod; + Pseudolocalizer mLocalizer; + + // Either value or item will be populated upon visiting the value. + std::unique_ptr<Value> mValue; + std::unique_ptr<Item> mItem; + + Visitor(StringPool* pool, Pseudolocalizer::Method method) : + mPool(pool), mMethod(method), mLocalizer(method) { + } + + void visit(Array* array) override { + std::unique_ptr<Array> localized = util::make_unique<Array>(); + localized->items.resize(array->items.size()); + for (size_t i = 0; i < array->items.size(); i++) { + Visitor subVisitor(mPool, mMethod); + array->items[i]->accept(&subVisitor); + if (subVisitor.mItem) { + localized->items[i] = std::move(subVisitor.mItem); + } else { + localized->items[i] = std::unique_ptr<Item>(array->items[i]->clone(mPool)); + } + } + localized->setSource(array->getSource()); + localized->setWeak(true); + mValue = std::move(localized); + } + + void visit(Plural* plural) override { + std::unique_ptr<Plural> localized = util::make_unique<Plural>(); + for (size_t i = 0; i < plural->values.size(); i++) { + Visitor subVisitor(mPool, mMethod); + if (plural->values[i]) { + plural->values[i]->accept(&subVisitor); + if (subVisitor.mValue) { + localized->values[i] = std::move(subVisitor.mItem); + } else { + localized->values[i] = std::unique_ptr<Item>(plural->values[i]->clone(mPool)); + } + } + } + localized->setSource(plural->getSource()); + localized->setWeak(true); + mValue = std::move(localized); + } + + void visit(String* string) override { + if (!string->isTranslateable()) { + return; + } + + std::u16string result = mLocalizer.start() + mLocalizer.text(*string->value) + + mLocalizer.end(); + std::unique_ptr<String> localized = util::make_unique<String>(mPool->makeRef(result)); + localized->setSource(string->getSource()); + localized->setWeak(true); + mItem = std::move(localized); + } + + void visit(StyledString* string) override { + if (!string->isTranslateable()) { + return; + } + + mItem = pseudolocalizeStyledString(string, mMethod, mPool); + mItem->setWeak(true); + } +}; + +ConfigDescription modifyConfigForPseudoLocale(const ConfigDescription& base, + Pseudolocalizer::Method m) { + ConfigDescription modified = base; + switch (m) { + case Pseudolocalizer::Method::kAccent: + modified.language[0] = 'e'; + modified.language[1] = 'n'; + modified.country[0] = 'X'; + modified.country[1] = 'A'; + break; + + case Pseudolocalizer::Method::kBidi: + modified.language[0] = 'a'; + modified.language[1] = 'r'; + modified.country[0] = 'X'; + modified.country[1] = 'B'; + break; + default: + break; + } + return modified; +} + +void pseudolocalizeIfNeeded(std::vector<ResourceConfigValue>* configValues, + Pseudolocalizer::Method method, StringPool* pool, Value* value) { + Visitor visitor(pool, method); + value->accept(&visitor); + + std::unique_ptr<Value> localizedValue; + if (visitor.mValue) { + localizedValue = std::move(visitor.mValue); + } else if (visitor.mItem) { + localizedValue = std::move(visitor.mItem); + } + + if (localizedValue) { + ConfigDescription pseudolocalizedConfig = modifyConfigForPseudoLocale(ConfigDescription{}, + method); + auto iter = std::lower_bound(configValues->begin(), configValues->end(), + pseudolocalizedConfig, cmp::lessThanConfig); + if (iter == configValues->end() || iter->config != pseudolocalizedConfig) { + // The pseudolocalized config doesn't exist, add it. + configValues->insert(iter, ResourceConfigValue{ pseudolocalizedConfig, + std::move(localizedValue) }); + } + } +} + +} // namespace + +bool PseudolocaleGenerator::consume(IAaptContext* context, ResourceTable* table) { + for (auto& package : table->packages) { + for (auto& type : package->types) { + for (auto& entry : type->entries) { + auto iter = std::lower_bound(entry->values.begin(), entry->values.end(), + ConfigDescription{}, cmp::lessThanConfig); + if (iter != entry->values.end() && iter->config == ConfigDescription{}) { + // Only pseudolocalize the default configuration. + + // The iterator will be invalidated, so grab a pointer to the value. + Value* originalValue = iter->value.get(); + + pseudolocalizeIfNeeded(&entry->values, Pseudolocalizer::Method::kAccent, + &table->stringPool, originalValue); + pseudolocalizeIfNeeded(&entry->values, Pseudolocalizer::Method::kBidi, + &table->stringPool, originalValue); + } + } + } + } + return true; +} + +} // namespace aapt diff --git a/tools/aapt2/compile/PseudolocaleGenerator.h b/tools/aapt2/compile/PseudolocaleGenerator.h new file mode 100644 index 000000000000..4fbc51607595 --- /dev/null +++ b/tools/aapt2/compile/PseudolocaleGenerator.h @@ -0,0 +1,36 @@ +/* + * 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. + */ + +#ifndef AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H +#define AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H + +#include "StringPool.h" +#include "compile/Pseudolocalizer.h" +#include "process/IResourceTableConsumer.h" + +namespace aapt { + +std::unique_ptr<StyledString> pseudolocalizeStyledString(StyledString* string, + Pseudolocalizer::Method method, + StringPool* pool); + +struct PseudolocaleGenerator : public IResourceTableConsumer { + bool consume(IAaptContext* context, ResourceTable* table) override; +}; + +} // namespace aapt + +#endif /* AAPT_COMPILE_PSEUDOLOCALEGENERATOR_H */ diff --git a/tools/aapt2/compile/PseudolocaleGenerator_test.cpp b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp new file mode 100644 index 000000000000..4cb6ea2db565 --- /dev/null +++ b/tools/aapt2/compile/PseudolocaleGenerator_test.cpp @@ -0,0 +1,123 @@ +/* + * 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. + */ + +#include "compile/PseudolocaleGenerator.h" +#include "test/Builders.h" +#include "test/Common.h" +#include "test/Context.h" +#include "util/Util.h" + +#include <androidfw/ResourceTypes.h> +#include <gtest/gtest.h> + +namespace aapt { + +TEST(PseudolocaleGeneratorTest, PseudolocalizeStyledString) { + StringPool pool; + StyleString originalStyle; + originalStyle.str = u"Hello world!"; + originalStyle.spans = { Span{ u"b", 2, 3 }, Span{ u"b", 6, 7 }, Span{ u"i", 1, 10 } }; + + std::unique_ptr<StyledString> newString = pseudolocalizeStyledString( + util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(), + Pseudolocalizer::Method::kNone, &pool); + + EXPECT_EQ(originalStyle.str, *newString->value->str); + ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size()); + + EXPECT_EQ(2u, newString->value->spans[0].firstChar); + EXPECT_EQ(3u, newString->value->spans[0].lastChar); + EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[0].name); + + EXPECT_EQ(6u, newString->value->spans[1].firstChar); + EXPECT_EQ(7u, newString->value->spans[1].lastChar); + EXPECT_EQ(std::u16string(u"b"), *newString->value->spans[1].name); + + EXPECT_EQ(1u, newString->value->spans[2].firstChar); + EXPECT_EQ(10u, newString->value->spans[2].lastChar); + EXPECT_EQ(std::u16string(u"i"), *newString->value->spans[2].name); + + originalStyle.spans.push_back(Span{ u"em", 0, 11u }); + + newString = pseudolocalizeStyledString( + util::make_unique<StyledString>(pool.makeRef(originalStyle)).get(), + Pseudolocalizer::Method::kAccent, &pool); + + EXPECT_EQ(std::u16string(u"[Ĥéļļö ŵöŕļð¡ one two]"), *newString->value->str); + ASSERT_EQ(originalStyle.spans.size(), newString->value->spans.size()); + + EXPECT_EQ(3u, newString->value->spans[0].firstChar); + EXPECT_EQ(4u, newString->value->spans[0].lastChar); + + EXPECT_EQ(7u, newString->value->spans[1].firstChar); + EXPECT_EQ(8u, newString->value->spans[1].lastChar); + + EXPECT_EQ(2u, newString->value->spans[2].firstChar); + EXPECT_EQ(11u, newString->value->spans[2].lastChar); + + EXPECT_EQ(1u, newString->value->spans[3].firstChar); + EXPECT_EQ(12u, newString->value->spans[3].lastChar); +} + +TEST(PseudolocaleGeneratorTest, PseudolocalizeOnlyDefaultConfigs) { + std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder() + .addString(u"@android:string/one", u"one") + .addString(u"@android:string/two", ResourceId{}, test::parseConfigOrDie("en"), u"two") + .addString(u"@android:string/three", u"three") + .addString(u"@android:string/three", ResourceId{}, test::parseConfigOrDie("en-rXA"), + u"three") + .addString(u"@android:string/four", u"four") + .build(); + + String* val = test::getValue<String>(table.get(), u"@android:string/four"); + val->setTranslateable(false); + + std::unique_ptr<IAaptContext> context = test::ContextBuilder().build(); + PseudolocaleGenerator generator; + ASSERT_TRUE(generator.consume(context.get(), table.get())); + + // Normal pseudolocalization should take place. + ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one", + test::parseConfigOrDie("en-rXA"))); + ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/one", + test::parseConfigOrDie("ar-rXB"))); + + // No default config for android:string/two, so no pseudlocales should exist. + ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two", + test::parseConfigOrDie("en-rXA"))); + ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/two", + test::parseConfigOrDie("ar-rXB"))); + + + // Check that we didn't override manual pseudolocalization. + val = test::getValueForConfig<String>(table.get(), u"@android:string/three", + test::parseConfigOrDie("en-rXA")); + ASSERT_NE(nullptr, val); + EXPECT_EQ(std::u16string(u"three"), *val->value); + + ASSERT_NE(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/three", + test::parseConfigOrDie("ar-rXB"))); + + // Check that four's translateable marker was honored. + ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four", + test::parseConfigOrDie("en-rXA"))); + ASSERT_EQ(nullptr, test::getValueForConfig<String>(table.get(), u"@android:string/four", + test::parseConfigOrDie("ar-rXB"))); + +} + +} // namespace aapt + diff --git a/tools/aapt2/compile/Pseudolocalizer.cpp b/tools/aapt2/compile/Pseudolocalizer.cpp new file mode 100644 index 000000000000..eae52d778744 --- /dev/null +++ b/tools/aapt2/compile/Pseudolocalizer.cpp @@ -0,0 +1,394 @@ +/* + * 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. + */ + +#include "compile/Pseudolocalizer.h" +#include "util/Util.h" + +namespace aapt { + +// String basis to generate expansion +static const std::u16string k_expansion_string = u"one two three " + "four five six seven eight nine ten eleven twelve thirteen " + "fourteen fiveteen sixteen seventeen nineteen twenty"; + +// Special unicode characters to override directionality of the words +static const std::u16string k_rlm = u"\u200f"; +static const std::u16string k_rlo = u"\u202e"; +static const std::u16string k_pdf = u"\u202c"; + +// Placeholder marks +static const std::u16string k_placeholder_open = u"\u00bb"; +static const std::u16string k_placeholder_close = u"\u00ab"; + +static const char16_t k_arg_start = u'{'; +static const char16_t k_arg_end = u'}'; + +class PseudoMethodNone : public PseudoMethodImpl { +public: + std::u16string text(const StringPiece16& text) override { return text.toString(); } + std::u16string placeholder(const StringPiece16& text) override { return text.toString(); } +}; + +class PseudoMethodBidi : public PseudoMethodImpl { +public: + std::u16string text(const StringPiece16& text) override; + std::u16string placeholder(const StringPiece16& text) override; +}; + +class PseudoMethodAccent : public PseudoMethodImpl { +public: + PseudoMethodAccent() : mDepth(0), mWordCount(0), mLength(0) {} + std::u16string start() override; + std::u16string end() override; + std::u16string text(const StringPiece16& text) override; + std::u16string placeholder(const StringPiece16& text) override; +private: + size_t mDepth; + size_t mWordCount; + size_t mLength; +}; + +Pseudolocalizer::Pseudolocalizer(Method method) : mLastDepth(0) { + setMethod(method); +} + +void Pseudolocalizer::setMethod(Method method) { + switch (method) { + case Method::kNone: + mImpl = util::make_unique<PseudoMethodNone>(); + break; + case Method::kAccent: + mImpl = util::make_unique<PseudoMethodAccent>(); + break; + case Method::kBidi: + mImpl = util::make_unique<PseudoMethodBidi>(); + break; + } +} + +std::u16string Pseudolocalizer::text(const StringPiece16& text) { + std::u16string out; + size_t depth = mLastDepth; + size_t lastpos, pos; + const size_t length = text.size(); + const char16_t* str = text.data(); + bool escaped = false; + for (lastpos = pos = 0; pos < length; pos++) { + char16_t c = str[pos]; + if (escaped) { + escaped = false; + continue; + } + if (c == '\'') { + escaped = true; + continue; + } + + if (c == k_arg_start) { + depth++; + } else if (c == k_arg_end && depth) { + depth--; + } + + if (mLastDepth != depth || pos == length - 1) { + bool pseudo = ((mLastDepth % 2) == 0); + size_t nextpos = pos; + if (!pseudo || depth == mLastDepth) { + nextpos++; + } + size_t size = nextpos - lastpos; + if (size) { + std::u16string chunk = text.substr(lastpos, size).toString(); + if (pseudo) { + chunk = mImpl->text(chunk); + } else if (str[lastpos] == k_arg_start && str[nextpos - 1] == k_arg_end) { + chunk = mImpl->placeholder(chunk); + } + out.append(chunk); + } + if (pseudo && depth < mLastDepth) { // End of message + out.append(mImpl->end()); + } else if (!pseudo && depth > mLastDepth) { // Start of message + out.append(mImpl->start()); + } + lastpos = nextpos; + mLastDepth = depth; + } + } + return out; +} + +static const char16_t* pseudolocalizeChar(const char16_t c) { + switch (c) { + case 'a': return u"\u00e5"; + case 'b': return u"\u0253"; + case 'c': return u"\u00e7"; + case 'd': return u"\u00f0"; + case 'e': return u"\u00e9"; + case 'f': return u"\u0192"; + case 'g': return u"\u011d"; + case 'h': return u"\u0125"; + case 'i': return u"\u00ee"; + case 'j': return u"\u0135"; + case 'k': return u"\u0137"; + case 'l': return u"\u013c"; + case 'm': return u"\u1e3f"; + case 'n': return u"\u00f1"; + case 'o': return u"\u00f6"; + case 'p': return u"\u00fe"; + case 'q': return u"\u0051"; + case 'r': return u"\u0155"; + case 's': return u"\u0161"; + case 't': return u"\u0163"; + case 'u': return u"\u00fb"; + case 'v': return u"\u0056"; + case 'w': return u"\u0175"; + case 'x': return u"\u0445"; + case 'y': return u"\u00fd"; + case 'z': return u"\u017e"; + case 'A': return u"\u00c5"; + case 'B': return u"\u03b2"; + case 'C': return u"\u00c7"; + case 'D': return u"\u00d0"; + case 'E': return u"\u00c9"; + case 'G': return u"\u011c"; + case 'H': return u"\u0124"; + case 'I': return u"\u00ce"; + case 'J': return u"\u0134"; + case 'K': return u"\u0136"; + case 'L': return u"\u013b"; + case 'M': return u"\u1e3e"; + case 'N': return u"\u00d1"; + case 'O': return u"\u00d6"; + case 'P': return u"\u00de"; + case 'Q': return u"\u0071"; + case 'R': return u"\u0154"; + case 'S': return u"\u0160"; + case 'T': return u"\u0162"; + case 'U': return u"\u00db"; + case 'V': return u"\u03bd"; + case 'W': return u"\u0174"; + case 'X': return u"\u00d7"; + case 'Y': return u"\u00dd"; + case 'Z': return u"\u017d"; + case '!': return u"\u00a1"; + case '?': return u"\u00bf"; + case '$': return u"\u20ac"; + default: return NULL; + } +} + +static bool isPossibleNormalPlaceholderEnd(const char16_t c) { + switch (c) { + case 's': return true; + case 'S': return true; + case 'c': return true; + case 'C': return true; + case 'd': return true; + case 'o': return true; + case 'x': return true; + case 'X': return true; + case 'f': return true; + case 'e': return true; + case 'E': return true; + case 'g': return true; + case 'G': return true; + case 'a': return true; + case 'A': return true; + case 'b': return true; + case 'B': return true; + case 'h': return true; + case 'H': return true; + case '%': return true; + case 'n': return true; + default: return false; + } +} + +static std::u16string pseudoGenerateExpansion(const unsigned int length) { + std::u16string result = k_expansion_string; + const char16_t* s = result.data(); + if (result.size() < length) { + result += u" "; + result += pseudoGenerateExpansion(length - result.size()); + } else { + int ext = 0; + // Should contain only whole words, so looking for a space + for (unsigned int i = length + 1; i < result.size(); ++i) { + ++ext; + if (s[i] == ' ') { + break; + } + } + result = result.substr(0, length + ext); + } + return result; +} + +std::u16string PseudoMethodAccent::start() { + std::u16string result; + if (mDepth == 0) { + result = u"["; + } + mWordCount = mLength = 0; + mDepth++; + return result; +} + +std::u16string PseudoMethodAccent::end() { + std::u16string result; + if (mLength) { + result += u" "; + result += pseudoGenerateExpansion(mWordCount > 3 ? mLength : mLength / 2); + } + mWordCount = mLength = 0; + mDepth--; + if (mDepth == 0) { + result += u"]"; + } + return result; +} + +/** + * Converts characters so they look like they've been localized. + * + * Note: This leaves placeholder syntax untouched. + */ +std::u16string PseudoMethodAccent::text(const StringPiece16& source) +{ + const char16_t* s = source.data(); + std::u16string result; + const size_t I = source.size(); + bool lastspace = true; + for (size_t i = 0; i < I; i++) { + char16_t c = s[i]; + if (c == '%') { + // Placeholder syntax, no need to pseudolocalize + std::u16string chunk; + bool end = false; + chunk.append(&c, 1); + while (!end && i < I) { + ++i; + c = s[i]; + chunk.append(&c, 1); + if (isPossibleNormalPlaceholderEnd(c)) { + end = true; + } else if (c == 't') { + ++i; + c = s[i]; + chunk.append(&c, 1); + end = true; + } + } + // Treat chunk as a placeholder unless it ends with %. + result += ((c == '%') ? chunk : placeholder(chunk)); + } else if (c == '<' || c == '&') { + // html syntax, no need to pseudolocalize + bool tag_closed = false; + while (!tag_closed && i < I) { + if (c == '&') { + std::u16string escapeText; + escapeText.append(&c, 1); + bool end = false; + size_t htmlCodePos = i; + while (!end && htmlCodePos < I) { + ++htmlCodePos; + c = s[htmlCodePos]; + escapeText.append(&c, 1); + // Valid html code + if (c == ';') { + end = true; + i = htmlCodePos; + } + // Wrong html code + else if (!((c == '#' || + (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9')))) { + end = true; + } + } + result += escapeText; + if (escapeText != u"<") { + tag_closed = true; + } + continue; + } + if (c == '>') { + tag_closed = true; + result.append(&c, 1); + continue; + } + result.append(&c, 1); + i++; + c = s[i]; + } + } else { + // This is a pure text that should be pseudolocalized + const char16_t* p = pseudolocalizeChar(c); + if (p != nullptr) { + result += p; + } else { + bool space = util::isspace16(c); + if (lastspace && !space) { + mWordCount++; + } + lastspace = space; + result.append(&c, 1); + } + // Count only pseudolocalizable chars and delimiters + mLength++; + } + } + return result; +} + +std::u16string PseudoMethodAccent::placeholder(const StringPiece16& source) { + // Surround a placeholder with brackets + return k_placeholder_open + source.toString() + k_placeholder_close; +} + +std::u16string PseudoMethodBidi::text(const StringPiece16& source) { + const char16_t* s = source.data(); + std::u16string result; + bool lastspace = true; + bool space = true; + for (size_t i = 0; i < source.size(); i++) { + char16_t c = s[i]; + space = util::isspace16(c); + if (lastspace && !space) { + // Word start + result += k_rlm + k_rlo; + } else if (!lastspace && space) { + // Word end + result += k_pdf + k_rlm; + } + lastspace = space; + result.append(&c, 1); + } + if (!lastspace) { + // End of last word + result += k_pdf + k_rlm; + } + return result; +} + +std::u16string PseudoMethodBidi::placeholder(const StringPiece16& source) { + // Surround a placeholder with directionality change sequence + return k_rlm + k_rlo + source.toString() + k_pdf + k_rlm; +} + +} // namespace aapt diff --git a/tools/aapt2/compile/Pseudolocalizer.h b/tools/aapt2/compile/Pseudolocalizer.h new file mode 100644 index 000000000000..8818c1725617 --- /dev/null +++ b/tools/aapt2/compile/Pseudolocalizer.h @@ -0,0 +1,58 @@ +/* + * 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. + */ + +#ifndef AAPT_COMPILE_PSEUDOLOCALIZE_H +#define AAPT_COMPILE_PSEUDOLOCALIZE_H + +#include "ResourceValues.h" +#include "StringPool.h" +#include "util/StringPiece.h" + +#include <android-base/macros.h> +#include <memory> + +namespace aapt { + +class PseudoMethodImpl { +public: + virtual ~PseudoMethodImpl() {} + virtual std::u16string start() { return {}; } + virtual std::u16string end() { return {}; } + virtual std::u16string text(const StringPiece16& text) = 0; + virtual std::u16string placeholder(const StringPiece16& text) = 0; +}; + +class Pseudolocalizer { +public: + enum class Method { + kNone, + kAccent, + kBidi, + }; + + Pseudolocalizer(Method method); + void setMethod(Method method); + std::u16string start() { return mImpl->start(); } + std::u16string end() { return mImpl->end(); } + std::u16string text(const StringPiece16& text); +private: + std::unique_ptr<PseudoMethodImpl> mImpl; + size_t mLastDepth; +}; + +} // namespace aapt + +#endif /* AAPT_COMPILE_PSEUDOLOCALIZE_H */ diff --git a/tools/aapt2/compile/Pseudolocalizer_test.cpp b/tools/aapt2/compile/Pseudolocalizer_test.cpp new file mode 100644 index 000000000000..b0bc2c10fbe0 --- /dev/null +++ b/tools/aapt2/compile/Pseudolocalizer_test.cpp @@ -0,0 +1,227 @@ +/* + * 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. + */ + +#include "compile/Pseudolocalizer.h" +#include "util/Util.h" + +#include <androidfw/ResourceTypes.h> +#include <gtest/gtest.h> + +namespace aapt { + +// In this context, 'Axis' represents a particular field in the configuration, +// such as language or density. + +static ::testing::AssertionResult simpleHelper(const char* input, const char* expected, + Pseudolocalizer::Method method) { + Pseudolocalizer pseudo(method); + std::string result = util::utf16ToUtf8( + pseudo.start() + pseudo.text(util::utf8ToUtf16(input)) + pseudo.end()); + if (StringPiece(expected) != result) { + return ::testing::AssertionFailure() << expected << " != " << result; + } + return ::testing::AssertionSuccess(); +} + +static ::testing::AssertionResult compoundHelper(const char* in1, const char* in2, const char *in3, + const char* expected, + Pseudolocalizer::Method method) { + Pseudolocalizer pseudo(method); + std::string result = util::utf16ToUtf8(pseudo.start() + + pseudo.text(util::utf8ToUtf16(in1)) + + pseudo.text(util::utf8ToUtf16(in2)) + + pseudo.text(util::utf8ToUtf16(in3)) + + pseudo.end()); + if (StringPiece(expected) != result) { + return ::testing::AssertionFailure() << expected << " != " << result; + } + return ::testing::AssertionSuccess(); +} + +TEST(PseudolocalizerTest, NoPseudolocalization) { + EXPECT_TRUE(simpleHelper("", "", Pseudolocalizer::Method::kNone)); + EXPECT_TRUE(simpleHelper("Hello, world", "Hello, world", Pseudolocalizer::Method::kNone)); + + EXPECT_TRUE(compoundHelper("Hello,", " world", "", + "Hello, world", Pseudolocalizer::Method::kNone)); +} + +TEST(PseudolocalizerTest, PlaintextAccent) { + EXPECT_TRUE(simpleHelper("", "[]", Pseudolocalizer::Method::kAccent)); + EXPECT_TRUE(simpleHelper("Hello, world", + "[Ĥéļļö, ŵöŕļð one two]", Pseudolocalizer::Method::kAccent)); + + EXPECT_TRUE(simpleHelper("Hello, %1d", + "[Ĥéļļö, »%1d« one two]", Pseudolocalizer::Method::kAccent)); + + EXPECT_TRUE(simpleHelper("Battery %1d%%", + "[βåţţéŕý »%1d«%% one two]", Pseudolocalizer::Method::kAccent)); + + EXPECT_TRUE(compoundHelper("", "", "", "[]", Pseudolocalizer::Method::kAccent)); + EXPECT_TRUE(compoundHelper("Hello,", " world", "", + "[Ĥéļļö, ŵöŕļð one two]", Pseudolocalizer::Method::kAccent)); +} + +TEST(PseudolocalizerTest, PlaintextBidi) { + EXPECT_TRUE(simpleHelper("", "", Pseudolocalizer::Method::kBidi)); + EXPECT_TRUE(simpleHelper("word", + "\xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f", + Pseudolocalizer::Method::kBidi)); + EXPECT_TRUE(simpleHelper(" word ", + " \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f ", + Pseudolocalizer::Method::kBidi)); + EXPECT_TRUE(simpleHelper(" word ", + " \xe2\x80\x8f\xE2\x80\xaeword\xE2\x80\xac\xe2\x80\x8f ", + Pseudolocalizer::Method::kBidi)); + EXPECT_TRUE(simpleHelper("hello\n world\n", + "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \ + " \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n", + Pseudolocalizer::Method::kBidi)); + EXPECT_TRUE(compoundHelper("hello", "\n ", " world\n", + "\xe2\x80\x8f\xE2\x80\xaehello\xE2\x80\xac\xe2\x80\x8f\n" \ + " \xe2\x80\x8f\xE2\x80\xaeworld\xE2\x80\xac\xe2\x80\x8f\n", + Pseudolocalizer::Method::kBidi)); +} + +TEST(PseudolocalizerTest, SimpleICU) { + // Single-fragment messages + EXPECT_TRUE(simpleHelper("{placeholder}", "[»{placeholder}«]", + Pseudolocalizer::Method::kAccent)); + EXPECT_TRUE(simpleHelper("{USER} is offline", + "[»{USER}« îš öƒƒļîñé one two]", Pseudolocalizer::Method::kAccent)); + EXPECT_TRUE(simpleHelper("Copy from {path1} to {path2}", + "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]", + Pseudolocalizer::Method::kAccent)); + EXPECT_TRUE(simpleHelper("Today is {1,date} {1,time}", + "[Ţöðåý îš »{1,date}« »{1,time}« one two]", + Pseudolocalizer::Method::kAccent)); + + // Multi-fragment messages + EXPECT_TRUE(compoundHelper("{USER}", " ", "is offline", + "[»{USER}« îš öƒƒļîñé one two]", + Pseudolocalizer::Method::kAccent)); + EXPECT_TRUE(compoundHelper("Copy from ", "{path1}", " to {path2}", + "[Çöþý ƒŕöḿ »{path1}« ţö »{path2}« one two three]", + Pseudolocalizer::Method::kAccent)); +} + +TEST(PseudolocalizerTest, ICUBidi) { + // Single-fragment messages + EXPECT_TRUE(simpleHelper("{placeholder}", + "\xe2\x80\x8f\xE2\x80\xae{placeholder}\xE2\x80\xac\xe2\x80\x8f", + Pseudolocalizer::Method::kBidi)); + EXPECT_TRUE(simpleHelper( + "{COUNT, plural, one {one} other {other}}", + "{COUNT, plural, " \ + "one {\xe2\x80\x8f\xE2\x80\xaeone\xE2\x80\xac\xe2\x80\x8f} " \ + "other {\xe2\x80\x8f\xE2\x80\xaeother\xE2\x80\xac\xe2\x80\x8f}}", + Pseudolocalizer::Method::kBidi)); +} + +TEST(PseudolocalizerTest, Escaping) { + // Single-fragment messages + EXPECT_TRUE(simpleHelper("'{USER'} is offline", + "['{ÛŠÉŔ'} îš öƒƒļîñé one two three]", + Pseudolocalizer::Method::kAccent)); + + // Multi-fragment messages + EXPECT_TRUE(compoundHelper("'{USER}", " ", "''is offline", + "['{ÛŠÉŔ} ''îš öƒƒļîñé one two three]", + Pseudolocalizer::Method::kAccent)); +} + +TEST(PseudolocalizerTest, PluralsAndSelects) { + EXPECT_TRUE(simpleHelper( + "{COUNT, plural, one {Delete a file} other {Delete {COUNT} files}}", + "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \ + "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]", + Pseudolocalizer::Method::kAccent)); + + EXPECT_TRUE(simpleHelper( + "Distance is {COUNT, plural, one {# mile} other {# miles}}", + "[Ðîšţåñçé îš {COUNT, plural, one {# ḿîļé one two} " \ + "other {# ḿîļéš one two}}]", + Pseudolocalizer::Method::kAccent)); + + EXPECT_TRUE(simpleHelper( + "{1, select, female {{1} added you} " \ + "male {{1} added you} other {{1} added you}}", + "[{1, select, female {»{1}« åððéð ýöû one two} " \ + "male {»{1}« åððéð ýöû one two} other {»{1}« åððéð ýöû one two}}]", + Pseudolocalizer::Method::kAccent)); + + EXPECT_TRUE(compoundHelper( + "{COUNT, plural, one {Delete a file} " \ + "other {Delete ", "{COUNT}", " files}}", + "[{COUNT, plural, one {Ðéļéţé å ƒîļé one two} " \ + "other {Ðéļéţé »{COUNT}« ƒîļéš one two}}]", + Pseudolocalizer::Method::kAccent)); +} + +TEST(PseudolocalizerTest, NestedICU) { + EXPECT_TRUE(simpleHelper( + "{person, select, " \ + "female {" \ + "{num_circles, plural," \ + "=0{{person} didn't add you to any of her circles.}" \ + "=1{{person} added you to one of her circles.}" \ + "other{{person} added you to her # circles.}}}" \ + "male {" \ + "{num_circles, plural," \ + "=0{{person} didn't add you to any of his circles.}" \ + "=1{{person} added you to one of his circles.}" \ + "other{{person} added you to his # circles.}}}" \ + "other {" \ + "{num_circles, plural," \ + "=0{{person} didn't add you to any of their circles.}" \ + "=1{{person} added you to one of their circles.}" \ + "other{{person} added you to their # circles.}}}}", + "[{person, select, " \ + "female {" \ + "{num_circles, plural," \ + "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥéŕ çîŕçļéš." \ + " one two three four five}" \ + "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥéŕ çîŕçļéš." \ + " one two three four}" \ + "other{»{person}« åððéð ýöû ţö ĥéŕ # çîŕçļéš." \ + " one two three four}}}" \ + "male {" \ + "{num_circles, plural," \ + "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ĥîš çîŕçļéš." \ + " one two three four five}" \ + "=1{»{person}« åððéð ýöû ţö öñé öƒ ĥîš çîŕçļéš." \ + " one two three four}" \ + "other{»{person}« åððéð ýöû ţö ĥîš # çîŕçļéš." \ + " one two three four}}}" \ + "other {{num_circles, plural," \ + "=0{»{person}« ðîðñ'ţ åðð ýöû ţö åñý öƒ ţĥéîŕ çîŕçļéš." \ + " one two three four five}" \ + "=1{»{person}« åððéð ýöû ţö öñé öƒ ţĥéîŕ çîŕçļéš." \ + " one two three four}" \ + "other{»{person}« åððéð ýöû ţö ţĥéîŕ # çîŕçļéš." \ + " one two three four}}}}]", + Pseudolocalizer::Method::kAccent)); +} + +TEST(PseudolocalizerTest, RedefineMethod) { + Pseudolocalizer pseudo(Pseudolocalizer::Method::kAccent); + std::u16string result = pseudo.text(u"Hello, "); + pseudo.setMethod(Pseudolocalizer::Method::kNone); + result += pseudo.text(u"world!"); + ASSERT_EQ(StringPiece("Ĥéļļö, world!"), util::utf16ToUtf8(result)); +} + +} // namespace aapt diff --git a/tools/aapt2/flatten/TableFlattener.cpp b/tools/aapt2/flatten/TableFlattener.cpp index a2f53e15df69..26d7c2ca055c 100644 --- a/tools/aapt2/flatten/TableFlattener.cpp +++ b/tools/aapt2/flatten/TableFlattener.cpp @@ -113,8 +113,7 @@ struct MapFlattenVisitor : public RawValueVisitor { bool mUseExtendedChunks; size_t mEntryCount = 0; - Maybe<uint32_t> mParentIdent; - Maybe<ResourceNameRef> mParentName; + const Reference* mParent = nullptr; MapFlattenVisitor(SymbolWriter* symbols, FlatEntry* entry, BigBuffer* buffer, StringPool* sourcePool, StringPool* commentPool, @@ -227,13 +226,8 @@ struct MapFlattenVisitor : public RawValueVisitor { void visit(Style* style) override { if (style->parent) { - bool privateRef = style->parent.value().privateReference && mUseExtendedChunks; - if (!style->parent.value().id || privateRef) { - assert(style->parent.value().name && "reference must have a name"); - mParentName = style->parent.value().name; - } else { - mParentIdent = style->parent.value().id.value().id; - } + // Parents are treated a bit differently, so record the existence and move on. + mParent = &style->parent.value(); } // Sort the style. @@ -427,11 +421,16 @@ private: mOptions.useExtendedChunks); entry->value->accept(&visitor); outEntry->count = util::hostToDevice32(visitor.mEntryCount); - if (visitor.mParentName) { - mSymbols->addSymbol(visitor.mParentName.value(), - beforeEntry + offsetof(ResTable_entry_ext, parent)); - } else if (visitor.mParentIdent) { - outEntry->parent.ident = util::hostToDevice32(visitor.mParentIdent.value()); + if (visitor.mParent) { + const bool forceSymbol = visitor.mParent->privateReference && + mOptions.useExtendedChunks; + if (!visitor.mParent->id || forceSymbol) { + assert(visitor.mParent->name && "reference must have a name"); + mSymbols->addSymbol(*visitor.mParent, + beforeEntry + offsetof(ResTable_entry_ext, parent)); + } else { + outEntry->parent.ident = util::hostToDevice32(visitor.mParent->id.value().id); + } } } return true; diff --git a/tools/aapt2/java/ProguardRules.cpp b/tools/aapt2/java/ProguardRules.cpp index c0968545ad81..c610bb0f2ff2 100644 --- a/tools/aapt2/java/ProguardRules.cpp +++ b/tools/aapt2/java/ProguardRules.cpp @@ -227,14 +227,14 @@ bool collectProguardRules(const Source& source, xml::XmlResource* res, KeepSet* bool writeKeepSet(std::ostream* out, const KeepSet& keepSet) { for (const auto& entry : keepSet.mKeepSet) { for (const Source& source : entry.second) { - *out << "// Referenced at " << source << "\n"; + *out << "# Referenced at " << source << "\n"; } *out << "-keep class " << entry.first << " { <init>(...); }\n" << std::endl; } for (const auto& entry : keepSet.mKeepMethodSet) { for (const Source& source : entry.second) { - *out << "// Referenced at " << source << "\n"; + *out << "# Referenced at " << source << "\n"; } *out << "-keepclassmembers class * { *** " << entry.first << "(...); }\n" << std::endl; } diff --git a/tools/aapt2/test/Builders.h b/tools/aapt2/test/Builders.h index f8e3d031fb67..93a11b9334a8 100644 --- a/tools/aapt2/test/Builders.h +++ b/tools/aapt2/test/Builders.h @@ -68,6 +68,12 @@ public: return addValue(name, id, util::make_unique<String>(mTable->stringPool.makeRef(str))); } + ResourceTableBuilder& addString(const StringPiece16& name, const ResourceId id, + const ConfigDescription& config, const StringPiece16& str) { + return addValue(name, id, config, + util::make_unique<String>(mTable->stringPool.makeRef(str))); + } + ResourceTableBuilder& addFileReference(const StringPiece16& name, const StringPiece16& path) { return addFileReference(name, {}, path); } diff --git a/tools/aapt2/unflatten/BinaryResourceParser.cpp b/tools/aapt2/unflatten/BinaryResourceParser.cpp index 21e476fc9c29..6b7a63cf7bf2 100644 --- a/tools/aapt2/unflatten/BinaryResourceParser.cpp +++ b/tools/aapt2/unflatten/BinaryResourceParser.cpp @@ -585,6 +585,13 @@ bool BinaryResourceParser::parseType(const ResourceTablePackage* package, source.path = path.toString(); } source.line = util::deviceToHost32(sourceBlock->line); + + if (Style* style = valueCast<Style>(resourceValue.get())) { + // The parent's source is the same as the resource itself, set it here. + if (style->parent) { + style->parent.value().setSource(source); + } + } } StringPiece16 comment = util::getString(mSourcePool, diff --git a/tools/aapt2/util/ImmutableMap.h b/tools/aapt2/util/ImmutableMap.h new file mode 100644 index 000000000000..b1f9e9d2fb57 --- /dev/null +++ b/tools/aapt2/util/ImmutableMap.h @@ -0,0 +1,84 @@ +/* + * 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. + */ + +#ifndef AAPT_UTIL_IMMUTABLEMAP_H +#define AAPT_UTIL_IMMUTABLEMAP_H + +#include "util/TypeTraits.h" + +#include <utility> +#include <vector> + +namespace aapt { + +template <typename TKey, typename TValue> +class ImmutableMap { + static_assert(is_comparable<TKey, TKey>::value, "key is not comparable"); + +private: + std::vector<std::pair<TKey, TValue>> mData; + + explicit ImmutableMap(std::vector<std::pair<TKey, TValue>> data) : mData(std::move(data)) { + } + +public: + using const_iterator = typename decltype(mData)::const_iterator; + + ImmutableMap(ImmutableMap&&) = default; + ImmutableMap& operator=(ImmutableMap&&) = default; + + ImmutableMap(const ImmutableMap&) = delete; + ImmutableMap& operator=(const ImmutableMap&) = delete; + + static ImmutableMap<TKey, TValue> createPreSorted( + std::initializer_list<std::pair<TKey, TValue>> list) { + return ImmutableMap(std::vector<std::pair<TKey, TValue>>(list.begin(), list.end())); + } + + static ImmutableMap<TKey, TValue> createAndSort( + std::initializer_list<std::pair<TKey, TValue>> list) { + std::vector<std::pair<TKey, TValue>> data(list.begin(), list.end()); + std::sort(data.begin(), data.end()); + return ImmutableMap(std::move(data)); + } + + template <typename TKey2, + typename = typename std::enable_if<is_comparable<TKey, TKey2>::value>::type> + const_iterator find(const TKey2& key) const { + auto cmp = [](const std::pair<TKey, TValue>& candidate, const TKey2& target) -> bool { + return candidate.first < target; + }; + + const_iterator endIter = end(); + auto iter = std::lower_bound(mData.begin(), endIter, key, cmp); + if (iter == endIter || iter->first == key) { + return iter; + } + return endIter; + } + + const_iterator begin() const { + return mData.begin(); + } + + const_iterator end() const { + return mData.end(); + } +}; + +} // namespace aapt + +#endif /* AAPT_UTIL_IMMUTABLEMAP_H */ diff --git a/tools/aapt2/util/TypeTraits.h b/tools/aapt2/util/TypeTraits.h new file mode 100644 index 000000000000..76c13d615e41 --- /dev/null +++ b/tools/aapt2/util/TypeTraits.h @@ -0,0 +1,51 @@ +/* + * 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. + */ + +#ifndef AAPT_UTIL_TYPETRAITS_H +#define AAPT_UTIL_TYPETRAITS_H + +#include <type_traits> + +namespace aapt { + +#define DEFINE_HAS_BINARY_OP_TRAIT(name, op) \ + template <typename T, typename U> \ + struct name { \ + template <typename V, typename W> \ + static constexpr decltype(std::declval<V>() op std::declval<W>(), bool()) test(int) { \ + return true; \ + } \ + template <typename V, typename W> \ + static constexpr bool test(...) { \ + return false; \ + } \ + static constexpr bool value = test<T, U>(int()); \ +} + +DEFINE_HAS_BINARY_OP_TRAIT(has_eq_op, ==); +DEFINE_HAS_BINARY_OP_TRAIT(has_lt_op, <); + +/** + * Type trait that checks if two types can be equated (==) and compared (<). + */ +template <typename T, typename U> +struct is_comparable { + static constexpr bool value = has_eq_op<T, U>::value && has_lt_op<T, U>::value; +}; + +} // namespace aapt + +#endif /* AAPT_UTIL_TYPETRAITS_H */ diff --git a/tools/layoutlib/.idea/compiler.xml b/tools/layoutlib/.idea/compiler.xml index 5aaaf18f9d94..35961a2896ac 100644 --- a/tools/layoutlib/.idea/compiler.xml +++ b/tools/layoutlib/.idea/compiler.xml @@ -21,7 +21,5 @@ <processorPath useClasspath="true" /> </profile> </annotationProcessing> - <bytecodeTargetLevel target="1.6" /> </component> -</project> - +</project>
\ No newline at end of file diff --git a/tools/layoutlib/bridge/src/android/os/ServiceManager.java b/tools/layoutlib/bridge/src/android/os/ServiceManager.java index 6a68ee29c9cb..549074d15757 100644 --- a/tools/layoutlib/bridge/src/android/os/ServiceManager.java +++ b/tools/layoutlib/bridge/src/android/os/ServiceManager.java @@ -51,8 +51,10 @@ public final class ServiceManager { /** * Return a list of all currently running services. + * @return an array of all currently running services, or <code>null</code> in + * case of an exception */ - public static String[] listServices() throws RemoteException { + public static String[] listServices() { // actual implementation returns null sometimes, so it's ok // to return null instead of an empty list. return null; diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java index 3f9574f3ba83..4625de25d200 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java @@ -97,7 +97,22 @@ public class BridgePackageManager extends PackageManager { } @Override - public int getPackageUid(String packageName, int userHandle) throws NameNotFoundException { + public int[] getPackageGids(String packageName, int flags) throws NameNotFoundException { + return new int[0]; + } + + @Override + public int getPackageUid(String packageName, int flags) throws NameNotFoundException { + return 0; + } + + @Override + public int getPackageUidAsUser(String packageName, int userHandle) throws NameNotFoundException { + return 0; + } + + @Override + public int getPackageUidAsUser(String packageName, int flags, int userHandle) throws NameNotFoundException { return 0; } @@ -164,7 +179,7 @@ public class BridgePackageManager extends PackageManager { } @Override - public List<PackageInfo> getInstalledPackages(int flags, int userId) { + public List<PackageInfo> getInstalledPackagesAsUser(int flags, int userId) { return null; } @@ -328,7 +343,7 @@ public class BridgePackageManager extends PackageManager { } @Override - public List<ResolveInfo> queryBroadcastReceivers(Intent intent, int flags, int userId) { + public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent, int flags, int userId) { return null; } @@ -578,12 +593,12 @@ public class BridgePackageManager extends PackageManager { } @Override - public int getIntentVerificationStatus(String packageName, int userId) { + public int getIntentVerificationStatusAsUser(String packageName, int userId) { return 0; } @Override - public boolean updateIntentVerificationStatus(String packageName, int status, int userId) { + public boolean updateIntentVerificationStatusAsUser(String packageName, int status, int userId) { return false; } @@ -598,12 +613,12 @@ public class BridgePackageManager extends PackageManager { } @Override - public String getDefaultBrowserPackageName(int userId) { + public String getDefaultBrowserPackageNameAsUser(int userId) { return null; } @Override - public boolean setDefaultBrowserPackageName(String packageName, int userId) { + public boolean setDefaultBrowserPackageNameAsUser(String packageName, int userId) { return false; } @@ -643,7 +658,7 @@ public class BridgePackageManager extends PackageManager { } @Override - public void getPackageSizeInfo(String packageName, int userHandle, + public void getPackageSizeInfoAsUser(String packageName, int userHandle, IPackageStatsObserver observer) { } diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk index e6f0bc306b07..c7f2c4137687 100644 --- a/tools/layoutlib/create/Android.mk +++ b/tools/layoutlib/create/Android.mk @@ -20,7 +20,7 @@ LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_JAR_MANIFEST := manifest.txt LOCAL_STATIC_JAVA_LIBRARIES := \ - asm-4.0 + asm-5.0 LOCAL_MODULE := layoutlib_create diff --git a/tools/layoutlib/create/create.iml b/tools/layoutlib/create/create.iml index 9b18e73aae90..b2b14b4e8a91 100644 --- a/tools/layoutlib/create/create.iml +++ b/tools/layoutlib/create/create.iml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <module type="JAVA_MODULE" version="4"> - <component name="NewModuleRootManager" inherit-compiler-output="true"> + <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8" inherit-compiler-output="true"> <exclude-output /> <content url="file://$MODULE_DIR$"> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> @@ -9,12 +9,12 @@ <sourceFolder url="file://$MODULE_DIR$/tests/mock_data" type="java-test-resource" /> <excludeFolder url="file://$MODULE_DIR$/.settings" /> </content> - <orderEntry type="inheritedJdk" /> + <orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" /> <orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="module-library"> - <library name="asm-4.0"> + <library name="asm-5.0"> <CLASSES> - <root url="jar://$MODULE_DIR$/../../../../../prebuilts/misc/common/asm/asm-4.0.jar!/" /> + <root url="jar://$MODULE_DIR$/../../../../../prebuilts/misc/common/asm/asm-5.0.jar!/" /> </CLASSES> <JAVADOC /> <SOURCES> diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java index a6902a40b1a3..758bd48e6067 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AbstractClassAdapter.java @@ -21,7 +21,6 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; @@ -44,7 +43,7 @@ public abstract class AbstractClassAdapter extends ClassVisitor { abstract String renameInternalType(String name); public AbstractClassAdapter(ClassVisitor cv) { - super(Opcodes.ASM4, cv); + super(Main.ASM_VERSION, cv); } /** @@ -239,7 +238,7 @@ public abstract class AbstractClassAdapter extends ClassVisitor { * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass). */ public RenameMethodAdapter(MethodVisitor mv) { - super(Opcodes.ASM4, mv); + super(Main.ASM_VERSION, mv); } @Override @@ -276,7 +275,8 @@ public abstract class AbstractClassAdapter extends ClassVisitor { } @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { + public void visitMethodInsn(int opcode, String owner, String name, String desc, + boolean itf) { // The owner sometimes turns out to be a type descriptor. We try to detect it and fix. if (owner.indexOf(';') > 0) { owner = renameTypeDesc(owner); @@ -285,7 +285,7 @@ public abstract class AbstractClassAdapter extends ClassVisitor { } desc = renameMethodDesc(desc); - super.visitMethodInsn(opcode, owner, name, desc); + super.visitMethodInsn(opcode, owner, name, desc, itf); } @Override @@ -330,7 +330,7 @@ public abstract class AbstractClassAdapter extends ClassVisitor { private final SignatureVisitor mSv; public RenameSignatureAdapter(SignatureVisitor sv) { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); mSv = sv; } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java index c8b2b8448e21..48544cac16ab 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java @@ -23,7 +23,6 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; @@ -65,7 +64,7 @@ public class AsmAnalyzer { /** Glob patterns of files to keep as is. */ private final String[] mIncludeFileGlobs; /** Internal names of classes that contain method calls that need to be rewritten. */ - private final Set<String> mReplaceMethodCallClasses = new HashSet<String>(); + private final Set<String> mReplaceMethodCallClasses = new HashSet<>(); /** * Creates a new analyzer. @@ -97,8 +96,8 @@ public class AsmAnalyzer { */ public void analyze() throws IOException, LogAbortException { - TreeMap<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + TreeMap<String, ClassReader> zipClasses = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); parseZip(mOsSourceJar, zipClasses, filesFound); mLog.info("Found %d classes in input JAR%s.", zipClasses.size(), @@ -189,7 +188,7 @@ public class AsmAnalyzer { */ Map<String, ClassReader> findIncludes(Map<String, ClassReader> zipClasses) throws LogAbortException { - TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); + TreeMap<String, ClassReader> found = new TreeMap<>(); mLog.debug("Find classes to include."); @@ -318,10 +317,10 @@ public class AsmAnalyzer { Map<String, ClassReader> findDeps(Map<String, ClassReader> zipClasses, Map<String, ClassReader> inOutKeepClasses) { - TreeMap<String, ClassReader> deps = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> new_deps = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> temp = new TreeMap<String, ClassReader>(); + TreeMap<String, ClassReader> deps = new TreeMap<>(); + TreeMap<String, ClassReader> new_deps = new TreeMap<>(); + TreeMap<String, ClassReader> new_keep = new TreeMap<>(); + TreeMap<String, ClassReader> temp = new TreeMap<>(); DependencyVisitor visitor = getVisitor(zipClasses, inOutKeepClasses, new_keep, @@ -399,7 +398,7 @@ public class AsmAnalyzer { Map<String, ClassReader> outKeep, Map<String,ClassReader> inDeps, Map<String,ClassReader> outDeps) { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); mZipClasses = zipClasses; mInKeep = inKeep; mOutKeep = outKeep; @@ -557,7 +556,7 @@ public class AsmAnalyzer { private class MyFieldVisitor extends FieldVisitor { public MyFieldVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } @Override @@ -630,7 +629,7 @@ public class AsmAnalyzer { private String mOwnerClass; public MyMethodVisitor(String ownerClass) { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); mOwnerClass = ownerClass; } @@ -719,7 +718,8 @@ public class AsmAnalyzer { // instruction that invokes a method @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { + public void visitMethodInsn(int opcode, String owner, String name, String desc, + boolean itf) { // owner is the internal name of the method's owner class considerName(owner); @@ -779,7 +779,7 @@ public class AsmAnalyzer { private class MySignatureVisitor extends SignatureVisitor { public MySignatureVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } // --------------------------------------------------- @@ -878,7 +878,7 @@ public class AsmAnalyzer { private class MyAnnotationVisitor extends AnnotationVisitor { public MyAnnotationVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } // Visits a primitive value of an annotation diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java index 8f0ad01c6dc3..5b99a6bae195 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java @@ -91,7 +91,7 @@ public class AsmGenerator { mLog = log; mOsDestJar = osDestJar; ArrayList<Class<?>> injectedClasses = - new ArrayList<Class<?>>(Arrays.asList(createInfo.getInjectedClasses())); + new ArrayList<>(Arrays.asList(createInfo.getInjectedClasses())); // Search for and add anonymous inner classes also. ListIterator<Class<?>> iter = injectedClasses.listIterator(); while (iter.hasNext()) { @@ -107,25 +107,25 @@ public class AsmGenerator { } } mInjectClasses = injectedClasses.toArray(new Class<?>[0]); - mStubMethods = new HashSet<String>(Arrays.asList(createInfo.getOverriddenMethods())); + mStubMethods = new HashSet<>(Arrays.asList(createInfo.getOverriddenMethods())); // Create the map/set of methods to change to delegates - mDelegateMethods = new HashMap<String, Set<String>>(); + mDelegateMethods = new HashMap<>(); addToMap(createInfo.getDelegateMethods(), mDelegateMethods); for (String className : createInfo.getDelegateClassNatives()) { className = binaryToInternalClassName(className); Set<String> methods = mDelegateMethods.get(className); if (methods == null) { - methods = new HashSet<String>(); + methods = new HashSet<>(); mDelegateMethods.put(className, methods); } methods.add(DelegateClassAdapter.ALL_NATIVES); } // Create the map of classes to rename. - mRenameClasses = new HashMap<String, String>(); - mClassesNotRenamed = new HashSet<String>(); + mRenameClasses = new HashMap<>(); + mClassesNotRenamed = new HashSet<>(); String[] renameClasses = createInfo.getRenamedClasses(); int n = renameClasses.length; for (int i = 0; i < n; i += 2) { @@ -138,7 +138,7 @@ public class AsmGenerator { } // Create a map of classes to be refactored. - mRefactorClasses = new HashMap<String, String>(); + mRefactorClasses = new HashMap<>(); String[] refactorClasses = createInfo.getJavaPkgClasses(); n = refactorClasses.length; for (int i = 0; i < n; i += 2) { @@ -149,7 +149,7 @@ public class AsmGenerator { } // create the map of renamed class -> return type of method to delete. - mDeleteReturns = new HashMap<String, Set<String>>(); + mDeleteReturns = new HashMap<>(); String[] deleteReturns = createInfo.getDeleteReturns(); Set<String> returnTypes = null; String renamedClass = null; @@ -172,12 +172,12 @@ public class AsmGenerator { // just a standard return type, we add it to the list. if (returnTypes == null) { - returnTypes = new HashSet<String>(); + returnTypes = new HashSet<>(); } returnTypes.add(binaryToInternalClassName(className)); } - mPromotedFields = new HashMap<String, Set<String>>(); + mPromotedFields = new HashMap<>(); addToMap(createInfo.getPromotedFields(), mPromotedFields); mInjectedMethodsMap = createInfo.getInjectedMethodsMap(); @@ -197,7 +197,7 @@ public class AsmGenerator { String methodOrFieldName = entry.substring(pos + 1); Set<String> set = map.get(className); if (set == null) { - set = new HashSet<String>(); + set = new HashSet<>(); map.put(className, set); } set.add(methodOrFieldName); @@ -247,7 +247,7 @@ public class AsmGenerator { /** Generates the final JAR */ public void generate() throws IOException { - TreeMap<String, byte[]> all = new TreeMap<String, byte[]>(); + TreeMap<String, byte[]> all = new TreeMap<>(); for (Class<?> clazz : mInjectClasses) { String name = classToEntryPath(clazz); @@ -314,7 +314,7 @@ public class AsmGenerator { * e.g. for the input "android.view.View" it returns "android/view/View.class" */ String classNameToEntryPath(String className) { - return className.replaceAll("\\.", "/").concat(".class"); + return className.replace('.', '/').concat(".class"); } /** diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java index 2c955fd9d9bb..4748a7c7b2f1 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java @@ -31,7 +31,7 @@ import org.objectweb.asm.Opcodes; */ public class ClassHasNativeVisitor extends ClassVisitor { public ClassHasNativeVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } private boolean mHasNativeMethods = false; diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index b571c5a486e9..3ca7590b2e83 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -111,7 +111,7 @@ public final class CreateInfo implements ICreateInfo { public Set<String> getExcludedClasses() { String[] refactoredClasses = getJavaPkgClasses(); int count = refactoredClasses.length / 2 + EXCLUDED_CLASSES.length; - Set<String> excludedClasses = new HashSet<String>(count); + Set<String> excludedClasses = new HashSet<>(count); for (int i = 0; i < refactoredClasses.length; i+=2) { excludedClasses.add(refactoredClasses[i]); } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java index 7ef75662aad4..cbb3a8abd692 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java @@ -60,7 +60,7 @@ public class DelegateClassAdapter extends ClassVisitor { ClassVisitor cv, String className, Set<String> delegateMethods) { - super(Opcodes.ASM4, cv); + super(Main.ASM_VERSION, cv); mLog = log; mClassName = className; mDelegateMethods = delegateMethods; diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java index cca9e574b7ea..da8babcbca83 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java @@ -124,7 +124,7 @@ class DelegateMethodAdapter extends MethodVisitor { String desc, boolean isStatic, boolean isStaticClass) { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); mLog = log; mOrgWriter = mvOriginal; mDelWriter = mvDelegate; @@ -188,7 +188,7 @@ class DelegateMethodAdapter extends MethodVisitor { mDelWriter.visitLineNumber((Integer) p[0], (Label) p[1]); } - ArrayList<Type> paramTypes = new ArrayList<Type>(); + ArrayList<Type> paramTypes = new ArrayList<>(); String delegateClassName = mClassName + DELEGATE_SUFFIX; boolean pushedArg0 = false; int maxStack = 0; @@ -253,7 +253,8 @@ class DelegateMethodAdapter extends MethodVisitor { mDelWriter.visitMethodInsn(Opcodes.INVOKESTATIC, delegateClassName, mMethodName, - desc); + desc, + false); Type returnType = Type.getReturnType(mDesc); mDelWriter.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); @@ -371,9 +372,9 @@ class DelegateMethodAdapter extends MethodVisitor { } @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if (mOrgWriter != null) { - mOrgWriter.visitMethodInsn(opcode, owner, name, desc); + mOrgWriter.visitMethodInsn(opcode, owner, name, desc, itf); } } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java index 61b64a2e8e38..aa68ea099844 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java @@ -26,7 +26,6 @@ import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import org.objectweb.asm.signature.SignatureReader; import org.objectweb.asm.signature.SignatureVisitor; @@ -82,7 +81,7 @@ public class DependencyFinder { Map<String, Set<String>> missing = findMissingClasses(deps, zipClasses.keySet()); - List<Map<String, Set<String>>> result = new ArrayList<Map<String,Set<String>>>(2); + List<Map<String, Set<String>>> result = new ArrayList<>(2); result.add(deps); result.add(missing); return result; @@ -151,7 +150,7 @@ public class DependencyFinder { * class name => ASM ClassReader. Class names are in the form "android.view.View". */ Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException { - TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>(); + TreeMap<String, ClassReader> classes = new TreeMap<>(); for (String jarPath : jarPathList) { ZipFile zip = new ZipFile(jarPath); @@ -202,7 +201,7 @@ public class DependencyFinder { // The dependencies that we'll collect. // It's a map Class name => uses class names. - Map<String, Set<String>> dependencyMap = new TreeMap<String, Set<String>>(); + Map<String, Set<String>> dependencyMap = new TreeMap<>(); DependencyVisitor visitor = getVisitor(); @@ -211,7 +210,7 @@ public class DependencyFinder { for (Entry<String, ClassReader> entry : zipClasses.entrySet()) { String name = entry.getKey(); - TreeSet<String> set = new TreeSet<String>(); + TreeSet<String> set = new TreeSet<>(); dependencyMap.put(name, set); visitor.setDependencySet(set); @@ -240,7 +239,7 @@ public class DependencyFinder { private Map<String, Set<String>> findMissingClasses( Map<String, Set<String>> deps, Set<String> zipClasses) { - Map<String, Set<String>> missing = new TreeMap<String, Set<String>>(); + Map<String, Set<String>> missing = new TreeMap<>(); for (Entry<String, Set<String>> entry : deps.entrySet()) { String name = entry.getKey(); @@ -250,7 +249,7 @@ public class DependencyFinder { // This dependency doesn't exist in the zip classes. Set<String> set = missing.get(dep); if (set == null) { - set = new TreeSet<String>(); + set = new TreeSet<>(); missing.put(dep, set); } set.add(name); @@ -284,7 +283,7 @@ public class DependencyFinder { * Creates a new visitor that will find all the dependencies for the visited class. */ public DependencyVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } /** @@ -435,7 +434,7 @@ public class DependencyFinder { private class MyFieldVisitor extends FieldVisitor { public MyFieldVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } @Override @@ -510,7 +509,7 @@ public class DependencyFinder { private class MyMethodVisitor extends MethodVisitor { public MyMethodVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } @@ -598,7 +597,8 @@ public class DependencyFinder { // instruction that invokes a method @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { + public void visitMethodInsn(int opcode, String owner, String name, String desc, + boolean itf) { // owner is the internal name of the method's owner class if (!considerDesc(owner) && owner.indexOf('/') != -1) { @@ -654,7 +654,7 @@ public class DependencyFinder { private class MySignatureVisitor extends SignatureVisitor { public MySignatureVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } // --------------------------------------------------- @@ -753,7 +753,7 @@ public class DependencyFinder { private class MyAnnotationVisitor extends AnnotationVisitor { public MyAnnotationVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } // Visits a primitive value of an annotation diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java index 37fc096acb04..1941ab4e78d8 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodRunnables.java @@ -42,9 +42,9 @@ public class InjectMethodRunnables { mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", - "()Ljava/lang/Class;"); + "()Ljava/lang/Class;", false); mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getClassLoader", - "()Ljava/lang/ClassLoader;"); + "()Ljava/lang/ClassLoader;", false); mv.visitInsn(ARETURN); mv.visitMaxs(1, 1); mv.visitEnd(); diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java index ea2b9c900ad0..c834808d950d 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/InjectMethodsAdapter.java @@ -19,7 +19,6 @@ package com.android.tools.layoutlib.create; import com.android.tools.layoutlib.create.ICreateInfo.InjectMethodRunnable; import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Opcodes; /** * Injects methods into some classes. @@ -29,7 +28,7 @@ public class InjectMethodsAdapter extends ClassVisitor { private final ICreateInfo.InjectMethodRunnable mRunnable; public InjectMethodsAdapter(ClassVisitor cv, InjectMethodRunnable runnable) { - super(Opcodes.ASM4, cv); + super(Main.ASM_VERSION, cv); mRunnable = runnable; } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java index 383168face86..9bb91e599d77 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java @@ -16,6 +16,8 @@ package com.android.tools.layoutlib.create; +import org.objectweb.asm.Opcodes; + import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -52,13 +54,15 @@ public class Main { public boolean listOnlyMissingDeps = false; } + public static final int ASM_VERSION = Opcodes.ASM5; + public static final Options sOptions = new Options(); public static void main(String[] args) { Log log = new Log(); - ArrayList<String> osJarPath = new ArrayList<String>(); + ArrayList<String> osJarPath = new ArrayList<>(); String[] osDestJar = { null }; if (!processArgs(log, args, osJarPath, osDestJar)) { diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java index 6fc2b240b84f..faba4d727a06 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java @@ -36,41 +36,40 @@ public interface MethodListener { * @param isNative True if the method was a native method. * @param caller The calling object. Null for static methods, "this" for instance methods. */ - public void onInvokeV(String signature, boolean isNative, Object caller); + void onInvokeV(String signature, boolean isNative, Object caller); /** * Same as {@link #onInvokeV(String, boolean, Object)} but returns an integer or similar. * @see #onInvokeV(String, boolean, Object) * @return an integer, or a boolean, or a short or a byte. */ - public int onInvokeI(String signature, boolean isNative, Object caller); + int onInvokeI(String signature, boolean isNative, Object caller); /** * Same as {@link #onInvokeV(String, boolean, Object)} but returns a long. * @see #onInvokeV(String, boolean, Object) * @return a long. */ - public long onInvokeL(String signature, boolean isNative, Object caller); + long onInvokeL(String signature, boolean isNative, Object caller); /** * Same as {@link #onInvokeV(String, boolean, Object)} but returns a float. * @see #onInvokeV(String, boolean, Object) * @return a float. */ - public float onInvokeF(String signature, boolean isNative, Object caller); + float onInvokeF(String signature, boolean isNative, Object caller); /** * Same as {@link #onInvokeV(String, boolean, Object)} but returns a double. * @see #onInvokeV(String, boolean, Object) * @return a double. */ - public double onInvokeD(String signature, boolean isNative, Object caller); + double onInvokeD(String signature, boolean isNative, Object caller); /** * Same as {@link #onInvokeV(String, boolean, Object)} but returns an object. * @see #onInvokeV(String, boolean, Object) * @return an object. */ - public Object onInvokeA(String signature, boolean isNative, Object caller); + Object onInvokeA(String signature, boolean isNative, Object caller); } - diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java index 4c87b3c3562d..7ccafc3867e7 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java @@ -28,7 +28,7 @@ import java.util.HashMap; public final class OverrideMethod { /** Map of method overridden. */ - private static HashMap<String, MethodListener> sMethods = new HashMap<String, MethodListener>(); + private static HashMap<String, MethodListener> sMethods = new HashMap<>(); /** Default listener for all method not listed in sMethods. Nothing if null. */ private static MethodListener sDefaultListener = null; diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java index e4b70da2504f..05af0337a397 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java @@ -24,7 +24,6 @@ import java.util.Set; import static org.objectweb.asm.Opcodes.ACC_PRIVATE; import static org.objectweb.asm.Opcodes.ACC_PROTECTED; import static org.objectweb.asm.Opcodes.ACC_PUBLIC; -import static org.objectweb.asm.Opcodes.ASM4; /** * Promotes given fields to public visibility. @@ -35,7 +34,7 @@ public class PromoteFieldClassAdapter extends ClassVisitor { private static final int ACC_NOT_PUBLIC = ~(ACC_PRIVATE | ACC_PROTECTED); public PromoteFieldClassAdapter(ClassVisitor cv, Set<String> fieldNames) { - super(ASM4, cv); + super(Main.ASM_VERSION, cv); mFieldNames = fieldNames; } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java index 5e47261ea89c..bf94415a4c6f 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ReplaceMethodCallsAdapter.java @@ -43,11 +43,11 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { * Descriptors for specialized versions {@link System#arraycopy} that are not present on the * Desktop VM. */ - private static Set<String> ARRAYCOPY_DESCRIPTORS = new HashSet<String>(Arrays.asList( + private static Set<String> ARRAYCOPY_DESCRIPTORS = new HashSet<>(Arrays.asList( "([CI[CII)V", "([BI[BII)V", "([SI[SII)V", "([II[III)V", "([JI[JII)V", "([FI[FII)V", "([DI[DII)V", "([ZI[ZII)V")); - private static final List<MethodReplacer> METHOD_REPLACERS = new ArrayList<MethodReplacer>(5); + private static final List<MethodReplacer> METHOD_REPLACERS = new ArrayList<>(5); private static final String ANDROID_LOCALE_CLASS = "com/android/layoutlib/bridge/android/AndroidLocale"; @@ -232,7 +232,7 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { private final String mOriginalClassName; public ReplaceMethodCallsAdapter(ClassVisitor cv, String originalClassName) { - super(Opcodes.ASM4, cv); + super(Main.ASM_VERSION, cv); mOriginalClassName = originalClassName; } @@ -245,11 +245,12 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { private class MyMethodVisitor extends MethodVisitor { public MyMethodVisitor(MethodVisitor mv) { - super(Opcodes.ASM4, mv); + super(Main.ASM_VERSION, mv); } @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { + public void visitMethodInsn(int opcode, String owner, String name, String desc, + boolean itf) { for (MethodReplacer replacer : METHOD_REPLACERS) { if (replacer.isNeeded(owner, name, desc, mOriginalClassName)) { MethodInformation mi = new MethodInformation(opcode, owner, name, desc); @@ -261,7 +262,7 @@ public class ReplaceMethodCallsAdapter extends ClassVisitor { break; } } - super.visitMethodInsn(opcode, owner, name, desc); + super.visitMethodInsn(opcode, owner, name, desc, itf); } } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java index 416b73a43c11..b5ab73855189 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java @@ -50,7 +50,7 @@ class StubMethodAdapter extends MethodVisitor { public StubMethodAdapter(MethodVisitor mv, String methodName, Type returnType, String invokeSignature, boolean isStatic, boolean isNative) { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); mParentVisitor = mv; mReturnType = returnType; mInvokeSignature = invokeSignature; @@ -82,7 +82,8 @@ class StubMethodAdapter extends MethodVisitor { mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeV", - "(Ljava/lang/String;ZLjava/lang/Object;)V"); + "(Ljava/lang/String;ZLjava/lang/Object;)V", + false); mParentVisitor.visitInsn(Opcodes.RETURN); break; case Type.BOOLEAN: @@ -93,7 +94,8 @@ class StubMethodAdapter extends MethodVisitor { mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeI", - "(Ljava/lang/String;ZLjava/lang/Object;)I"); + "(Ljava/lang/String;ZLjava/lang/Object;)I", + false); switch(sort) { case Type.BOOLEAN: Label l1 = new Label(); @@ -119,21 +121,24 @@ class StubMethodAdapter extends MethodVisitor { mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeL", - "(Ljava/lang/String;ZLjava/lang/Object;)J"); + "(Ljava/lang/String;ZLjava/lang/Object;)J", + false); mParentVisitor.visitInsn(Opcodes.LRETURN); break; case Type.FLOAT: mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeF", - "(Ljava/lang/String;ZLjava/lang/Object;)F"); + "(Ljava/lang/String;ZLjava/lang/Object;)F", + false); mParentVisitor.visitInsn(Opcodes.FRETURN); break; case Type.DOUBLE: mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeD", - "(Ljava/lang/String;ZLjava/lang/Object;)D"); + "(Ljava/lang/String;ZLjava/lang/Object;)D", + false); mParentVisitor.visitInsn(Opcodes.DRETURN); break; case Type.ARRAY: @@ -141,7 +146,8 @@ class StubMethodAdapter extends MethodVisitor { mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, "com/android/tools/layoutlib/create/OverrideMethod", "invokeA", - "(Ljava/lang/String;ZLjava/lang/Object;)Ljava/lang/Object;"); + "(Ljava/lang/String;ZLjava/lang/Object;)Ljava/lang/Object;", + false); mParentVisitor.visitTypeInsn(Opcodes.CHECKCAST, mReturnType.getInternalName()); mParentVisitor.visitInsn(Opcodes.ARETURN); break; @@ -282,9 +288,9 @@ class StubMethodAdapter extends MethodVisitor { } @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { + public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) { if (mIsInitMethod) { - mParentVisitor.visitMethodInsn(opcode, owner, name, desc); + mParentVisitor.visitMethodInsn(opcode, owner, name, desc, itf); } } diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java index d9ecf980658c..a28ae694246d 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java @@ -49,7 +49,7 @@ class TransformClassAdapter extends ClassVisitor { public TransformClassAdapter(Log logger, Set<String> stubMethods, Set<String> deleteReturns, String className, ClassVisitor cv, boolean stubNativesOnly) { - super(Opcodes.ASM4, cv); + super(Main.ASM_VERSION, cv); mLog = logger; mStubMethods = stubMethods; mClassName = className; diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java index ed2c128e1900..7d6c4ec1ad9e 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/java/AutoCloseable.java @@ -28,4 +28,5 @@ public interface AutoCloseable { /** * Closes the object and release any system resources it holds. */ - void close() throws Exception; } + void close() throws Exception; +} diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk index c197d5733658..dafb9c6f9402 100644 --- a/tools/layoutlib/create/tests/Android.mk +++ b/tools/layoutlib/create/tests/Android.mk @@ -24,7 +24,7 @@ LOCAL_MODULE := layoutlib-create-tests LOCAL_MODULE_TAGS := optional LOCAL_JAVA_LIBRARIES := layoutlib_create junit -LOCAL_STATIC_JAVA_LIBRARIES := asm-4.0 +LOCAL_STATIC_JAVA_LIBRARIES := asm-5.0 include $(BUILD_HOST_JAVA_LIBRARY) diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java index 78e2c4899c1b..f86917a8139c 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java @@ -17,13 +17,8 @@ package com.android.tools.layoutlib.create; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - import com.android.tools.layoutlib.create.AsmAnalyzer.DependencyVisitor; -import org.junit.After; import org.junit.Before; import org.junit.Test; import org.objectweb.asm.ClassReader; @@ -32,11 +27,15 @@ import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; -import java.util.HashSet; +import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.TreeMap; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + /** * Unit tests for some methods of {@link AsmAnalyzer}. */ @@ -51,26 +50,22 @@ public class AsmAnalyzerTest { mLog = new MockLog(); URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar"); - mOsJarPath = new ArrayList<String>(); + mOsJarPath = new ArrayList<>(); + //noinspection ConstantConditions mOsJarPath.add(url.getFile()); - Set<String> excludeClasses = new HashSet<String>(1); - excludeClasses.add("java.lang.JavaClass"); + Set<String> excludeClasses = Collections.singleton("java.lang.JavaClass"); String[] includeFiles = new String[]{"mock_android/data/data*"}; mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, null /* deriveFrom */, null /* includeGlobs */, excludeClasses, includeFiles); } - @After - public void tearDown() throws Exception { - } - @Test public void testParseZip() throws IOException { - Map<String, ClassReader> map = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + Map<String, ClassReader> map = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); mAa.parseZip(mOsJarPath, map, filesFound); @@ -101,11 +96,11 @@ public class AsmAnalyzerTest { @Test public void testFindClass() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + Map<String, ClassReader> zipClasses = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); mAa.parseZip(mOsJarPath, zipClasses, filesFound); - TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); + TreeMap<String, ClassReader> found = new TreeMap<>(); ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams", zipClasses, found); @@ -120,11 +115,11 @@ public class AsmAnalyzerTest { @Test public void testFindGlobs() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + Map<String, ClassReader> zipClasses = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); mAa.parseZip(mOsJarPath, zipClasses, filesFound); - TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); + TreeMap<String, ClassReader> found = new TreeMap<>(); // this matches classes, a package match returns nothing found.clear(); @@ -183,11 +178,11 @@ public class AsmAnalyzerTest { @Test public void testFindClassesDerivingFrom() throws LogAbortException, IOException { - Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + Map<String, ClassReader> zipClasses = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); mAa.parseZip(mOsJarPath, zipClasses, filesFound); - TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); + TreeMap<String, ClassReader> found = new TreeMap<>(); mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found); @@ -209,14 +204,14 @@ public class AsmAnalyzerTest { @Test public void testDependencyVisitor() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + Map<String, ClassReader> zipClasses = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); mAa.parseZip(mOsJarPath, zipClasses, filesFound); - TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>(); + TreeMap<String, ClassReader> keep = new TreeMap<>(); + TreeMap<String, ClassReader> new_keep = new TreeMap<>(); + TreeMap<String, ClassReader> in_deps = new TreeMap<>(); + TreeMap<String, ClassReader> out_deps = new TreeMap<>(); ClassReader cr = mAa.findClass("mock_android.widget.LinearLayout", zipClasses, keep); DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps); diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java index 8a2235b8526c..c4dd7eeafbba 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java @@ -18,12 +18,6 @@ package com.android.tools.layoutlib.create; -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -31,7 +25,6 @@ import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassVisitor; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.Type; import java.io.ByteArrayOutputStream; @@ -44,7 +37,6 @@ import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; -import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -52,11 +44,18 @@ import java.util.TreeMap; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + /** * Unit tests for some methods of {@link AsmGenerator}. */ public class AsmGeneratorTest { + private static final String[] EMPTY_STRING_ARRAY = new String[0]; private MockLog mLog; private ArrayList<String> mOsJarPath; private String mOsDestJar; @@ -70,7 +69,8 @@ public class AsmGeneratorTest { mLog = new MockLog(); URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar"); - mOsJarPath = new ArrayList<String>(); + mOsJarPath = new ArrayList<>(); + //noinspection ConstantConditions mOsJarPath.add(url.getFile()); mTempFile = File.createTempFile("mock", ".jar"); @@ -98,18 +98,18 @@ public class AsmGeneratorTest { @Override public String[] getDelegateMethods() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getDelegateClassNatives() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getOverriddenMethods() { // methods to force override - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override @@ -123,7 +123,7 @@ public class AsmGeneratorTest { @Override public String[] getJavaPkgClasses() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override @@ -134,17 +134,17 @@ public class AsmGeneratorTest { @Override public String[] getDeleteReturns() { // methods deleted from their return type. - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getPromotedFields() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { - return new HashMap<String, InjectMethodRunnable>(0); + return Collections.emptyMap(); } }; @@ -155,7 +155,7 @@ public class AsmGeneratorTest { new String[] { // include classes "**" }, - new HashSet<String>(0) /* excluded classes */, + Collections.<String>emptySet() /* excluded classes */, new String[]{} /* include files */); aa.analyze(); agen.generate(); @@ -178,24 +178,24 @@ public class AsmGeneratorTest { @Override public String[] getDelegateMethods() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getDelegateClassNatives() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getOverriddenMethods() { // methods to force override - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getRenamedClasses() { // classes to rename (so that we can replace them) - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override @@ -214,17 +214,17 @@ public class AsmGeneratorTest { @Override public String[] getDeleteReturns() { // methods deleted from their return type. - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getPromotedFields() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { - return new HashMap<String, InjectMethodRunnable>(0); + return Collections.emptyMap(); } }; @@ -235,14 +235,14 @@ public class AsmGeneratorTest { new String[] { // include classes "**" }, - new HashSet<String>(1), + Collections.<String>emptySet(), new String[] { /* include files */ "mock_android/data/data*" }); aa.analyze(); agen.generate(); - Map<String, ClassReader> output = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + Map<String, ClassReader> output = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); parseZip(mOsDestJar, output, filesFound); boolean injectedClassFound = false; for (ClassReader cr: output.values()) { @@ -265,35 +265,35 @@ public class AsmGeneratorTest { @Override public String[] getDelegateMethods() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getDelegateClassNatives() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getOverriddenMethods() { // methods to force override - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getRenamedClasses() { // classes to rename (so that we can replace them) - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getJavaPkgClasses() { // classes to refactor (so that we can replace them) - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public Set<String> getExcludedClasses() { - Set<String> set = new HashSet<String>(2); + Set<String> set = new HashSet<>(2); set.add("mock_android.dummy.InnerTest"); set.add("java.lang.JavaClass"); return set; @@ -302,17 +302,17 @@ public class AsmGeneratorTest { @Override public String[] getDeleteReturns() { // methods deleted from their return type. - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getPromotedFields() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { - return new HashMap<String, InjectMethodRunnable>(0); + return Collections.emptyMap(); } }; @@ -329,8 +329,8 @@ public class AsmGeneratorTest { }); aa.analyze(); agen.generate(); - Map<String, ClassReader> output = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + Map<String, ClassReader> output = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); parseZip(mOsDestJar, output, filesFound); for (String s : output.keySet()) { assertFalse(excludedClasses.contains(s)); @@ -351,55 +351,52 @@ public class AsmGeneratorTest { @Override public String[] getDelegateMethods() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getDelegateClassNatives() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getOverriddenMethods() { // methods to force override - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getRenamedClasses() { // classes to rename (so that we can replace them) - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getJavaPkgClasses() { // classes to refactor (so that we can replace them) - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public Set<String> getExcludedClasses() { - return new HashSet<String>(0); + return Collections.emptySet(); } @Override public String[] getDeleteReturns() { // methods deleted from their return type. - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public String[] getPromotedFields() { - return new String[0]; + return EMPTY_STRING_ARRAY; } @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { - HashMap<String, InjectMethodRunnable> map = - new HashMap<String, InjectMethodRunnable>(1); - map.put("mock_android.util.EmptyArray", + return Collections.singletonMap("mock_android.util.EmptyArray", InjectMethodRunnables.CONTEXT_GET_FRAMEWORK_CLASS_LOADER); - return map; } }; @@ -415,8 +412,8 @@ public class AsmGeneratorTest { }); aa.analyze(); agen.generate(); - Map<String, ClassReader> output = new TreeMap<String, ClassReader>(); - Map<String, InputStream> filesFound = new TreeMap<String, InputStream>(); + Map<String, ClassReader> output = new TreeMap<>(); + Map<String, InputStream> filesFound = new TreeMap<>(); parseZip(mOsDestJar, output, filesFound); final String modifiedClass = "mock_android.util.EmptyArray"; final String modifiedClassPath = modifiedClass.replace('.', '/').concat(".class"); @@ -424,11 +421,8 @@ public class AsmGeneratorTest { ZipEntry entry = zipFile.getEntry(modifiedClassPath); assertNotNull(entry); final byte[] bytes; - final InputStream inputStream = zipFile.getInputStream(entry); - try { + try (InputStream inputStream = zipFile.getInputStream(entry)) { bytes = getByteArray(inputStream); - } finally { - inputStream.close(); } ClassLoader classLoader = new ClassLoader(getClass().getClassLoader()) { @Override @@ -489,7 +483,7 @@ public class AsmGeneratorTest { boolean mInjectedClassFound = false; TestClassVisitor() { - super(Opcodes.ASM4); + super(Main.ASM_VERSION); } @Override @@ -514,7 +508,7 @@ public class AsmGeneratorTest { public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) { MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions); - return new MethodVisitor(Opcodes.ASM4, mv) { + return new MethodVisitor(Main.ASM_VERSION, mv) { @Override public void visitFieldInsn(int opcode, String owner, String name, @@ -540,10 +534,10 @@ public class AsmGeneratorTest { @Override public void visitMethodInsn(int opcode, String owner, String name, - String desc) { + String desc, boolean itf) { assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME)); assertTrue(testType(Type.getType(desc))); - super.visitMethodInsn(opcode, owner, name, desc); + super.visitMethodInsn(opcode, owner, name, desc, itf); } }; diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java index 0135c40e71ab..0cdcdc0c1235 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java @@ -60,7 +60,7 @@ public class ClassHasNativeVisitorTest { * Overrides {@link ClassHasNativeVisitor} to collec the name of the native methods found. */ private static class MockClassHasNativeVisitor extends ClassHasNativeVisitor { - private ArrayList<String> mMethodsFound = new ArrayList<String>(); + private ArrayList<String> mMethodsFound = new ArrayList<>(); public String[] getMethodsFound() { return mMethodsFound.toArray(new String[mMethodsFound.size()]); diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java index e37a09b348b8..0912fb1e105c 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java @@ -88,7 +88,7 @@ public class DelegateClassAdapterTest { // Now process it but tell the delegate to not modify any method ClassWriter cw = new ClassWriter(0 /*flags*/); - HashSet<String> delegateMethods = new HashSet<String>(); + HashSet<String> delegateMethods = new HashSet<>(); String internalClassName = NATIVE_CLASS_NAME.replace('.', '/'); DelegateClassAdapter cv = new DelegateClassAdapter( mLog, cw, internalClassName, delegateMethods); @@ -152,7 +152,7 @@ public class DelegateClassAdapterTest { String internalClassName = NATIVE_CLASS_NAME.replace('.', '/'); - HashSet<String> delegateMethods = new HashSet<String>(); + HashSet<String> delegateMethods = new HashSet<>(); delegateMethods.add("<init>"); DelegateClassAdapter cv = new DelegateClassAdapter( mLog, cw, internalClassName, delegateMethods); @@ -166,7 +166,7 @@ public class DelegateClassAdapterTest { ClassWriter cw = new ClassWriter(0 /*flags*/); String internalClassName = NATIVE_CLASS_NAME.replace('.', '/'); - HashSet<String> delegateMethods = new HashSet<String>(); + HashSet<String> delegateMethods = new HashSet<>(); delegateMethods.add(DelegateClassAdapter.ALL_NATIVES); DelegateClassAdapter cv = new DelegateClassAdapter( mLog, cw, internalClassName, delegateMethods); @@ -217,7 +217,7 @@ public class DelegateClassAdapterTest { @Test public void testDelegateInner() throws Throwable { // We'll delegate the "get" method of both the inner and outer class. - HashSet<String> delegateMethods = new HashSet<String>(); + HashSet<String> delegateMethods = new HashSet<>(); delegateMethods.add("get"); delegateMethods.add("privateMethod"); @@ -300,7 +300,7 @@ public class DelegateClassAdapterTest { @Test public void testDelegateStaticInner() throws Throwable { // We'll delegate the "get" method of both the inner and outer class. - HashSet<String> delegateMethods = new HashSet<String>(); + HashSet<String> delegateMethods = new HashSet<>(); delegateMethods.add("get"); // Generate the delegate for the outer class. @@ -367,7 +367,7 @@ public class DelegateClassAdapterTest { */ private abstract class ClassLoader2 extends ClassLoader { - private final Map<String, byte[]> mClassDefs = new HashMap<String, byte[]>(); + private final Map<String, byte[]> mClassDefs = new HashMap<>(); public ClassLoader2() { super(null); diff --git a/tools/preload2/Android.mk b/tools/preload2/Android.mk new file mode 100644 index 000000000000..35d28fbfeba8 --- /dev/null +++ b/tools/preload2/Android.mk @@ -0,0 +1,32 @@ +LOCAL_PATH:= $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := $(call all-java-files-under,src) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk + +# To connect to devices (and take hprof dumps). +LOCAL_STATIC_JAVA_LIBRARIES := ddmlib-prebuilt + +# To process hprof dumps. +LOCAL_STATIC_JAVA_LIBRARIES += perflib-prebuilt trove-prebuilt guavalib + +# For JDWP access we use the framework in the JDWP tests from Apache Harmony, for +# convenience (and to not depend on internal JDK APIs). +LOCAL_STATIC_JAVA_LIBRARIES += apache-harmony-jdwp-tests-host junit + +LOCAL_MODULE:= preload2 + +include $(BUILD_HOST_JAVA_LIBRARY) + +# Copy the preload-tool shell script to the host's bin directory. +include $(CLEAR_VARS) +LOCAL_IS_HOST_MODULE := true +LOCAL_MODULE_TAGS := optional +LOCAL_MODULE_CLASS := EXECUTABLES +LOCAL_MODULE := preload-tool +include $(BUILD_SYSTEM)/base_rules.mk +$(LOCAL_BUILT_MODULE): $(LOCAL_PATH)/preload-tool $(ACP) + @echo "Copy: $(PRIVATE_MODULE) ($@)" + $(copy-file-to-new-target) + $(hide) chmod 755 $@ diff --git a/tools/preload2/preload-tool b/tools/preload2/preload-tool new file mode 100644 index 000000000000..36dbc1c775b1 --- /dev/null +++ b/tools/preload2/preload-tool @@ -0,0 +1,37 @@ +# 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. + +# This script is used on the host only. It uses a common subset +# shell dialect that should work well. It is partially derived +# from art/tools/art. + +function follow_links() { + if [ z"$BASH_SOURCE" != z ]; then + file="$BASH_SOURCE" + else + file="$0" + fi + while [ -h "$file" ]; do + # On Mac OS, readlink -f doesn't work. + file="$(readlink "$file")" + done + echo "$file" +} + + +PROG_NAME="$(follow_links)" +PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)" +ANDROID_ROOT=$PROG_DIR/.. + +java -cp $ANDROID_ROOT/framework/preload2.jar com.android.preload.Main diff --git a/tools/preload2/src/com/android/preload/ClientUtils.java b/tools/preload2/src/com/android/preload/ClientUtils.java new file mode 100644 index 000000000000..71ef025d6587 --- /dev/null +++ b/tools/preload2/src/com/android/preload/ClientUtils.java @@ -0,0 +1,224 @@ +/* + * 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.preload; + +import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.AndroidDebugBridge.IClientChangeListener; +import com.android.ddmlib.Client; +import com.android.ddmlib.IDevice; + +/** + * Helper class for common communication with a Client (the ddms name for a running application). + * + * Instances take a default timeout parameter that's applied to all functions without explicit + * timeout. Timeouts are in milliseconds. + */ +public class ClientUtils { + + private int defaultTimeout; + + public ClientUtils() { + this(10000); + } + + public ClientUtils(int defaultTimeout) { + this.defaultTimeout = defaultTimeout; + } + + /** + * Shortcut for findClient with default timeout. + */ + public Client findClient(IDevice device, String processName, int processPid) { + return findClient(device, processName, processPid, defaultTimeout); + } + + /** + * Find the client with the given process name or process id. The name takes precedence over + * the process id (if valid). Stop looking after the given timeout. + * + * @param device The device to communicate with. + * @param processName The name of the process. May be null. + * @param processPid The pid of the process. Values less than or equal to zero are ignored. + * @param timeout The amount of milliseconds to wait, at most. + * @return The client, if found. Otherwise null. + */ + public Client findClient(IDevice device, String processName, int processPid, int timeout) { + WaitForClient wfc = new WaitForClient(device, processName, processPid, timeout); + return wfc.get(); + } + + /** + * Shortcut for findAllClients with default timeout. + */ + public Client[] findAllClients(IDevice device) { + return findAllClients(device, defaultTimeout); + } + + /** + * Retrieve all clients known to the given device. Wait at most the given timeout. + * + * @param device The device to investigate. + * @param timeout The amount of milliseconds to wait, at most. + * @return An array of clients running on the given device. May be null depending on the + * device implementation. + */ + public Client[] findAllClients(IDevice device, int timeout) { + if (device.hasClients()) { + return device.getClients(); + } + WaitForClients wfc = new WaitForClients(device, timeout); + return wfc.get(); + } + + private static class WaitForClient implements IClientChangeListener { + + private IDevice device; + private String processName; + private int processPid; + private long timeout; + private Client result; + + public WaitForClient(IDevice device, String processName, int processPid, long timeout) { + this.device = device; + this.processName = processName; + this.processPid = processPid; + this.timeout = timeout; + this.result = null; + } + + public Client get() { + synchronized (this) { + AndroidDebugBridge.addClientChangeListener(this); + + // Maybe it's already there. + if (result == null) { + result = searchForClient(device); + } + + if (result == null) { + try { + wait(timeout); + } catch (InterruptedException e) { + // Note: doesn't guard for spurious wakeup. + } + } + } + + AndroidDebugBridge.removeClientChangeListener(this); + return result; + } + + private Client searchForClient(IDevice device) { + if (processName != null) { + Client tmp = device.getClient(processName); + if (tmp != null) { + return tmp; + } + } + if (processPid > 0) { + String name = device.getClientName(processPid); + if (name != null && !name.isEmpty()) { + Client tmp = device.getClient(name); + if (tmp != null) { + return tmp; + } + } + } + if (processPid > 0) { + // Try manual search. + for (Client cl : device.getClients()) { + if (cl.getClientData().getPid() == processPid + && cl.getClientData().getClientDescription() != null) { + return cl; + } + } + } + return null; + } + + private boolean isTargetClient(Client c) { + if (processPid > 0 && c.getClientData().getPid() == processPid) { + return true; + } + if (processName != null + && processName.equals(c.getClientData().getClientDescription())) { + return true; + } + return false; + } + + @Override + public void clientChanged(Client arg0, int arg1) { + synchronized (this) { + if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) { + if (isTargetClient(arg0)) { + result = arg0; + notifyAll(); + } + } + } + } + } + + private static class WaitForClients implements IClientChangeListener { + + private IDevice device; + private long timeout; + + public WaitForClients(IDevice device, long timeout) { + this.device = device; + this.timeout = timeout; + } + + public Client[] get() { + synchronized (this) { + AndroidDebugBridge.addClientChangeListener(this); + + if (device.hasClients()) { + return device.getClients(); + } + + try { + wait(timeout); // Note: doesn't guard for spurious wakeup. + } catch (InterruptedException exc) { + } + + // We will be woken up when the first client data arrives. Sleep a little longer + // to give (hopefully all of) the rest of the clients a chance to become available. + // Note: a loop with timeout is brittle as well and complicated, just accept this + // for now. + try { + Thread.sleep(500); + } catch (InterruptedException exc) { + } + } + + AndroidDebugBridge.removeClientChangeListener(this); + + return device.getClients(); + } + + @Override + public void clientChanged(Client arg0, int arg1) { + synchronized (this) { + if ((arg1 & Client.CHANGE_INFO) != 0 && (arg0.getDevice() == device)) { + notifyAll(); + } + } + } + } +} diff --git a/tools/preload2/src/com/android/preload/DeviceUtils.java b/tools/preload2/src/com/android/preload/DeviceUtils.java new file mode 100644 index 000000000000..72de7b58b0a7 --- /dev/null +++ b/tools/preload2/src/com/android/preload/DeviceUtils.java @@ -0,0 +1,390 @@ +/* + * 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.preload; + +import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; +import com.android.preload.classdataretrieval.hprof.Hprof; +import com.android.ddmlib.DdmPreferences; +import com.android.ddmlib.IDevice; +import com.android.ddmlib.IShellOutputReceiver; + +import java.util.Date; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +/** + * Helper class for some device routines. + */ +public class DeviceUtils { + + public static void init(int debugPort) { + DdmPreferences.setSelectedDebugPort(debugPort); + + Hprof.init(); + + AndroidDebugBridge.init(true); + + AndroidDebugBridge.createBridge(); + } + + /** + * Run a command in the shell on the device. + */ + public static void doShell(IDevice device, String cmdline, long timeout, TimeUnit unit) { + doShell(device, cmdline, new NullShellOutputReceiver(), timeout, unit); + } + + /** + * Run a command in the shell on the device. Collects and returns the console output. + */ + public static String doShellReturnString(IDevice device, String cmdline, long timeout, + TimeUnit unit) { + CollectStringShellOutputReceiver rec = new CollectStringShellOutputReceiver(); + doShell(device, cmdline, rec, timeout, unit); + return rec.toString(); + } + + /** + * Run a command in the shell on the device, directing all output to the given receiver. + */ + public static void doShell(IDevice device, String cmdline, IShellOutputReceiver receiver, + long timeout, TimeUnit unit) { + try { + device.executeShellCommand(cmdline, receiver, timeout, unit); + } catch (Exception e) { + e.printStackTrace(); + } + } + + /** + * Run am start on the device. + */ + public static void doAMStart(IDevice device, String name, String activity) { + doShell(device, "am start -n " + name + " /." + activity, 30, TimeUnit.SECONDS); + } + + /** + * Find the device with the given serial. Give up after the given timeout (in milliseconds). + */ + public static IDevice findDevice(String serial, int timeout) { + WaitForDevice wfd = new WaitForDevice(serial, timeout); + return wfd.get(); + } + + /** + * Get all devices ddms knows about. Wait at most for the given timeout. + */ + public static IDevice[] findDevices(int timeout) { + WaitForDevice wfd = new WaitForDevice(null, timeout); + wfd.get(); + return AndroidDebugBridge.getBridge().getDevices(); + } + + /** + * Return the build type of the given device. This is the value of the "ro.build.type" + * system property. + */ + public static String getBuildType(IDevice device) { + try { + Future<String> buildType = device.getSystemProperty("ro.build.type"); + return buildType.get(500, TimeUnit.MILLISECONDS); + } catch (Exception e) { + } + return null; + } + + /** + * Check whether the given device has a pre-optimized boot image. More precisely, checks + * whether /system/framework/ * /boot.art exists. + */ + public static boolean hasPrebuiltBootImage(IDevice device) { + String ret = + doShellReturnString(device, "ls /system/framework/*/boot.art", 500, TimeUnit.MILLISECONDS); + + return !ret.contains("No such file or directory"); + } + + /** + * Remove files involved in a standard build that interfere with collecting data. This will + * remove /etc/preloaded-classes, which determines which classes are allocated already in the + * boot image. It also deletes any compiled boot image on the device. Then it restarts the + * device. + * + * This is a potentially long-running operation, as the boot after the deletion may take a while. + * The method will abort after the given timeout. + */ + public static boolean removePreloaded(IDevice device, long preloadedWaitTimeInSeconds) { + String oldContent = + DeviceUtils.doShellReturnString(device, "cat /etc/preloaded-classes", 1, TimeUnit.SECONDS); + if (oldContent.trim().equals("")) { + System.out.println("Preloaded-classes already empty."); + return true; + } + + // Stop the system server etc. + doShell(device, "stop", 100, TimeUnit.MILLISECONDS); + + // Remount /system, delete /etc/preloaded-classes. It would be nice to use "adb remount," + // but AndroidDebugBridge doesn't expose it. + doShell(device, "mount -o remount,rw /system", 500, TimeUnit.MILLISECONDS); + doShell(device, "rm /etc/preloaded-classes", 100, TimeUnit.MILLISECONDS); + // We do need an empty file. + doShell(device, "touch /etc/preloaded-classes", 100, TimeUnit.MILLISECONDS); + + // Delete the files in the dalvik cache. + doShell(device, "rm /data/dalvik-cache/*/*boot.art", 500, TimeUnit.MILLISECONDS); + + // We'll try to use dev.bootcomplete to know when the system server is back up. But stop + // doesn't reset it, so do it manually. + doShell(device, "setprop dev.bootcomplete \"0\"", 500, TimeUnit.MILLISECONDS); + + // Start the system server. + doShell(device, "start", 100, TimeUnit.MILLISECONDS); + + // Do a loop checking each second whether bootcomplete. Wait for at most the given + // threshold. + Date startDate = new Date(); + for (;;) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // Ignore spurious wakeup. + } + // Check whether bootcomplete. + String ret = + doShellReturnString(device, "getprop dev.bootcomplete", 500, TimeUnit.MILLISECONDS); + if (ret.trim().equals("1")) { + break; + } + System.out.println("Still not booted: " + ret); + + // Check whether we timed out. This is a simplistic check that doesn't take into account + // things like switches in time. + Date endDate = new Date(); + long seconds = + TimeUnit.SECONDS.convert(endDate.getTime() - startDate.getTime(), TimeUnit.MILLISECONDS); + if (seconds > preloadedWaitTimeInSeconds) { + return false; + } + } + + return true; + } + + /** + * Enable method-tracing on device. The system should be restarted after this. + */ + public static void enableTracing(IDevice device) { + // Disable selinux. + doShell(device, "setenforce 0", 100, TimeUnit.MILLISECONDS); + + // Make the profile directory world-writable. + doShell(device, "chmod 777 /data/dalvik-cache/profiles", 100, TimeUnit.MILLISECONDS); + + // Enable streaming method tracing with a small 1K buffer. + doShell(device, "setprop dalvik.vm.method-trace true", 100, TimeUnit.MILLISECONDS); + doShell(device, "setprop dalvik.vm.method-trace-file " + + "/data/dalvik-cache/profiles/zygote.trace.bin", 100, TimeUnit.MILLISECONDS); + doShell(device, "setprop dalvik.vm.method-trace-file-siz 1024", 100, TimeUnit.MILLISECONDS); + doShell(device, "setprop dalvik.vm.method-trace-stream true", 100, TimeUnit.MILLISECONDS); + } + + private static class NullShellOutputReceiver implements IShellOutputReceiver { + @Override + public boolean isCancelled() { + return false; + } + + @Override + public void flush() {} + + @Override + public void addOutput(byte[] arg0, int arg1, int arg2) {} + } + + private static class CollectStringShellOutputReceiver implements IShellOutputReceiver { + + private StringBuilder builder = new StringBuilder(); + + @Override + public String toString() { + String ret = builder.toString(); + // Strip trailing newlines. They are especially ugly because adb uses DOS line endings. + while (ret.endsWith("\r") || ret.endsWith("\n")) { + ret = ret.substring(0, ret.length() - 1); + } + return ret; + } + + @Override + public void addOutput(byte[] arg0, int arg1, int arg2) { + builder.append(new String(arg0, arg1, arg2)); + } + + @Override + public void flush() {} + + @Override + public boolean isCancelled() { + return false; + } + } + + private static class WaitForDevice { + + private String serial; + private long timeout; + private IDevice device; + + public WaitForDevice(String serial, long timeout) { + this.serial = serial; + this.timeout = timeout; + device = null; + } + + public IDevice get() { + if (device == null) { + WaitForDeviceListener wfdl = new WaitForDeviceListener(serial); + synchronized (wfdl) { + AndroidDebugBridge.addDeviceChangeListener(wfdl); + + // Check whether we already know about this device. + IDevice[] devices = AndroidDebugBridge.getBridge().getDevices(); + if (serial != null) { + for (IDevice d : devices) { + if (serial.equals(d.getSerialNumber())) { + // Only accept if there are clients already. Else wait for the callback informing + // us that we now have clients. + if (d.hasClients()) { + device = d; + } + + break; + } + } + } else { + if (devices.length > 0) { + device = devices[0]; + } + } + + if (device == null) { + try { + wait(timeout); + } catch (InterruptedException e) { + // Ignore spurious wakeups. + } + device = wfdl.getDevice(); + } + + AndroidDebugBridge.removeDeviceChangeListener(wfdl); + } + } + + if (device != null) { + // Wait for clients. + WaitForClientsListener wfcl = new WaitForClientsListener(device); + synchronized (wfcl) { + AndroidDebugBridge.addDeviceChangeListener(wfcl); + + if (!device.hasClients()) { + try { + wait(timeout); + } catch (InterruptedException e) { + // Ignore spurious wakeups. + } + } + + AndroidDebugBridge.removeDeviceChangeListener(wfcl); + } + } + + return device; + } + + private static class WaitForDeviceListener implements IDeviceChangeListener { + + private String serial; + private IDevice device; + + public WaitForDeviceListener(String serial) { + this.serial = serial; + } + + public IDevice getDevice() { + return device; + } + + @Override + public void deviceChanged(IDevice arg0, int arg1) { + // We may get a device changed instead of connected. Handle like a connection. + deviceConnected(arg0); + } + + @Override + public void deviceConnected(IDevice arg0) { + if (device != null) { + // Ignore updates. + return; + } + + if (serial == null || serial.equals(arg0.getSerialNumber())) { + device = arg0; + synchronized (this) { + notifyAll(); + } + } + } + + @Override + public void deviceDisconnected(IDevice arg0) { + // Ignore disconnects. + } + + } + + private static class WaitForClientsListener implements IDeviceChangeListener { + + private IDevice myDevice; + + public WaitForClientsListener(IDevice myDevice) { + this.myDevice = myDevice; + } + + @Override + public void deviceChanged(IDevice arg0, int arg1) { + if (arg0 == myDevice && (arg1 & IDevice.CHANGE_CLIENT_LIST) != 0) { + // Got a client list, done here. + synchronized (this) { + notifyAll(); + } + } + } + + @Override + public void deviceConnected(IDevice arg0) { + } + + @Override + public void deviceDisconnected(IDevice arg0) { + } + + } + } + +} diff --git a/tools/preload2/src/com/android/preload/DumpData.java b/tools/preload2/src/com/android/preload/DumpData.java new file mode 100644 index 000000000000..d99722416a1d --- /dev/null +++ b/tools/preload2/src/com/android/preload/DumpData.java @@ -0,0 +1,91 @@ +/* + * 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.preload; + +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * Holds the collected data for a process. + */ +public class DumpData { + /** + * Name of the package (=application). + */ + String packageName; + + /** + * A map of class name to a string for the classloader. This may be a toString equivalent, + * or just a unique ID. + */ + Map<String, String> dumpData; + + /** + * The Date when this data was captured. Mostly for display purposes. + */ + Date date; + + /** + * A cached value for the number of boot classpath classes (classloader value in dumpData is + * null). + */ + int bcpClasses; + + public DumpData(String packageName, Map<String, String> dumpData, Date date) { + this.packageName = packageName; + this.dumpData = dumpData; + this.date = date; + + countBootClassPath(); + } + + public String getPackageName() { + return packageName; + } + + public Date getDate() { + return date; + } + + public Map<String, String> getDumpData() { + return dumpData; + } + + public void countBootClassPath() { + bcpClasses = 0; + for (Map.Entry<String, String> e : dumpData.entrySet()) { + if (e.getValue() == null) { + bcpClasses++; + } + } + } + + // Return an inverted mapping. + public Map<String, Set<String>> invertData() { + Map<String, Set<String>> ret = new HashMap<>(); + for (Map.Entry<String, String> e : dumpData.entrySet()) { + if (!ret.containsKey(e.getValue())) { + ret.put(e.getValue(), new HashSet<String>()); + } + ret.get(e.getValue()).add(e.getKey()); + } + return ret; + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/DumpDataIO.java b/tools/preload2/src/com/android/preload/DumpDataIO.java new file mode 100644 index 000000000000..28625c5531e4 --- /dev/null +++ b/tools/preload2/src/com/android/preload/DumpDataIO.java @@ -0,0 +1,141 @@ +/* + * 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.preload; + +import org.xml.sax.Attributes; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.DefaultHandler; + +import java.io.File; +import java.io.FileReader; +import java.text.DateFormat; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; + +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +/** + * Helper class for serialization and deserialization of a collection of DumpData objects to XML. + */ +public class DumpDataIO { + + /** + * Serialize the given collection to an XML document. Returns the produced string. + */ + public static String serialize(Collection<DumpData> data) { + // We'll do this by hand, constructing a DOM or similar is too complicated for our simple + // use case. + + StringBuilder sb = new StringBuilder(); + sb.append("<preloaded-classes-data>\n"); + + for (DumpData d : data) { + serialize(d, sb); + } + + sb.append("</preloaded-classes-data>\n"); + return sb.toString(); + } + + private static void serialize(DumpData d, StringBuilder sb) { + sb.append("<data package=\"" + d.packageName + "\" date=\"" + + DateFormat.getDateTimeInstance().format(d.date) +"\">\n"); + + for (Map.Entry<String, String> e : d.dumpData.entrySet()) { + sb.append("<class name=\"" + e.getKey() + "\" classloader=\"" + e.getValue() + "\"/>\n"); + } + + sb.append("</data>\n"); + } + + /** + * Load a collection of DumpData objects from the given file. + */ + public static Collection<DumpData> deserialize(File f) throws Exception { + // Use SAX parsing. Our format is very simple. Don't do any schema validation or such. + + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(false); + SAXParser saxParser = spf.newSAXParser(); + + XMLReader xmlReader = saxParser.getXMLReader(); + DumpDataContentHandler ddch = new DumpDataContentHandler(); + xmlReader.setContentHandler(ddch); + xmlReader.parse(new InputSource(new FileReader(f))); + + return ddch.data; + } + + private static class DumpDataContentHandler extends DefaultHandler { + Collection<DumpData> data = new LinkedList<DumpData>(); + DumpData openData = null; + + @Override + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { + if (qName.equals("data")) { + if (openData != null) { + throw new IllegalStateException(); + } + String pkg = attributes.getValue("package"); + String dateString = attributes.getValue("date"); + + if (pkg == null || dateString == null) { + throw new IllegalArgumentException(); + } + + try { + Date date = DateFormat.getDateTimeInstance().parse(dateString); + openData = new DumpData(pkg, new HashMap<String, String>(), date); + } catch (Exception e) { + throw new RuntimeException(e); + } + } else if (qName.equals("class")) { + if (openData == null) { + throw new IllegalStateException(); + } + String className = attributes.getValue("name"); + String classLoader = attributes.getValue("classloader"); + + if (className == null || classLoader == null) { + throw new IllegalArgumentException(); + } + + openData.dumpData.put(className, classLoader.equals("null") ? null : classLoader); + } + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (qName.equals("data")) { + if (openData == null) { + throw new IllegalStateException(); + } + openData.countBootClassPath(); + + data.add(openData); + openData = null; + } + } + } +} diff --git a/tools/preload2/src/com/android/preload/DumpTableModel.java b/tools/preload2/src/com/android/preload/DumpTableModel.java new file mode 100644 index 000000000000..d97cbf0df5e5 --- /dev/null +++ b/tools/preload2/src/com/android/preload/DumpTableModel.java @@ -0,0 +1,93 @@ +/* + * 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.preload; + +import java.util.ArrayList; +import java.util.List; + +import javax.swing.table.AbstractTableModel; + +/** + * A table model for collected DumpData. This is both the internal storage as well as the model + * for display. + */ +public class DumpTableModel extends AbstractTableModel { + + private List<DumpData> data = new ArrayList<DumpData>(); + + public void addData(DumpData d) { + data.add(d); + fireTableRowsInserted(data.size() - 1, data.size() - 1); + } + + public void clear() { + int size = data.size(); + if (size > 0) { + data.clear(); + fireTableRowsDeleted(0, size - 1); + } + } + + public List<DumpData> getData() { + return data; + } + + @Override + public int getRowCount() { + return data.size(); + } + + @Override + public int getColumnCount() { + return 4; + } + + @Override + public String getColumnName(int column) { + switch (column) { + case 0: + return "Package"; + case 1: + return "Date"; + case 2: + return "# All Classes"; + case 3: + return "# Boot Classpath Classes"; + + default: + throw new IndexOutOfBoundsException(String.valueOf(column)); + } + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + DumpData d = data.get(rowIndex); + switch (columnIndex) { + case 0: + return d.packageName; + case 1: + return d.date; + case 2: + return d.dumpData.size(); + case 3: + return d.bcpClasses; + + default: + throw new IndexOutOfBoundsException(String.valueOf(columnIndex)); + } + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/Main.java b/tools/preload2/src/com/android/preload/Main.java new file mode 100644 index 000000000000..ca5b0e005a1d --- /dev/null +++ b/tools/preload2/src/com/android/preload/Main.java @@ -0,0 +1,242 @@ +/* + * 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.preload; + +import com.android.ddmlib.Client; +import com.android.ddmlib.IDevice; +import com.android.preload.actions.ClearTableAction; +import com.android.preload.actions.ComputeThresholdAction; +import com.android.preload.actions.ComputeThresholdXAction; +import com.android.preload.actions.DeviceSpecific; +import com.android.preload.actions.ExportAction; +import com.android.preload.actions.ImportAction; +import com.android.preload.actions.ReloadListAction; +import com.android.preload.actions.RunMonkeyAction; +import com.android.preload.actions.ScanAllPackagesAction; +import com.android.preload.actions.ScanPackageAction; +import com.android.preload.actions.ShowDataAction; +import com.android.preload.classdataretrieval.ClassDataRetriever; +import com.android.preload.classdataretrieval.hprof.Hprof; +import com.android.preload.classdataretrieval.jdwp.JDWPClassDataRetriever; +import com.android.preload.ui.UI; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import javax.swing.Action; +import javax.swing.DefaultListModel; + +public class Main { + + /** + * Enable tracing mode. This is a work-in-progress to derive compiled-methods data, so it is + * off for now. + */ + public final static boolean ENABLE_TRACING = false; + + /** + * Ten-second timeout. + */ + public final static int DEFAULT_TIMEOUT_MILLIS = 10 * 1000; + + /** + * Hprof timeout. Two minutes. + */ + public final static int HPROF_TIMEOUT_MILLIS = 120 * 1000; + + private IDevice device; + private static ClientUtils clientUtils; + + private DumpTableModel dataTableModel; + private DefaultListModel<Client> clientListModel; + + private UI ui; + + // Actions that need to be updated once a device is selected. + private Collection<DeviceSpecific> deviceSpecificActions; + + // Current main instance. + private static Main top; + private static boolean useJdwpClassDataRetriever = false; + + public final static String CLASS_PRELOAD_BLACKLIST = "android.app.AlarmManager$" + "|" + + "android.app.SearchManager$" + "|" + "android.os.FileObserver$" + "|" + + "com.android.server.PackageManagerService\\$AppDirObserver$" + "|" + + + + // Threads + "android.os.AsyncTask$" + "|" + "android.pim.ContactsAsyncHelper$" + "|" + + "android.webkit.WebViewClassic\\$1$" + "|" + "java.lang.ProcessManager$" + "|" + + "(.*\\$NoPreloadHolder$)"; + + /** + * @param args + */ + public static void main(String[] args) { + Main m = new Main(); + top = m; + + m.startUp(); + } + + public Main() { + clientListModel = new DefaultListModel<Client>(); + dataTableModel = new DumpTableModel(); + + clientUtils = new ClientUtils(DEFAULT_TIMEOUT_MILLIS); // Client utils with 10s timeout. + + List<Action> actions = new ArrayList<Action>(); + actions.add(new ReloadListAction(clientUtils, null, clientListModel)); + actions.add(new ClearTableAction(dataTableModel)); + actions.add(new RunMonkeyAction(null, dataTableModel)); + actions.add(new ScanPackageAction(clientUtils, null, dataTableModel)); + actions.add(new ScanAllPackagesAction(clientUtils, null, dataTableModel)); + actions.add(new ComputeThresholdAction("Compute preloaded-classes", dataTableModel, 2, + CLASS_PRELOAD_BLACKLIST)); + actions.add(new ComputeThresholdAction("Compute compiled-classes", dataTableModel, 1, + null)); + actions.add(new ComputeThresholdXAction("Compute(X)", dataTableModel, + CLASS_PRELOAD_BLACKLIST)); + actions.add(new ShowDataAction(dataTableModel)); + actions.add(new ImportAction(dataTableModel)); + actions.add(new ExportAction(dataTableModel)); + + deviceSpecificActions = new ArrayList<DeviceSpecific>(); + for (Action a : actions) { + if (a instanceof DeviceSpecific) { + deviceSpecificActions.add((DeviceSpecific)a); + } + } + + ui = new UI(clientListModel, dataTableModel, actions); + ui.setVisible(true); + } + + public static UI getUI() { + return top.ui; + } + + public static ClassDataRetriever getClassDataRetriever() { + if (useJdwpClassDataRetriever) { + return new JDWPClassDataRetriever(); + } else { + return new Hprof(HPROF_TIMEOUT_MILLIS); + } + } + + public IDevice getDevice() { + return device; + } + + public void setDevice(IDevice device) { + this.device = device; + for (DeviceSpecific ds : deviceSpecificActions) { + ds.setDevice(device); + } + } + + public DefaultListModel<Client> getClientListModel() { + return clientListModel; + } + + static class DeviceWrapper { + IDevice device; + + public DeviceWrapper(IDevice d) { + device = d; + } + + @Override + public String toString() { + return device.getName() + " (#" + device.getSerialNumber() + ")"; + } + } + + private void startUp() { + getUI().showWaitDialog(); + initDevice(); + + // Load clients. + new ReloadListAction(clientUtils, getDevice(), clientListModel).run(); + + getUI().hideWaitDialog(); + } + + private void initDevice() { + DeviceUtils.init(DEFAULT_TIMEOUT_MILLIS); + + IDevice devices[] = DeviceUtils.findDevices(DEFAULT_TIMEOUT_MILLIS); + if (devices == null || devices.length == 0) { + throw new RuntimeException("Could not find any devices..."); + } + + getUI().hideWaitDialog(); + + DeviceWrapper deviceWrappers[] = new DeviceWrapper[devices.length]; + for (int i = 0; i < devices.length; i++) { + deviceWrappers[i] = new DeviceWrapper(devices[i]); + } + + DeviceWrapper ret = Main.getUI().showChoiceDialog("Choose a device", "Choose device", + deviceWrappers); + if (ret != null) { + setDevice(ret.device); + } else { + System.exit(0); + } + + boolean prepare = Main.getUI().showConfirmDialog("Prepare device?", + "Do you want to prepare the device? This is highly recommended."); + if (prepare) { + String buildType = DeviceUtils.getBuildType(device); + if (buildType == null || (!buildType.equals("userdebug") && !buildType.equals("eng"))) { + Main.getUI().showMessageDialog("Need a userdebug or eng build! (Found " + buildType + + ")"); + return; + } + if (DeviceUtils.hasPrebuiltBootImage(device)) { + Main.getUI().showMessageDialog("Cannot prepare a device with pre-optimized boot " + + "image!"); + return; + } + + if (ENABLE_TRACING) { + DeviceUtils.enableTracing(device); + } + + Main.getUI().showMessageDialog("The device will reboot. This will potentially take a " + + "long time. Please be patient."); + if (!DeviceUtils.removePreloaded(device, 15 * 60) /* 15m timeout */) { + Main.getUI().showMessageDialog("Removing preloaded-classes failed unexpectedly!"); + } + } + } + + public static Map<String, String> findAndGetClassData(IDevice device, String packageName) + throws Exception { + Client client = clientUtils.findClient(device, packageName, -1); + if (client == null) { + throw new RuntimeException("Could not find client..."); + } + System.out.println("Found client: " + client); + + return getClassDataRetriever().getClassData(client); + } + +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java index 74535dd94987..fbf83d2e2339 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/RenderableBase.java +++ b/tools/preload2/src/com/android/preload/actions/AbstractThreadedAction.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * 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. @@ -14,26 +14,21 @@ * limitations under the License. */ -package com.android.scenegraph; +package com.android.preload.actions; -import java.lang.Math; -import java.util.ArrayList; - -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.util.Log; - -/** - * @hide - */ -public class RenderableBase extends SceneGraphBase { - public RenderableBase() { - } -} +import java.awt.event.ActionEvent; +import javax.swing.AbstractAction; +public abstract class AbstractThreadedAction extends AbstractAction implements Runnable { + protected AbstractThreadedAction(String title) { + super(title); + } + @Override + public void actionPerformed(ActionEvent e) { + new Thread(this).start(); + } +} diff --git a/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java b/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java new file mode 100644 index 000000000000..7906417b7a8d --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/AbstractThreadedDeviceSpecificAction.java @@ -0,0 +1,45 @@ +/* + * 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.preload.actions; + +import com.android.ddmlib.IDevice; + +import java.awt.event.ActionEvent; + +public abstract class AbstractThreadedDeviceSpecificAction extends AbstractThreadedAction + implements DeviceSpecific { + + protected IDevice device; + + protected AbstractThreadedDeviceSpecificAction(String title, IDevice device) { + super(title); + this.device = device; + } + + @Override + public void setDevice(IDevice device) { + this.device = device; + } + + @Override + public void actionPerformed(ActionEvent e) { + if (device == null) { + return; + } + super.actionPerformed(e); + } +} diff --git a/tools/preload2/src/com/android/preload/actions/ClearTableAction.java b/tools/preload2/src/com/android/preload/actions/ClearTableAction.java new file mode 100644 index 000000000000..c0e4795b6d90 --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ClearTableAction.java @@ -0,0 +1,37 @@ +/* + * 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.preload.actions; + +import com.android.preload.DumpTableModel; + +import java.awt.event.ActionEvent; + +import javax.swing.AbstractAction; + +public class ClearTableAction extends AbstractAction { + private final DumpTableModel dataTableModel; + + public ClearTableAction(DumpTableModel dataTableModel) { + super("Clear"); + this.dataTableModel = dataTableModel; + } + + @Override + public void actionPerformed(ActionEvent e) { + dataTableModel.clear(); + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java new file mode 100644 index 000000000000..b524716fc2cb --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ComputeThresholdAction.java @@ -0,0 +1,151 @@ +/* + * 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.preload.actions; + +import com.android.preload.DumpData; +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.regex.Pattern; + +import javax.swing.AbstractAction; +import javax.swing.JFileChooser; + +/** + * Compute an intersection of classes from the given data. A class is in the intersection if it + * appears in at least the number of threshold given packages. An optional blacklist can be + * used to filter classes from the intersection. + */ +public class ComputeThresholdAction extends AbstractAction implements Runnable { + protected int threshold; + private Pattern blacklist; + private DumpTableModel dataTableModel; + + /** + * Create an action with the given parameters. The blacklist is a regular expression + * that filters classes. + */ + public ComputeThresholdAction(String name, DumpTableModel dataTableModel, int threshold, + String blacklist) { + super(name); + this.dataTableModel = dataTableModel; + this.threshold = threshold; + if (blacklist != null) { + this.blacklist = Pattern.compile(blacklist); + } + } + + @Override + public void actionPerformed(ActionEvent e) { + List<DumpData> data = dataTableModel.getData(); + if (data.size() == 0) { + Main.getUI().showMessageDialog("No data available, please scan packages or run " + + "monkeys."); + return; + } + if (data.size() == 1) { + Main.getUI().showMessageDialog("Cannot compute list from only one data set, please " + + "scan packages or run monkeys."); + return; + } + + new Thread(this).start(); + } + + @Override + public void run() { + Main.getUI().showWaitDialog(); + + Map<String, Set<String>> uses = new HashMap<String, Set<String>>(); + for (DumpData d : dataTableModel.getData()) { + Main.getUI().updateWaitDialog("Merging " + d.getPackageName()); + updateClassUse(d.getPackageName(), uses, getBootClassPathClasses(d.getDumpData())); + } + + Main.getUI().updateWaitDialog("Computing thresholded set"); + Set<String> result = fromThreshold(uses, blacklist, threshold); + Main.getUI().hideWaitDialog(); + + boolean ret = Main.getUI().showConfirmDialog("Computed a set with " + result.size() + + " classes, would you like to save to disk?", "Save?"); + if (ret) { + JFileChooser jfc = new JFileChooser(); + int ret2 = jfc.showSaveDialog(Main.getUI()); + if (ret2 == JFileChooser.APPROVE_OPTION) { + File f = jfc.getSelectedFile(); + saveSet(result, f); + } + } + } + + private Set<String> fromThreshold(Map<String, Set<String>> classUses, Pattern blacklist, + int threshold) { + TreeSet<String> ret = new TreeSet<>(); // TreeSet so it's nicely ordered by name. + + for (Map.Entry<String, Set<String>> e : classUses.entrySet()) { + if (e.getValue().size() >= threshold) { + if (blacklist == null || !blacklist.matcher(e.getKey()).matches()) { + ret.add(e.getKey()); + } + } + } + + return ret; + } + + private static void updateClassUse(String pkg, Map<String, Set<String>> classUses, + Set<String> classes) { + for (String className : classes) { + Set<String> old = classUses.get(className); + if (old == null) { + classUses.put(className, new HashSet<String>()); + } + classUses.get(className).add(pkg); + } + } + + private static Set<String> getBootClassPathClasses(Map<String, String> source) { + Set<String> ret = new HashSet<>(); + for (Map.Entry<String, String> e : source.entrySet()) { + if (e.getValue() == null) { + ret.add(e.getKey()); + } + } + return ret; + } + + private static void saveSet(Set<String> result, File f) { + try { + PrintWriter out = new PrintWriter(f); + for (String s : result) { + out.println(s); + } + out.close(); + } catch (Exception e) { + e.printStackTrace(); + } + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java b/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java new file mode 100644 index 000000000000..3ec0a4c18db1 --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ComputeThresholdXAction.java @@ -0,0 +1,41 @@ +/* + * 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.preload.actions; + +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +public class ComputeThresholdXAction extends ComputeThresholdAction { + + public ComputeThresholdXAction(String name, DumpTableModel dataTableModel, + String blacklist) { + super(name, dataTableModel, 1, blacklist); + } + + @Override + public void run() { + String value = Main.getUI().showInputDialog("Threshold?"); + + if (value != null) { + try { + threshold = Integer.parseInt(value); + super.run(); + } catch (Exception exc) { + } + } + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java b/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java new file mode 100644 index 000000000000..35a8f26a99fe --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/DeviceSpecific.java @@ -0,0 +1,38 @@ +/* + * 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.preload.actions; + +import com.android.ddmlib.IDevice; + +/** + * Marks an action as being device-specific. The user must set the device through the specified + * method if the device selection changes. + * + * Implementors must tolerate a null device (for example, with a no-op). This includes calling + * any methods before setDevice has been called. + */ +public interface DeviceSpecific { + + /** + * Set the device that should be used. Note that there is no restriction on calling other + * methods of the implementor before a setDevice call. Neither is device guaranteed to be + * non-null. + * + * @param device The device to use going forward. + */ + public void setDevice(IDevice device); +} diff --git a/tools/preload2/src/com/android/preload/actions/ExportAction.java b/tools/preload2/src/com/android/preload/actions/ExportAction.java new file mode 100644 index 000000000000..cb8b3df75b18 --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ExportAction.java @@ -0,0 +1,65 @@ +/* + * 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.preload.actions; + +import com.android.preload.DumpDataIO; +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.io.PrintWriter; + +import javax.swing.AbstractAction; + +public class ExportAction extends AbstractAction implements Runnable { + private File lastSaveFile; + private DumpTableModel dataTableModel; + + public ExportAction(DumpTableModel dataTableModel) { + super("Export data"); + this.dataTableModel = dataTableModel; + } + + @Override + public void actionPerformed(ActionEvent e) { + lastSaveFile = Main.getUI().showSaveDialog(); + if (lastSaveFile != null) { + new Thread(this).start(); + } + } + + @Override + public void run() { + Main.getUI().showWaitDialog(); + + String serialized = DumpDataIO.serialize(dataTableModel.getData()); + + if (serialized != null) { + try { + PrintWriter out = new PrintWriter(lastSaveFile); + out.println(serialized); + out.close(); + + Main.getUI().hideWaitDialog(); + } catch (Exception e) { + Main.getUI().hideWaitDialog(); + Main.getUI().showMessageDialog("Failed writing: " + e.getMessage()); + } + } + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/ImportAction.java b/tools/preload2/src/com/android/preload/actions/ImportAction.java new file mode 100644 index 000000000000..5c1976580f94 --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ImportAction.java @@ -0,0 +1,68 @@ +/* + * 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.preload.actions; + +import com.android.preload.DumpData; +import com.android.preload.DumpDataIO; +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +import java.awt.event.ActionEvent; +import java.io.File; +import java.util.Collection; + +import javax.swing.AbstractAction; + +public class ImportAction extends AbstractAction implements Runnable { + private File[] lastOpenFiles; + private DumpTableModel dataTableModel; + + public ImportAction(DumpTableModel dataTableModel) { + super("Import data"); + this.dataTableModel = dataTableModel; + } + + @Override + public void actionPerformed(ActionEvent e) { + lastOpenFiles = Main.getUI().showOpenDialog(true); + if (lastOpenFiles != null) { + new Thread(this).start(); + } + } + + @Override + public void run() { + Main.getUI().showWaitDialog(); + + try { + for (File f : lastOpenFiles) { + try { + Collection<DumpData> data = DumpDataIO.deserialize(f); + + for (DumpData d : data) { + dataTableModel.addData(d); + } + } catch (Exception e) { + Main.getUI().showMessageDialog("Failed reading: " + e.getMessage()); + } + } + } finally { + Main.getUI().hideWaitDialog(); + } + + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/ReloadListAction.java b/tools/preload2/src/com/android/preload/actions/ReloadListAction.java new file mode 100644 index 000000000000..29f055700dfa --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ReloadListAction.java @@ -0,0 +1,68 @@ +/* + * 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.preload.actions; + +import com.android.ddmlib.Client; +import com.android.ddmlib.IDevice; +import com.android.preload.ClientUtils; + +import java.util.Arrays; +import java.util.Comparator; + +import javax.swing.DefaultListModel; + +public class ReloadListAction extends AbstractThreadedDeviceSpecificAction { + + private ClientUtils clientUtils; + private final DefaultListModel<Client> clientListModel; + + public ReloadListAction(ClientUtils utils, IDevice device, + DefaultListModel<Client> clientListModel) { + super("Reload", device); + this.clientUtils = utils; + this.clientListModel = clientListModel; + } + + @Override + public void run() { + Client[] clients = clientUtils.findAllClients(device); + if (clients != null) { + Arrays.sort(clients, new ClientComparator()); + } + clientListModel.removeAllElements(); + for (Client c : clients) { + clientListModel.addElement(c); + } + } + + private static class ClientComparator implements Comparator<Client> { + + @Override + public int compare(Client o1, Client o2) { + String s1 = o1.getClientData().getClientDescription(); + String s2 = o2.getClientData().getClientDescription(); + + if (s1 == null || s2 == null) { + // Not good, didn't get all data? + return (s1 == null) ? -1 : 1; + } + + return s1.compareTo(s2); + } + + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java new file mode 100644 index 000000000000..385e8577b1c8 --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/RunMonkeyAction.java @@ -0,0 +1,119 @@ +/* + * 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.preload.actions; + +import com.android.ddmlib.IDevice; +import com.android.preload.DeviceUtils; +import com.android.preload.DumpData; +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +import java.awt.event.ActionEvent; +import java.util.Date; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import javax.swing.AbstractAction; + +public class RunMonkeyAction extends AbstractAction implements DeviceSpecific { + + private final static String DEFAULT_MONKEY_PACKAGES = + "com.android.calendar,com.android.gallery3d"; + + private IDevice device; + private DumpTableModel dataTableModel; + + public RunMonkeyAction(IDevice device, DumpTableModel dataTableModel) { + super("Run monkey"); + this.device = device; + this.dataTableModel = dataTableModel; + } + + @Override + public void setDevice(IDevice device) { + this.device = device; + } + + @Override + public void actionPerformed(ActionEvent e) { + String packages = Main.getUI().showInputDialog("Please enter packages name to run with" + + " the monkey, or leave empty for default."); + if (packages == null) { + return; + } + if (packages.isEmpty()) { + packages = DEFAULT_MONKEY_PACKAGES; + } + new Thread(new RunMonkeyRunnable(packages)).start(); + } + + private class RunMonkeyRunnable implements Runnable { + + private String packages; + private final static int ITERATIONS = 1000; + + public RunMonkeyRunnable(String packages) { + this.packages = packages; + } + + @Override + public void run() { + Main.getUI().showWaitDialog(); + + try { + String pkgs[] = packages.split(","); + + for (String pkg : pkgs) { + Main.getUI().updateWaitDialog("Running monkey on " + pkg); + + try { + // Stop running app. + forceStop(pkg); + + // Little bit of breather here. + try { + Thread.sleep(1000); + } catch (Exception e) { + } + + DeviceUtils.doShell(device, "monkey -p " + pkg + " " + ITERATIONS, 1, + TimeUnit.MINUTES); + + Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg); + Map<String, String> data = Main.findAndGetClassData(device, pkg); + DumpData dumpData = new DumpData(pkg, data, new Date()); + dataTableModel.addData(dumpData); + } catch (Exception e) { + e.printStackTrace(); + } finally { + // Stop running app. + forceStop(pkg); + } + } + } finally { + Main.getUI().hideWaitDialog(); + } + } + + private void forceStop(String packageName) { + // Stop running app. + DeviceUtils.doShell(device, "force-stop " + packageName, 5, TimeUnit.SECONDS); + DeviceUtils.doShell(device, "kill " + packageName, 5, TimeUnit.SECONDS); + DeviceUtils.doShell(device, "kill `pid " + packageName + "`", 5, TimeUnit.SECONDS); + } + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java b/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java new file mode 100644 index 000000000000..d74b8a3f6cfb --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ScanAllPackagesAction.java @@ -0,0 +1,63 @@ +/* + * 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.preload.actions; + +import com.android.ddmlib.Client; +import com.android.ddmlib.IDevice; +import com.android.preload.ClientUtils; +import com.android.preload.DumpData; +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +import java.util.Date; +import java.util.Map; + +public class ScanAllPackagesAction extends AbstractThreadedDeviceSpecificAction { + + private ClientUtils clientUtils; + private DumpTableModel dataTableModel; + + public ScanAllPackagesAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) { + super("Scan all packages", device); + this.clientUtils = utils; + this.dataTableModel = dataTableModel; + } + + @Override + public void run() { + Main.getUI().showWaitDialog(); + + try { + Client[] clients = clientUtils.findAllClients(device); + for (Client c : clients) { + String pkg = c.getClientData().getClientDescription(); + Main.getUI().showWaitDialog(); + Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg); + + try { + Map<String, String> data = Main.getClassDataRetriever().getClassData(c); + DumpData dumpData = new DumpData(pkg, data, new Date()); + dataTableModel.addData(dumpData); + } catch (Exception e) { + e.printStackTrace(); + } + } + } finally { + Main.getUI().hideWaitDialog(); + } + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java b/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java new file mode 100644 index 000000000000..98492bd951bf --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ScanPackageAction.java @@ -0,0 +1,97 @@ +/* + * 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.preload.actions; + +import com.android.ddmlib.Client; +import com.android.ddmlib.IDevice; +import com.android.preload.ClientUtils; +import com.android.preload.DumpData; +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +import java.util.Date; +import java.util.Map; + +public class ScanPackageAction extends AbstractThreadedDeviceSpecificAction { + + private ClientUtils clientUtils; + private DumpTableModel dataTableModel; + + public ScanPackageAction(ClientUtils utils, IDevice device, DumpTableModel dataTableModel) { + super("Scan package", device); + this.clientUtils = utils; + this.dataTableModel = dataTableModel; + } + + @Override + public void run() { + Main.getUI().showWaitDialog(); + + try { + Client client = Main.getUI().getSelectedClient(); + if (client != null) { + work(client); + } else { + Client[] clients = clientUtils.findAllClients(device); + if (clients.length > 0) { + ClientWrapper[] clientWrappers = new ClientWrapper[clients.length]; + for (int i = 0; i < clientWrappers.length; i++) { + clientWrappers[i] = new ClientWrapper(clients[i]); + } + Main.getUI().hideWaitDialog(); + + ClientWrapper ret = Main.getUI().showChoiceDialog("Choose a package to scan", + "Choose package", + clientWrappers); + if (ret != null) { + work(ret.client); + } + } + } + } finally { + Main.getUI().hideWaitDialog(); + } + } + + private void work(Client c) { + String pkg = c.getClientData().getClientDescription(); + Main.getUI().showWaitDialog(); + Main.getUI().updateWaitDialog("Retrieving heap data for " + pkg); + + try { + Map<String, String> data = Main.findAndGetClassData(device, pkg); + DumpData dumpData = new DumpData(pkg, data, new Date()); + dataTableModel.addData(dumpData); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private static class ClientWrapper { + private Client client; + + public ClientWrapper(Client c) { + client = c; + } + + @Override + public String toString() { + return client.getClientData().getClientDescription() + " (pid " + + client.getClientData().getPid() + ")"; + } + } +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/actions/ShowDataAction.java b/tools/preload2/src/com/android/preload/actions/ShowDataAction.java new file mode 100644 index 000000000000..2bb175f60772 --- /dev/null +++ b/tools/preload2/src/com/android/preload/actions/ShowDataAction.java @@ -0,0 +1,94 @@ +/* + * 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.preload.actions; + +import com.android.preload.DumpData; +import com.android.preload.DumpTableModel; +import com.android.preload.Main; + +import java.awt.BorderLayout; +import java.awt.event.ActionEvent; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.swing.AbstractAction; +import javax.swing.JFrame; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; + +public class ShowDataAction extends AbstractAction { + private DumpTableModel dataTableModel; + + public ShowDataAction(DumpTableModel dataTableModel) { + super("Show data"); + this.dataTableModel = dataTableModel; + } + + @Override + public void actionPerformed(ActionEvent e) { + // TODO(agampe): Auto-generated method stub + int selRow = Main.getUI().getSelectedDataTableRow(); + if (selRow != -1) { + DumpData data = dataTableModel.getData().get(selRow); + Map<String, Set<String>> inv = data.invertData(); + + StringBuilder builder = new StringBuilder(); + + // First bootclasspath. + add(builder, "Boot classpath:", inv.get(null)); + + // Now everything else. + for (String k : inv.keySet()) { + if (k != null) { + builder.append("==================\n\n"); + add(builder, k, inv.get(k)); + } + } + + JFrame newFrame = new JFrame(data.getPackageName() + " " + data.getDate()); + newFrame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE); + newFrame.getContentPane().add(new JScrollPane(new JTextArea(builder.toString())), + BorderLayout.CENTER); + newFrame.setSize(800, 600); + newFrame.setLocationRelativeTo(null); + newFrame.setVisible(true); + } + } + + private void add(StringBuilder builder, String head, Set<String> set) { + builder.append(head); + builder.append('\n'); + addSet(builder, set); + builder.append('\n'); + } + + private void addSet(StringBuilder builder, Set<String> set) { + if (set == null) { + builder.append(" NONE\n"); + return; + } + List<String> sorted = new ArrayList<>(set); + Collections.sort(sorted); + for (String s : sorted) { + builder.append(s); + builder.append('\n'); + } + } +}
\ No newline at end of file diff --git a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchBaseTest.java b/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java index a9e1777f436a..f04360fc1942 100644 --- a/tests/RenderScriptTests/PerfTest/src/com/android/perftest/RsBenchBaseTest.java +++ b/tools/preload2/src/com/android/preload/classdataretrieval/ClassDataRetriever.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * 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. @@ -14,13 +14,16 @@ * limitations under the License. */ -package com.android.perftest; -import android.renderscript.*; -import android.content.res.Resources; +package com.android.preload.classdataretrieval; -interface RsBenchBaseTest { - boolean init(RenderScriptGL rs, Resources res); +import com.android.ddmlib.Client; - ScriptField_TestScripts_s.Item[] getTests(); - String[] getTestNames(); +import java.util.Map; + +/** + * Retrieve a class-to-classloader map for loaded classes from the client. + */ +public interface ClassDataRetriever { + + public Map<String, String> getClassData(Client client); } diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java new file mode 100644 index 000000000000..8d797ee00128 --- /dev/null +++ b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/GeneralHprofDumpHandler.java @@ -0,0 +1,70 @@ +/* + * 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.preload.classdataretrieval.hprof; + +import com.android.ddmlib.Client; +import com.android.ddmlib.ClientData.IHprofDumpHandler; + +import java.util.ArrayList; +import java.util.List; + +public class GeneralHprofDumpHandler implements IHprofDumpHandler { + + private List<IHprofDumpHandler> handlers = new ArrayList<>(); + + public void addHandler(IHprofDumpHandler h) { + synchronized (handlers) { + handlers.add(h); + } + } + + public void removeHandler(IHprofDumpHandler h) { + synchronized (handlers) { + handlers.remove(h); + } + } + + private List<IHprofDumpHandler> getIterationList() { + synchronized (handlers) { + return new ArrayList<>(handlers); + } + } + + @Override + public void onEndFailure(Client arg0, String arg1) { + List<IHprofDumpHandler> iterList = getIterationList(); + for (IHprofDumpHandler h : iterList) { + h.onEndFailure(arg0, arg1); + } + } + + @Override + public void onSuccess(String arg0, Client arg1) { + List<IHprofDumpHandler> iterList = getIterationList(); + for (IHprofDumpHandler h : iterList) { + h.onSuccess(arg0, arg1); + } + } + + @Override + public void onSuccess(byte[] arg0, Client arg1) { + List<IHprofDumpHandler> iterList = getIterationList(); + for (IHprofDumpHandler h : iterList) { + h.onSuccess(arg0, arg1); + } + } + }
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java new file mode 100644 index 000000000000..21b7a04e07dc --- /dev/null +++ b/tools/preload2/src/com/android/preload/classdataretrieval/hprof/Hprof.java @@ -0,0 +1,220 @@ +/* + * 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.preload.classdataretrieval.hprof; + +import com.android.ddmlib.Client; +import com.android.ddmlib.ClientData; +import com.android.ddmlib.ClientData.IHprofDumpHandler; +import com.android.preload.classdataretrieval.ClassDataRetriever; +import com.android.preload.ui.NullProgressMonitor; +import com.android.tools.perflib.captures.MemoryMappedFileBuffer; +import com.android.tools.perflib.heap.ClassObj; +import com.android.tools.perflib.heap.Queries; +import com.android.tools.perflib.heap.Snapshot; + +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public class Hprof implements ClassDataRetriever { + + private static GeneralHprofDumpHandler hprofHandler; + + public static void init() { + synchronized(Hprof.class) { + if (hprofHandler == null) { + ClientData.setHprofDumpHandler(hprofHandler = new GeneralHprofDumpHandler()); + } + } + } + + public static File doHprof(Client client, int timeout) { + GetHprof gh = new GetHprof(client, timeout); + return gh.get(); + } + + /** + * Return a map of class names to class-loader names derived from the hprof dump. + * + * @param hprofLocalFile + */ + public static Map<String, String> analyzeHprof(File hprofLocalFile) throws Exception { + Snapshot snapshot = Snapshot.createSnapshot(new MemoryMappedFileBuffer(hprofLocalFile)); + + Map<String, Set<ClassObj>> classes = Queries.classes(snapshot, null); + Map<String, String> retValue = new HashMap<String, String>(); + for (Map.Entry<String, Set<ClassObj>> e : classes.entrySet()) { + for (ClassObj c : e.getValue()) { + String cl = c.getClassLoader() == null ? null : c.getClassLoader().toString(); + String cName = c.getClassName(); + int aDepth = 0; + while (cName.endsWith("[]")) { + cName = cName.substring(0, cName.length()-2); + aDepth++; + } + String newName = transformPrimitiveClass(cName); + if (aDepth > 0) { + // Need to use kind-a descriptor syntax. If it was transformed, it is primitive. + if (newName.equals(cName)) { + newName = "L" + newName + ";"; + } + for (int i = 0; i < aDepth; i++) { + newName = "[" + newName; + } + } + retValue.put(newName, cl); + } + } + + // Free up memory. + snapshot.dispose(); + + return retValue; + } + + private static Map<String, String> primitiveMapping; + + static { + primitiveMapping = new HashMap<>(); + primitiveMapping.put("boolean", "Z"); + primitiveMapping.put("byte", "B"); + primitiveMapping.put("char", "C"); + primitiveMapping.put("double", "D"); + primitiveMapping.put("float", "F"); + primitiveMapping.put("int", "I"); + primitiveMapping.put("long", "J"); + primitiveMapping.put("short", "S"); + primitiveMapping.put("void", "V"); + } + + private static String transformPrimitiveClass(String name) { + String rep = primitiveMapping.get(name); + if (rep != null) { + return rep; + } + return name; + } + + private static class GetHprof implements IHprofDumpHandler { + + private File target; + private long timeout; + private Client client; + + public GetHprof(Client client, long timeout) { + this.client = client; + this.timeout = timeout; + } + + public File get() { + synchronized (this) { + hprofHandler.addHandler(this); + client.dumpHprof(); + if (target == null) { + try { + wait(timeout); + } catch (Exception e) { + System.out.println(e); + } + } + } + + hprofHandler.removeHandler(this); + return target; + } + + private void wakeUp() { + synchronized (this) { + notifyAll(); + } + } + + @Override + public void onEndFailure(Client arg0, String arg1) { + System.out.println("GetHprof.onEndFailure"); + if (client == arg0) { + wakeUp(); + } + } + + private static File createTargetFile() { + try { + return File.createTempFile("ddms", ".hprof"); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + @Override + public void onSuccess(String arg0, Client arg1) { + System.out.println("GetHprof.onSuccess"); + if (client == arg1) { + try { + target = createTargetFile(); + arg1.getDevice().getSyncService().pullFile(arg0, + target.getAbsoluteFile().toString(), new NullProgressMonitor()); + } catch (Exception e) { + e.printStackTrace(); + target = null; + } + wakeUp(); + } + } + + @Override + public void onSuccess(byte[] arg0, Client arg1) { + System.out.println("GetHprof.onSuccess"); + if (client == arg1) { + try { + target = createTargetFile(); + BufferedOutputStream out = + new BufferedOutputStream(new FileOutputStream(target)); + out.write(arg0); + out.close(); + } catch (Exception e) { + e.printStackTrace(); + target = null; + } + wakeUp(); + } + } + } + + private int timeout; + + public Hprof(int timeout) { + this.timeout = timeout; + } + + @Override + public Map<String, String> getClassData(Client client) { + File hprofLocalFile = Hprof.doHprof(client, timeout); + if (hprofLocalFile == null) { + throw new RuntimeException("Failed getting dump..."); + } + System.out.println("Dump file is " + hprofLocalFile); + + try { + return analyzeHprof(hprofLocalFile); + } catch (Exception e) { + throw new RuntimeException(e); + } + } +} diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java new file mode 100644 index 000000000000..dbd4c89b27cf --- /dev/null +++ b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/JDWPClassDataRetriever.java @@ -0,0 +1,221 @@ +/* + * 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.preload.classdataretrieval.jdwp; + +import com.android.ddmlib.Client; +import com.android.preload.classdataretrieval.ClassDataRetriever; + +import org.apache.harmony.jpda.tests.framework.jdwp.CommandPacket; +import org.apache.harmony.jpda.tests.framework.jdwp.JDWPCommands; +import org.apache.harmony.jpda.tests.framework.jdwp.JDWPConstants; +import org.apache.harmony.jpda.tests.framework.jdwp.ReplyPacket; +import org.apache.harmony.jpda.tests.jdwp.share.JDWPTestCase; +import org.apache.harmony.jpda.tests.jdwp.share.JDWPUnitDebuggeeWrapper; +import org.apache.harmony.jpda.tests.share.JPDALogWriter; +import org.apache.harmony.jpda.tests.share.JPDATestOptions; + +import java.util.HashMap; +import java.util.Map; + +public class JDWPClassDataRetriever extends JDWPTestCase implements ClassDataRetriever { + + private final Client client; + + public JDWPClassDataRetriever() { + this(null); + } + + public JDWPClassDataRetriever(Client client) { + this.client = client; + } + + + @Override + protected String getDebuggeeClassName() { + return "<unset>"; + } + + @Override + public Map<String, String> getClassData(Client client) { + return new JDWPClassDataRetriever(client).retrieve(); + } + + private Map<String, String> retrieve() { + if (client == null) { + throw new IllegalStateException(); + } + + settings = createTestOptions("localhost:" + String.valueOf(client.getDebuggerListenPort())); + settings.setDebuggeeSuspend("n"); + + logWriter = new JPDALogWriter(System.out, "", false); + + try { + internalSetUp(); + + return retrieveImpl(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } finally { + internalTearDown(); + } + } + + private Map<String, String> retrieveImpl() { + try { + // Suspend the app. + { + CommandPacket packet = new CommandPacket( + JDWPCommands.VirtualMachineCommandSet.CommandSetID, + JDWPCommands.VirtualMachineCommandSet.SuspendCommand); + ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet); + if (reply.getErrorCode() != JDWPConstants.Error.NONE) { + return null; + } + } + + // List all classes. + CommandPacket packet = new CommandPacket( + JDWPCommands.VirtualMachineCommandSet.CommandSetID, + JDWPCommands.VirtualMachineCommandSet.AllClassesCommand); + ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet); + + if (reply.getErrorCode() != JDWPConstants.Error.NONE) { + return null; + } + + int classCount = reply.getNextValueAsInt(); + System.out.println("Runtime reported " + classCount + " classes."); + + Map<Long, String> classes = new HashMap<Long, String>(); + Map<Long, String> arrayClasses = new HashMap<Long, String>(); + + for (int i = 0; i < classCount; i++) { + byte refTypeTag = reply.getNextValueAsByte(); + long typeID = reply.getNextValueAsReferenceTypeID(); + String signature = reply.getNextValueAsString(); + /* int status = */ reply.getNextValueAsInt(); + + switch (refTypeTag) { + case JDWPConstants.TypeTag.CLASS: + case JDWPConstants.TypeTag.INTERFACE: + classes.put(typeID, signature); + break; + + case JDWPConstants.TypeTag.ARRAY: + arrayClasses.put(typeID, signature); + break; + } + } + + Map<String, String> result = new HashMap<String, String>(); + + // Parse all classes. + for (Map.Entry<Long, String> entry : classes.entrySet()) { + long typeID = entry.getKey(); + String signature = entry.getValue(); + + if (!checkClass(typeID, signature, result)) { + System.err.println("Issue investigating " + signature); + } + } + + // For arrays, look at the leaf component type. + for (Map.Entry<Long, String> entry : arrayClasses.entrySet()) { + long typeID = entry.getKey(); + String signature = entry.getValue(); + + if (!checkArrayClass(typeID, signature, result)) { + System.err.println("Issue investigating " + signature); + } + } + + return result; + } finally { + // Resume the app. + { + CommandPacket packet = new CommandPacket( + JDWPCommands.VirtualMachineCommandSet.CommandSetID, + JDWPCommands.VirtualMachineCommandSet.ResumeCommand); + /* ReplyPacket reply = */ debuggeeWrapper.vmMirror.performCommand(packet); + } + } + } + + private boolean checkClass(long typeID, String signature, Map<String, String> result) { + CommandPacket packet = new CommandPacket( + JDWPCommands.ReferenceTypeCommandSet.CommandSetID, + JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand); + packet.setNextValueAsReferenceTypeID(typeID); + ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet); + if (reply.getErrorCode() != JDWPConstants.Error.NONE) { + return false; + } + + long classLoaderID = reply.getNextValueAsObjectID(); + + // TODO: Investigate the classloader to have a better string? + String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID); + + result.put(getClassName(signature), classLoaderString); + + return true; + } + + private boolean checkArrayClass(long typeID, String signature, Map<String, String> result) { + // Classloaders of array classes are the same as the component class'. + CommandPacket packet = new CommandPacket( + JDWPCommands.ReferenceTypeCommandSet.CommandSetID, + JDWPCommands.ReferenceTypeCommandSet.ClassLoaderCommand); + packet.setNextValueAsReferenceTypeID(typeID); + ReplyPacket reply = debuggeeWrapper.vmMirror.performCommand(packet); + if (reply.getErrorCode() != JDWPConstants.Error.NONE) { + return false; + } + + long classLoaderID = reply.getNextValueAsObjectID(); + + // TODO: Investigate the classloader to have a better string? + String classLoaderString = (classLoaderID == 0) ? null : String.valueOf(classLoaderID); + + // For array classes, we *need* the signature directly. + result.put(signature, classLoaderString); + + return true; + } + + private static String getClassName(String signature) { + String withoutLAndSemicolon = signature.substring(1, signature.length() - 1); + return withoutLAndSemicolon.replace('/', '.'); + } + + + private static JPDATestOptions createTestOptions(String address) { + JPDATestOptions options = new JPDATestOptions(); + options.setAttachConnectorKind(); + options.setTimeout(1000); + options.setWaitingTime(1000); + options.setTransportAddress(address); + return options; + } + + @Override + protected JDWPUnitDebuggeeWrapper createDebuggeeWrapper() { + return new PreloadDebugeeWrapper(settings, logWriter); + } +} diff --git a/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java new file mode 100644 index 000000000000..b9df6d0aeb93 --- /dev/null +++ b/tools/preload2/src/com/android/preload/classdataretrieval/jdwp/PreloadDebugeeWrapper.java @@ -0,0 +1,40 @@ +/* + * 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.preload.classdataretrieval.jdwp; + +import org.apache.harmony.jpda.tests.framework.LogWriter; +import org.apache.harmony.jpda.tests.jdwp.share.JDWPManualDebuggeeWrapper; +import org.apache.harmony.jpda.tests.share.JPDATestOptions; + +import java.io.IOException; + +public class PreloadDebugeeWrapper extends JDWPManualDebuggeeWrapper { + + public PreloadDebugeeWrapper(JPDATestOptions options, LogWriter writer) { + super(options, writer); + } + + @Override + protected Process launchProcess(String cmdLine) throws IOException { + return null; + } + + @Override + protected void WaitForProcessExit(Process process) { + } + +} diff --git a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java b/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java index 574bafc4173c..f45aad06ac6b 100644 --- a/tests/RenderScriptTests/SceneGraph/src/com/android/scenegraph/PointLight.java +++ b/tools/preload2/src/com/android/preload/ui/NullProgressMonitor.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * 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. @@ -14,30 +14,26 @@ * limitations under the License. */ -package com.android.scenegraph; +package com.android.preload.ui; -import java.lang.Math; -import java.util.ArrayList; +import com.android.ddmlib.SyncService.ISyncProgressMonitor; -import android.renderscript.Matrix4f; -import android.renderscript.ProgramFragment; -import android.renderscript.ProgramStore; -import android.renderscript.ProgramVertex; -import android.util.Log; +public class NullProgressMonitor implements ISyncProgressMonitor { -/** - * @hide - */ -public class PointLight extends LightBase { - public PointLight() { - } + @Override + public void advance(int arg0) {} - void initLocalData() { - mFieldData.type = RS_LIGHT_POINT; + @Override + public boolean isCanceled() { + return false; } -} - - + @Override + public void start(int arg0) {} + @Override + public void startSubTask(String arg0) {} + @Override + public void stop() {} +}
\ No newline at end of file diff --git a/tools/preload2/src/com/android/preload/ui/UI.java b/tools/preload2/src/com/android/preload/ui/UI.java new file mode 100644 index 000000000000..47174ddd0e07 --- /dev/null +++ b/tools/preload2/src/com/android/preload/ui/UI.java @@ -0,0 +1,267 @@ +/* + * 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.preload.ui; + +import com.android.ddmlib.Client; +import com.android.ddmlib.ClientData; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.io.File; +import java.util.List; + +import javax.swing.Action; +import javax.swing.DefaultListCellRenderer; +import javax.swing.JDialog; +import javax.swing.JFileChooser; +import javax.swing.JFrame; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JOptionPane; +import javax.swing.JProgressBar; +import javax.swing.JScrollPane; +import javax.swing.JTable; +import javax.swing.JToolBar; +import javax.swing.ListModel; +import javax.swing.SwingUtilities; +import javax.swing.table.TableModel; + +public class UI extends JFrame { + + private JList<Client> clientList; + private JTable dataTable; + + // Shared file chooser, means the directory is retained. + private JFileChooser jfc; + + public UI(ListModel<Client> clientListModel, + TableModel dataTableModel, + List<Action> actions) { + super("Preloaded-classes computation"); + + getContentPane().add(new JScrollPane(clientList = new JList<Client>(clientListModel)), + BorderLayout.WEST); + clientList.setCellRenderer(new ClientListCellRenderer()); + // clientList.addListSelectionListener(listener); + + dataTable = new JTable(dataTableModel); + getContentPane().add(new JScrollPane(dataTable), BorderLayout.CENTER); + + JToolBar toolbar = new JToolBar(JToolBar.HORIZONTAL); + for (Action a : actions) { + if (a == null) { + toolbar.addSeparator(); + } else { + toolbar.add(a); + } + } + getContentPane().add(toolbar, BorderLayout.PAGE_START); + + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setBounds(100, 100, 800, 600); + } + + public Client getSelectedClient() { + return clientList.getSelectedValue(); + } + + public int getSelectedDataTableRow() { + return dataTable.getSelectedRow(); + } + + private JDialog currentWaitDialog = null; + + public void showWaitDialog() { + if (currentWaitDialog == null) { + currentWaitDialog = new JDialog(this, "Please wait...", true); + currentWaitDialog.getContentPane().add(new JLabel("Please be patient."), + BorderLayout.CENTER); + JProgressBar progress = new JProgressBar(JProgressBar.HORIZONTAL); + progress.setIndeterminate(true); + currentWaitDialog.getContentPane().add(progress, BorderLayout.SOUTH); + currentWaitDialog.setSize(200, 100); + currentWaitDialog.setLocationRelativeTo(null); + showWaitDialogLater(); + } + } + + private void showWaitDialogLater() { + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + if (currentWaitDialog != null) { + currentWaitDialog.setVisible(true); // This is blocking. + } + } + }); + } + + public void updateWaitDialog(String s) { + if (currentWaitDialog != null) { + ((JLabel) currentWaitDialog.getContentPane().getComponent(0)).setText(s); + Dimension prefSize = currentWaitDialog.getPreferredSize(); + Dimension curSize = currentWaitDialog.getSize(); + if (prefSize.width > curSize.width || prefSize.height > curSize.height) { + currentWaitDialog.setSize(Math.max(prefSize.width, curSize.width), + Math.max(prefSize.height, curSize.height)); + currentWaitDialog.invalidate(); + } + } + } + + public void hideWaitDialog() { + if (currentWaitDialog != null) { + currentWaitDialog.setVisible(false); + currentWaitDialog = null; + } + } + + public void showMessageDialog(String s) { + // Hide the wait dialog... + if (currentWaitDialog != null) { + currentWaitDialog.setVisible(false); + } + + try { + JOptionPane.showMessageDialog(this, s); + } finally { + // And reshow it afterwards... + if (currentWaitDialog != null) { + showWaitDialogLater(); + } + } + } + + public boolean showConfirmDialog(String title, String message) { + // Hide the wait dialog... + if (currentWaitDialog != null) { + currentWaitDialog.setVisible(false); + } + + try { + return JOptionPane.showConfirmDialog(this, title, message, JOptionPane.YES_NO_OPTION) + == JOptionPane.YES_OPTION; + } finally { + // And reshow it afterwards... + if (currentWaitDialog != null) { + showWaitDialogLater(); + } + } + } + + public String showInputDialog(String message) { + // Hide the wait dialog... + if (currentWaitDialog != null) { + currentWaitDialog.setVisible(false); + } + + try { + return JOptionPane.showInputDialog(message); + } finally { + // And reshow it afterwards... + if (currentWaitDialog != null) { + showWaitDialogLater(); + } + } + } + + @SuppressWarnings("unchecked") + public <T> T showChoiceDialog(String title, String message, T[] choices) { + // Hide the wait dialog... + if (currentWaitDialog != null) { + currentWaitDialog.setVisible(false); + } + + try{ + return (T)JOptionPane.showInputDialog(this, + title, + message, + JOptionPane.QUESTION_MESSAGE, + null, + choices, + choices[0]); + } finally { + // And reshow it afterwards... + if (currentWaitDialog != null) { + showWaitDialogLater(); + } + } + } + + public File showSaveDialog() { + // Hide the wait dialog... + if (currentWaitDialog != null) { + currentWaitDialog.setVisible(false); + } + + try{ + if (jfc == null) { + jfc = new JFileChooser(); + } + + int ret = jfc.showSaveDialog(this); + if (ret == JFileChooser.APPROVE_OPTION) { + return jfc.getSelectedFile(); + } else { + return null; + } + } finally { + // And reshow it afterwards... + if (currentWaitDialog != null) { + showWaitDialogLater(); + } + } + } + + public File[] showOpenDialog(boolean multi) { + // Hide the wait dialog... + if (currentWaitDialog != null) { + currentWaitDialog.setVisible(false); + } + + try{ + if (jfc == null) { + jfc = new JFileChooser(); + } + + jfc.setMultiSelectionEnabled(multi); + int ret = jfc.showOpenDialog(this); + if (ret == JFileChooser.APPROVE_OPTION) { + return jfc.getSelectedFiles(); + } else { + return null; + } + } finally { + // And reshow it afterwards... + if (currentWaitDialog != null) { + showWaitDialogLater(); + } + } + } + + private class ClientListCellRenderer extends DefaultListCellRenderer { + + @Override + public Component getListCellRendererComponent(JList<?> list, Object value, int index, + boolean isSelected, boolean cellHasFocus) { + ClientData cd = ((Client) value).getClientData(); + String s = cd.getClientDescription() + " (pid " + cd.getPid() + ")"; + return super.getListCellRendererComponent(list, s, index, isSelected, cellHasFocus); + } + } +} |