diff options
684 files changed, 21912 insertions, 8503 deletions
@@ -737,7 +737,8 @@ sample_groups := -samplegroup Background \ -samplegroup Sensors \ -samplegroup Testing \ -samplegroup UI \ - -samplegroup Views + -samplegroup Views \ + -samplegroup Wearable ## SDK version identifiers used in the published docs # major[.minor] version for current SDK. (full releases only) diff --git a/api/current.txt b/api/current.txt index fe0c209..aa8057d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -113,6 +113,8 @@ package android { field public static final java.lang.String RECEIVE_SMS = "android.permission.RECEIVE_SMS"; field public static final java.lang.String RECEIVE_WAP_PUSH = "android.permission.RECEIVE_WAP_PUSH"; field public static final java.lang.String RECORD_AUDIO = "android.permission.RECORD_AUDIO"; + field public static final java.lang.String REGISTER_CONNECTION_MANAGER = "android.permission.REGISTER_CONNECTION_MANAGER"; + field public static final java.lang.String REGISTER_PROVIDER_OR_SUBSCRIPTION = "android.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION"; field public static final java.lang.String REORDER_TASKS = "android.permission.REORDER_TASKS"; field public static final deprecated java.lang.String RESTART_PACKAGES = "android.permission.RESTART_PACKAGES"; field public static final java.lang.String SEND_RESPOND_VIA_MESSAGE = "android.permission.SEND_RESPOND_VIA_MESSAGE"; @@ -1002,6 +1004,7 @@ package android { field public static final int requiredForAllUsers = 16843728; // 0x10103d0 field public static final int requiresFadingEdge = 16843685; // 0x10103a5 field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364 + field public static final int resizeClip = 16844033; // 0x1010501 field public static final int resizeMode = 16843619; // 0x1010363 field public static final int resizeable = 16843405; // 0x101028d field public static final int resource = 16842789; // 0x1010025 @@ -2612,7 +2615,7 @@ package android.accessibilityservice { field public static final int CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS = 8; // 0x8 field public static final int CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION = 2; // 0x2 field public static final int CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT = 1; // 0x1 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.accessibilityservice.AccessibilityServiceInfo> CREATOR; field public static final int DEFAULT = 1; // 0x1 field public static final int FEEDBACK_ALL_MASK = -1; // 0xffffffff field public static final int FEEDBACK_AUDIBLE = 4; // 0x4 @@ -2658,7 +2661,7 @@ package android.accounts { ctor public Account(android.os.Parcel); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.accounts.Account> CREATOR; field public final java.lang.String name; field public final java.lang.String type; } @@ -2675,7 +2678,7 @@ package android.accounts { method public void onRequestContinued(); method public void onResult(android.os.Bundle); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.accounts.AccountAuthenticatorResponse> CREATOR; } public class AccountManager { @@ -2767,7 +2770,7 @@ package android.accounts { method public int describeContents(); method public static android.accounts.AuthenticatorDescription newKey(java.lang.String); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.accounts.AuthenticatorDescription> CREATOR; field public final int accountPreferencesId; field public final boolean customTokens; field public final int iconId; @@ -3052,9 +3055,10 @@ package android.animation { method public android.graphics.Rect evaluate(float, android.graphics.Rect, android.graphics.Rect); } - public class StateListAnimator { + public class StateListAnimator implements java.lang.Cloneable { ctor public StateListAnimator(); method public void addState(int[], android.animation.Animator); + method public android.animation.StateListAnimator clone(); method public void jumpToCurrentState(); } @@ -3525,7 +3529,7 @@ package android.app { method public int describeContents(); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.ActivityManager.MemoryInfo> CREATOR; field public long availMem; field public boolean lowMemory; field public long threshold; @@ -3538,7 +3542,7 @@ package android.app { method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); field public static final int CRASHED = 1; // 0x1 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.ActivityManager.ProcessErrorStateInfo> CREATOR; field public static final int NOT_RESPONDING = 2; // 0x2 field public static final int NO_ERROR = 0; // 0x0 field public int condition; @@ -3557,7 +3561,7 @@ package android.app { method public int describeContents(); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RecentTaskInfo> CREATOR; field public int affiliatedTaskId; field public android.content.Intent baseIntent; field public java.lang.CharSequence description; @@ -3573,7 +3577,7 @@ package android.app { method public int describeContents(); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningAppProcessInfo> CREATOR; field public static final int IMPORTANCE_BACKGROUND = 400; // 0x190 field public static final int IMPORTANCE_EMPTY = 500; // 0x1f4 field public static final int IMPORTANCE_FOREGROUND = 100; // 0x64 @@ -3601,7 +3605,7 @@ package android.app { method public int describeContents(); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningServiceInfo> CREATOR; field public static final int FLAG_FOREGROUND = 2; // 0x2 field public static final int FLAG_PERSISTENT_PROCESS = 8; // 0x8 field public static final int FLAG_STARTED = 1; // 0x1 @@ -3627,7 +3631,7 @@ package android.app { method public int describeContents(); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.ActivityManager.RunningTaskInfo> CREATOR; field public android.content.ComponentName baseActivity; field public java.lang.CharSequence description; field public int id; @@ -3649,7 +3653,7 @@ package android.app { method public int getPrimaryColor(); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.ActivityManager.TaskDescription> CREATOR; } public class ActivityOptions { @@ -3692,7 +3696,7 @@ package android.app { method public android.app.PendingIntent getShowIntent(); method public long getTriggerTime(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.AlarmManager.AlarmClockInfo> CREATOR; } public class AlertDialog extends android.app.Dialog implements android.content.DialogInterface { @@ -3829,7 +3833,7 @@ package android.app { method public static android.content.ComponentName getErrorReportReceiver(android.content.Context, java.lang.String, int); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.ApplicationErrorReport> CREATOR; field public static final int TYPE_ANR = 2; // 0x2 field public static final int TYPE_BATTERY = 3; // 0x3 field public static final int TYPE_CRASH = 1; // 0x1 @@ -4210,7 +4214,7 @@ package android.app { public static class Fragment.SavedState implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.ClassLoaderCreator CREATOR; + field public static final android.os.Parcelable.ClassLoaderCreator<android.app.Fragment.SavedState> CREATOR; } public deprecated class FragmentBreadCrumbs extends android.view.ViewGroup implements android.app.FragmentManager.OnBackStackChangedListener { @@ -4402,6 +4406,7 @@ package android.app { method public android.content.Intent createConfirmDeviceCredentialIntent(java.lang.CharSequence, java.lang.CharSequence); method public deprecated void exitKeyguardSecurely(android.app.KeyguardManager.OnKeyguardExitResult); method public boolean inKeyguardRestrictedInputMode(); + method public boolean isKeyguardInTrustedState(); method public boolean isKeyguardLocked(); method public boolean isKeyguardSecure(); method public deprecated android.app.KeyguardManager.KeyguardLock newKeyguardLock(java.lang.String); @@ -4557,7 +4562,7 @@ package android.app { field public static final java.lang.String CATEGORY_SYSTEM = "sys"; field public static final java.lang.String CATEGORY_TRANSPORT = "transport"; field public static final int COLOR_DEFAULT = 0; // 0x0 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.Notification> CREATOR; field public static final int DEFAULT_ALL = -1; // 0xffffffff field public static final int DEFAULT_LIGHTS = 4; // 0x4 field public static final int DEFAULT_SOUND = 1; // 0x1 @@ -4642,7 +4647,7 @@ package android.app { method public android.os.Bundle getExtras(); method public android.app.RemoteInput[] getRemoteInputs(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.Notification.Action> CREATOR; field public android.app.PendingIntent actionIntent; field public int icon; field public java.lang.CharSequence title; @@ -4845,7 +4850,7 @@ package android.app { method public void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, java.lang.String) throws android.app.PendingIntent.CanceledException; method public static void writePendingIntentOrNullToParcel(android.app.PendingIntent, android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.PendingIntent> CREATOR; field public static final int FLAG_CANCEL_CURRENT = 268435456; // 0x10000000 field public static final int FLAG_NO_CREATE = 536870912; // 0x20000000 field public static final int FLAG_ONE_SHOT = 1073741824; // 0x40000000 @@ -4908,7 +4913,7 @@ package android.app { method public java.lang.String getResultKey(); method public static android.os.Bundle getResultsFromIntent(android.content.Intent); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR; field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData"; field public static final java.lang.String RESULTS_CLIP_LABEL = "android.remoteinput.results"; } @@ -5023,7 +5028,7 @@ package android.app { method public boolean shouldRewriteQueryFromData(); method public boolean shouldRewriteQueryFromText(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.SearchableInfo> CREATOR; } public abstract class Service extends android.content.ContextWrapper implements android.content.ComponentCallbacks2 { @@ -5169,7 +5174,7 @@ package android.app { method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadThumbnail(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.WallpaperInfo> CREATOR; } public class WallpaperManager { @@ -5224,7 +5229,7 @@ package android.app.admin { method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public boolean usesPolicy(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.admin.DeviceAdminInfo> CREATOR; field public static final int USES_ENCRYPTED_STORAGE = 7; // 0x7 field public static final int USES_POLICY_DISABLE_CAMERA = 8; // 0x8 field public static final int USES_POLICY_DISABLE_KEYGUARD_FEATURES = 9; // 0x9 @@ -5516,7 +5521,7 @@ package android.app.job { method public void writeToParcel(android.os.Parcel, int); field public static final int BACKOFF_POLICY_EXPONENTIAL = 1; // 0x1 field public static final int BACKOFF_POLICY_LINEAR = 0; // 0x0 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR; field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L field public static final int NETWORK_TYPE_ANY = 1; // 0x1 @@ -5544,7 +5549,7 @@ package android.app.job { method public int getJobId(); method public boolean isOverrideDeadlineExpired(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.job.JobParameters> CREATOR; } public abstract class JobScheduler { @@ -5580,7 +5585,7 @@ package android.app.usage { method public long getLastTimeStamp(); method public long getTotalTimeActive(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.usage.ConfigurationStats> CREATOR; } public final class UsageEvents implements android.os.Parcelable { @@ -5588,7 +5593,7 @@ package android.app.usage { method public boolean getNextEvent(android.app.usage.UsageEvents.Event); method public boolean hasNextEvent(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.usage.UsageEvents> CREATOR; } public static final class UsageEvents.Event { @@ -5614,7 +5619,7 @@ package android.app.usage { method public java.lang.String getPackageName(); method public long getTotalTimeInForeground(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.app.usage.UsageStats> CREATOR; } public final class UsageStatsManager { @@ -5731,7 +5736,7 @@ package android.appwidget { method public final java.lang.String loadLabel(android.content.pm.PackageManager); method public final android.graphics.drawable.Drawable loadPreviewImage(android.content.Context, int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.appwidget.AppWidgetProviderInfo> CREATOR; field public static final int RESIZE_BOTH = 3; // 0x3 field public static final int RESIZE_HORIZONTAL = 1; // 0x1 field public static final int RESIZE_NONE = 0; // 0x0 @@ -6072,7 +6077,7 @@ package android.bluetooth { method public int getMajorDeviceClass(); method public boolean hasService(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothClass> CREATOR; } public static class BluetoothClass.Device { @@ -6185,7 +6190,7 @@ package android.bluetooth { field public static final int BOND_BONDED = 12; // 0xc field public static final int BOND_BONDING = 11; // 0xb field public static final int BOND_NONE = 10; // 0xa - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothDevice> CREATOR; field public static final int DEVICE_TYPE_CLASSIC = 1; // 0x1 field public static final int DEVICE_TYPE_DUAL = 3; // 0x3 field public static final int DEVICE_TYPE_LE = 2; // 0x2 @@ -6303,7 +6308,7 @@ package android.bluetooth { field public static final int WRITE_TYPE_DEFAULT = 2; // 0x2 field public static final int WRITE_TYPE_NO_RESPONSE = 1; // 0x1 field public static final int WRITE_TYPE_SIGNED = 4; // 0x4 - field protected java.util.List mDescriptors; + field protected java.util.List<android.bluetooth.BluetoothGattDescriptor> mDescriptors; } public class BluetoothGattDescriptor { @@ -6366,8 +6371,8 @@ package android.bluetooth { method public java.util.UUID getUuid(); field public static final int SERVICE_TYPE_PRIMARY = 0; // 0x0 field public static final int SERVICE_TYPE_SECONDARY = 1; // 0x1 - field protected java.util.List mCharacteristics; - field protected java.util.List mIncludedServices; + field protected java.util.List<android.bluetooth.BluetoothGattCharacteristic> mCharacteristics; + field protected java.util.List<android.bluetooth.BluetoothGattService> mIncludedServices; } public final class BluetoothHeadset implements android.bluetooth.BluetoothProfile { @@ -6425,7 +6430,7 @@ package android.bluetooth { method public java.lang.String getName(); method public int getRole(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.bluetooth.BluetoothHealthAppConfiguration> CREATOR; } public abstract class BluetoothHealthCallback { @@ -6502,7 +6507,7 @@ package android.bluetooth.le { method public java.util.Map<android.os.ParcelUuid, byte[]> getServiceData(); method public java.util.List<android.os.ParcelUuid> getServiceUuids(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseData> CREATOR; } public static final class AdvertiseData.Builder { @@ -6529,7 +6534,7 @@ package android.bluetooth.le { field public static final int ADVERTISE_TX_POWER_LOW = 1; // 0x1 field public static final int ADVERTISE_TX_POWER_MEDIUM = 2; // 0x2 field public static final int ADVERTISE_TX_POWER_ULTRA_LOW = 0; // 0x0 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.bluetooth.le.AdvertiseSettings> CREATOR; } public static final class AdvertiseSettings.Builder { @@ -6579,7 +6584,7 @@ package android.bluetooth.le { method public android.os.ParcelUuid getServiceUuidMask(); method public boolean matches(android.bluetooth.le.ScanResult); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanFilter> CREATOR; } public static final class ScanFilter.Builder { @@ -6615,7 +6620,7 @@ package android.bluetooth.le { method public android.bluetooth.le.ScanRecord getScanRecord(); method public long getTimestampNanos(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR; } public final class ScanSettings implements android.os.Parcelable { @@ -6626,7 +6631,7 @@ package android.bluetooth.le { method public int getScanResultType(); method public void writeToParcel(android.os.Parcel, int); field public static final int CALLBACK_TYPE_ALL_MATCHES = 1; // 0x1 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanSettings> CREATOR; field public static final int SCAN_MODE_BALANCED = 1; // 0x1 field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2 field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0 @@ -6751,7 +6756,7 @@ package android.content { method public static android.content.ClipData newRawUri(java.lang.CharSequence, android.net.Uri); method public static android.content.ClipData newUri(android.content.ContentResolver, java.lang.CharSequence, android.net.Uri); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.ClipData> CREATOR; } public static class ClipData.Item { @@ -6781,7 +6786,7 @@ package android.content { method public int getMimeTypeCount(); method public boolean hasMimeType(java.lang.String); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.ClipDescription> CREATOR; field public static final java.lang.String MIMETYPE_TEXT_HTML = "text/html"; field public static final java.lang.String MIMETYPE_TEXT_INTENT = "text/vnd.android.intent"; field public static final java.lang.String MIMETYPE_TEXT_PLAIN = "text/plain"; @@ -6838,7 +6843,7 @@ package android.content { method public static android.content.ComponentName unflattenFromString(java.lang.String); method public void writeToParcel(android.os.Parcel, int); method public static void writeToParcel(android.content.ComponentName, android.os.Parcel); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.ComponentName> CREATOR; } public abstract class ContentProvider implements android.content.ComponentCallbacks2 { @@ -6922,7 +6927,7 @@ package android.content { method public java.lang.String[] resolveSelectionArgsBackReferences(android.content.ContentProviderResult[], int); method public android.content.ContentValues resolveValueBackReferences(android.content.ContentProviderResult[], int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.ContentProviderOperation> CREATOR; } public static class ContentProviderOperation.Builder { @@ -6943,7 +6948,7 @@ package android.content { ctor public ContentProviderResult(android.os.Parcel); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.ContentProviderResult> CREATOR; field public final java.lang.Integer count; field public final android.net.Uri uri; } @@ -7078,7 +7083,7 @@ package android.content { method public int size(); method public java.util.Set<java.util.Map.Entry<java.lang.String, java.lang.Object>> valueSet(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.ContentValues> CREATOR; field public static final java.lang.String TAG = "ContentValues"; } @@ -7432,6 +7437,7 @@ package android.content { method public java.lang.Object clone(); method public android.content.Intent cloneFilter(); method public static android.content.Intent createChooser(android.content.Intent, java.lang.CharSequence); + method public static android.content.Intent createChooser(android.content.Intent, java.lang.CharSequence, android.content.IntentSender); method public int describeContents(); method public int fillIn(android.content.Intent, int); method public boolean filterEquals(android.content.Intent); @@ -7693,7 +7699,7 @@ package android.content { field public static final java.lang.String CATEGORY_TAB = "android.intent.category.TAB"; field public static final java.lang.String CATEGORY_TEST = "android.intent.category.TEST"; field public static final java.lang.String CATEGORY_UNIT_TEST = "android.intent.category.UNIT_TEST"; - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.Intent> CREATOR; field public static final java.lang.String EXTRA_ALARM_COUNT = "android.intent.extra.ALARM_COUNT"; field public static final java.lang.String EXTRA_ALLOW_MULTIPLE = "android.intent.extra.ALLOW_MULTIPLE"; field public static final deprecated java.lang.String EXTRA_ALLOW_REPLACE = "android.intent.extra.ALLOW_REPLACE"; @@ -7707,6 +7713,8 @@ package android.content { field public static final java.lang.String EXTRA_CHANGED_COMPONENT_NAME_LIST = "android.intent.extra.changed_component_name_list"; field public static final java.lang.String EXTRA_CHANGED_PACKAGE_LIST = "android.intent.extra.changed_package_list"; field public static final java.lang.String EXTRA_CHANGED_UID_LIST = "android.intent.extra.changed_uid_list"; + field public static final java.lang.String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT"; + field public static final java.lang.String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER"; field public static final java.lang.String EXTRA_DATA_REMOVED = "android.intent.extra.DATA_REMOVED"; field public static final java.lang.String EXTRA_DOCK_STATE = "android.intent.extra.DOCK_STATE"; field public static final int EXTRA_DOCK_STATE_CAR = 2; // 0x2 @@ -7799,7 +7807,7 @@ package android.content { method public int describeContents(); method public static android.content.Intent.ShortcutIconResource fromContext(android.content.Context, int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.Intent.ShortcutIconResource> CREATOR; field public java.lang.String packageName; field public java.lang.String resourceName; } @@ -7858,7 +7866,7 @@ package android.content { method public final java.util.Iterator<java.lang.String> typesIterator(); method public final void writeToParcel(android.os.Parcel, int); method public void writeToXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException; - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.IntentFilter> CREATOR; field public static final int MATCH_ADJUSTMENT_MASK = 65535; // 0xffff field public static final int MATCH_ADJUSTMENT_NORMAL = 32768; // 0x8000 field public static final int MATCH_CATEGORY_EMPTY = 1048576; // 0x100000 @@ -7900,7 +7908,7 @@ package android.content { method public void sendIntent(android.content.Context, int, android.content.Intent, android.content.IntentSender.OnFinished, android.os.Handler, java.lang.String) throws android.content.IntentSender.SendIntentException; method public static void writeIntentSenderOrNullToParcel(android.content.IntentSender, android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.IntentSender> CREATOR; } public static abstract interface IntentSender.OnFinished { @@ -7977,7 +7985,7 @@ package android.content { ctor public PeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.PeriodicSync> CREATOR; field public final android.accounts.Account account; field public final java.lang.String authority; field public final android.os.Bundle extras; @@ -8018,7 +8026,7 @@ package android.content { method public void setTitle(java.lang.String); method public void setType(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.RestrictionEntry> CREATOR; field public static final int TYPE_BOOLEAN = 1; // 0x1 field public static final int TYPE_CHOICE = 2; // 0x2 field public static final int TYPE_INTEGER = 5; // 0x5 @@ -8126,7 +8134,7 @@ package android.content { method public static android.content.SyncAdapterType newKey(java.lang.String, java.lang.String); method public boolean supportsUploading(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.SyncAdapterType> CREATOR; field public final java.lang.String accountType; field public final java.lang.String authority; field public final boolean isKey; @@ -8148,7 +8156,7 @@ package android.content { public class SyncRequest implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.SyncRequest> CREATOR; } public static class SyncRequest.Builder { @@ -8177,7 +8185,7 @@ package android.content { method public java.lang.String toDebugString(); method public void writeToParcel(android.os.Parcel, int); field public static final android.content.SyncResult ALREADY_IN_PROGRESS; - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.SyncResult> CREATOR; field public boolean databaseError; field public long delayUntil; field public boolean fullSyncRequested; @@ -8195,7 +8203,7 @@ package android.content { method public void clear(); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.SyncStats> CREATOR; field public long numAuthExceptions; field public long numConflictDetectedExceptions; field public long numDeletes; @@ -8225,7 +8233,7 @@ package android.content { method public boolean isReadPermission(); method public boolean isWritePermission(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.UriPermission> CREATOR; field public static final long INVALID_TIME = -9223372036854775808L; // 0x8000000000000000L } @@ -8254,7 +8262,7 @@ package android.content.pm { field public static final int CONFIG_SMALLEST_SCREEN_SIZE = 2048; // 0x800 field public static final int CONFIG_TOUCHSCREEN = 8; // 0x8 field public static final int CONFIG_UI_MODE = 512; // 0x200 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.ActivityInfo> CREATOR; field public static final int DOCUMENT_LAUNCH_ALWAYS = 2; // 0x2 field public static final int DOCUMENT_LAUNCH_INTO_EXISTING = 1; // 0x1 field public static final int DOCUMENT_LAUNCH_NEVER = 3; // 0x3 @@ -8320,7 +8328,7 @@ package android.content.pm { method public int describeContents(); method public void dump(android.util.Printer, java.lang.String); method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.ApplicationInfo> CREATOR; field public static final int FLAG_ALLOW_BACKUP = 32768; // 0x8000 field public static final int FLAG_ALLOW_CLEAR_USER_DATA = 64; // 0x40 field public static final int FLAG_ALLOW_TASK_REPARENTING = 32; // 0x20 @@ -8400,7 +8408,7 @@ package android.content.pm { method public int describeContents(); method public java.lang.String getGlEsVersion(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.ConfigurationInfo> CREATOR; field public static final int GL_ES_VERSION_UNDEFINED = 0; // 0x0 field public static final int INPUT_FEATURE_FIVE_WAY_NAV = 2; // 0x2 field public static final int INPUT_FEATURE_HARD_KEYBOARD = 1; // 0x1 @@ -8416,7 +8424,7 @@ package android.content.pm { ctor public FeatureGroupInfo(android.content.pm.FeatureGroupInfo); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.FeatureGroupInfo> CREATOR; field public android.content.pm.FeatureInfo[] features; } @@ -8426,7 +8434,7 @@ package android.content.pm { method public int describeContents(); method public java.lang.String getGlEsVersion(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.FeatureInfo> CREATOR; field public static final int FLAG_REQUIRED = 1; // 0x1 field public static final int GL_ES_VERSION_UNDEFINED = 0; // 0x0 field public int flags; @@ -8438,7 +8446,7 @@ package android.content.pm { ctor public InstrumentationInfo(); ctor public InstrumentationInfo(android.content.pm.InstrumentationInfo); method public int describeContents(); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.InstrumentationInfo> CREATOR; field public java.lang.String dataDir; field public boolean functionalTest; field public boolean handleProfiling; @@ -8460,7 +8468,7 @@ package android.content.pm { method public java.lang.String getSourcePackage(); method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.LabeledIntent> CREATOR; } public class LauncherActivityInfo { @@ -8499,7 +8507,7 @@ package android.content.pm { ctor public PackageInfo(); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.PackageInfo> CREATOR; field public static final int INSTALL_LOCATION_AUTO = 0; // 0x0 field public static final int INSTALL_LOCATION_INTERNAL_ONLY = 1; // 0x1 field public static final int INSTALL_LOCATION_PREFER_EXTERNAL = 2; // 0x2 @@ -8592,7 +8600,7 @@ package android.content.pm { method public int getSessionId(); method public boolean isActive(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionInfo> CREATOR; } public static class PackageInstaller.SessionParams implements android.os.Parcelable { @@ -8606,7 +8614,7 @@ package android.content.pm { method public void setReferrerUri(android.net.Uri); method public void setSize(long); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.PackageInstaller.SessionParams> CREATOR; field public static final int MODE_FULL_INSTALL = 1; // 0x1 field public static final int MODE_INHERIT_EXISTING = 2; // 0x2 } @@ -8621,6 +8629,7 @@ package android.content.pm { method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager); + method public android.graphics.drawable.Drawable loadUnbadgedIcon(android.content.pm.PackageManager); method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String); method public void writeToParcel(android.os.Parcel, int); field public int banner; @@ -8839,7 +8848,7 @@ package android.content.pm { ctor public PackageStats(android.content.pm.PackageStats); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.PackageStats> CREATOR; field public long cacheSize; field public long codeSize; field public long dataSize; @@ -8856,7 +8865,7 @@ package android.content.pm { ctor public PathPermission(android.os.Parcel); method public java.lang.String getReadPermission(); method public java.lang.String getWritePermission(); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.PathPermission> CREATOR; } public class PermissionGroupInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable { @@ -8864,7 +8873,7 @@ package android.content.pm { ctor public PermissionGroupInfo(android.content.pm.PermissionGroupInfo); method public int describeContents(); method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.PermissionGroupInfo> CREATOR; field public static final int FLAG_PERSONAL_INFO = 1; // 0x1 field public int descriptionRes; field public int flags; @@ -8877,7 +8886,7 @@ package android.content.pm { ctor public PermissionInfo(android.content.pm.PermissionInfo); method public int describeContents(); method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR; field public static final int FLAG_COSTS_MONEY = 1; // 0x1 field public static final int PROTECTION_DANGEROUS = 1; // 0x1 field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40 @@ -8900,7 +8909,7 @@ package android.content.pm { ctor public ProviderInfo(android.content.pm.ProviderInfo); method public int describeContents(); method public void dump(android.util.Printer, java.lang.String); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.ProviderInfo> CREATOR; field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 field public java.lang.String authority; field public int flags; @@ -8923,7 +8932,7 @@ package android.content.pm { method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.ResolveInfo> CREATOR; field public android.content.pm.ActivityInfo activityInfo; field public android.content.IntentFilter filter; field public int icon; @@ -8949,7 +8958,7 @@ package android.content.pm { ctor public ServiceInfo(android.content.pm.ServiceInfo); method public int describeContents(); method public void dump(android.util.Printer, java.lang.String); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.ServiceInfo> CREATOR; field public static final int FLAG_ISOLATED_PROCESS = 2; // 0x2 field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000 field public static final int FLAG_STOP_WITH_TASK = 1; // 0x1 @@ -8966,7 +8975,7 @@ package android.content.pm { method public char[] toChars(char[], int[]); method public java.lang.String toCharsString(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.pm.Signature> CREATOR; } } @@ -8987,7 +8996,7 @@ package android.content.res { method public android.os.ParcelFileDescriptor getParcelFileDescriptor(); method public long getStartOffset(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.res.AssetFileDescriptor> CREATOR; field public static final long UNKNOWN_LENGTH = -1L; // 0xffffffffffffffffL } @@ -9039,7 +9048,7 @@ package android.content.res { method public static android.content.res.ColorStateList valueOf(int); method public android.content.res.ColorStateList withAlpha(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.res.ColorStateList> CREATOR; } public final class Configuration implements java.lang.Comparable android.os.Parcelable { @@ -9059,7 +9068,7 @@ package android.content.res { method public void setToDefaults(); method public int updateFrom(android.content.res.Configuration); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.res.Configuration> CREATOR; field public static final int DENSITY_DPI_UNDEFINED = 0; // 0x0 field public static final int HARDKEYBOARDHIDDEN_NO = 1; // 0x1 field public static final int HARDKEYBOARDHIDDEN_UNDEFINED = 0; // 0x0 @@ -9141,7 +9150,7 @@ package android.content.res { public class ObbInfo implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.content.res.ObbInfo> CREATOR; field public static final int OBB_OVERLAY = 1; // 0x1 field public java.lang.String filename; field public int flags; @@ -9317,7 +9326,7 @@ package android.database { field protected deprecated java.lang.Long mCurrentRowID; field protected int mPos; field protected deprecated int mRowIdColumnIndex; - field protected deprecated java.util.HashMap mUpdatedRows; + field protected deprecated java.util.HashMap<java.lang.Long, java.util.Map<java.lang.String, java.lang.Object>> mUpdatedRows; } protected static class AbstractCursor.SelfContentObserver extends android.database.ContentObserver { @@ -9481,7 +9490,7 @@ package android.database { method public boolean setNumColumns(int); method public void setStartPosition(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.database.CursorWindow> CREATOR; } public class CursorWrapper implements android.database.Cursor { @@ -9670,7 +9679,7 @@ package android.database { method public void registerObserver(T); method public void unregisterAll(); method public void unregisterObserver(T); - field protected final java.util.ArrayList mObservers; + field protected final java.util.ArrayList<T> mObservers; } public class SQLException extends java.lang.RuntimeException { @@ -10199,7 +10208,7 @@ package android.gesture { method public android.graphics.Path toPath(int, int, int, int); method public android.graphics.Path toPath(android.graphics.Path, int, int, int, int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.gesture.Gesture> CREATOR; } public final class GestureLibraries { @@ -10431,7 +10440,7 @@ package android.graphics { method public final void setPremultiplied(boolean); method public void setWidth(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.graphics.Bitmap> CREATOR; field public static final int DENSITY_NONE = 0; // 0x0 } @@ -11235,7 +11244,7 @@ package android.graphics { method public void readFromParcel(android.os.Parcel); method public void set(int, int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.graphics.Point> CREATOR; field public int x; field public int y; } @@ -11254,7 +11263,7 @@ package android.graphics { method public final void set(float, float); method public final void set(android.graphics.PointF); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.graphics.PointF> CREATOR; field public float x; field public float y; } @@ -11338,7 +11347,7 @@ package android.graphics { method public void union(int, int); method public final int width(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.graphics.Rect> CREATOR; field public int bottom; field public int left; field public int right; @@ -11380,7 +11389,7 @@ package android.graphics { method public void union(float, float); method public final float width(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.graphics.RectF> CREATOR; field public float bottom; field public float left; field public float right; @@ -11420,7 +11429,7 @@ package android.graphics { method public void translate(int, int, android.graphics.Region); method public final boolean union(android.graphics.Rect); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.graphics.Region> CREATOR; } public static final class Region.Op extends java.lang.Enum { @@ -12550,70 +12559,70 @@ package android.hardware.camera2 { method public T get(android.hardware.camera2.CameraCharacteristics.Key<T>); method public java.util.List<android.hardware.camera2.CaptureRequest.Key<?>> getAvailableCaptureRequestKeys(); method public java.util.List<android.hardware.camera2.CaptureResult.Key<?>> getAvailableCaptureResultKeys(); - field public static final android.hardware.camera2.CameraCharacteristics.Key COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_ANTIBANDING_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_COMPENSATION_RANGE; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AE_COMPENSATION_STEP; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AF_AVAILABLE_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_EFFECTS; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_SCENE_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_AWB_AVAILABLE_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS_AE; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS_AF; - field public static final android.hardware.camera2.CameraCharacteristics.Key CONTROL_MAX_REGIONS_AWB; - field public static final android.hardware.camera2.CameraCharacteristics.Key EDGE_AVAILABLE_EDGE_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key FLASH_INFO_AVAILABLE; - field public static final android.hardware.camera2.CameraCharacteristics.Key HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key INFO_SUPPORTED_HARDWARE_LEVEL; - field public static final android.hardware.camera2.CameraCharacteristics.Key JPEG_AVAILABLE_THUMBNAIL_SIZES; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_FACING; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_APERTURES; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_FILTER_DENSITIES; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_FOCAL_LENGTHS; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_FOCUS_DISTANCE_CALIBRATION; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_HYPERFOCAL_DISTANCE; - field public static final android.hardware.camera2.CameraCharacteristics.Key LENS_INFO_MINIMUM_FOCUS_DISTANCE; - field public static final android.hardware.camera2.CameraCharacteristics.Key NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_AVAILABLE_CAPABILITIES; - field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_PROC; - field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_PROC_STALLING; - field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_MAX_NUM_OUTPUT_RAW; - field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PARTIAL_RESULT_COUNT; - field public static final android.hardware.camera2.CameraCharacteristics.Key REQUEST_PIPELINE_MAX_DEPTH; - field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; - field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_CROPPING_TYPE; - field public static final android.hardware.camera2.CameraCharacteristics.Key SCALER_STREAM_CONFIGURATION_MAP; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_AVAILABLE_TEST_PATTERN_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_BLACK_LEVEL_PATTERN; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_CALIBRATION_TRANSFORM1; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_CALIBRATION_TRANSFORM2; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_COLOR_TRANSFORM1; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_COLOR_TRANSFORM2; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_FORWARD_MATRIX1; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_FORWARD_MATRIX2; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_ACTIVE_ARRAY_SIZE; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_COLOR_FILTER_ARRANGEMENT; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_EXPOSURE_TIME_RANGE; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_MAX_FRAME_DURATION; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PHYSICAL_SIZE; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_PIXEL_ARRAY_SIZE; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_SENSITIVITY_RANGE; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_TIMESTAMP_SOURCE; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_INFO_WHITE_LEVEL; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_MAX_ANALOG_SENSITIVITY; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_ORIENTATION; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_REFERENCE_ILLUMINANT1; - field public static final android.hardware.camera2.CameraCharacteristics.Key SENSOR_REFERENCE_ILLUMINANT2; - field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key STATISTICS_INFO_MAX_FACE_COUNT; - field public static final android.hardware.camera2.CameraCharacteristics.Key SYNC_MAX_LATENCY; - field public static final android.hardware.camera2.CameraCharacteristics.Key TONEMAP_AVAILABLE_TONE_MAP_MODES; - field public static final android.hardware.camera2.CameraCharacteristics.Key TONEMAP_MAX_CURVE_POINTS; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_ANTIBANDING_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AE_AVAILABLE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>[]> CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_COMPENSATION_RANGE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Rational> CONTROL_AE_COMPENSATION_STEP; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AF_AVAILABLE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_EFFECTS; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_SCENE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> CONTROL_AWB_AVAILABLE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AF; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> CONTROL_MAX_REGIONS_AWB; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> EDGE_AVAILABLE_EDGE_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Boolean> FLASH_INFO_AVAILABLE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> INFO_SUPPORTED_HARDWARE_LEVEL; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size[]> JPEG_AVAILABLE_THUMBNAIL_SIZES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LENS_FACING; + field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_INFO_AVAILABLE_APERTURES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_INFO_AVAILABLE_FILTER_DENSITIES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<float[]> LENS_INFO_AVAILABLE_FOCAL_LENGTHS; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> LENS_INFO_FOCUS_DISTANCE_CALIBRATION; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_HYPERFOCAL_DISTANCE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> LENS_INFO_MINIMUM_FOCUS_DISTANCE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> REQUEST_AVAILABLE_CAPABILITIES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_PROC_STALLING; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_MAX_NUM_OUTPUT_RAW; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> REQUEST_PARTIAL_RESULT_COUNT; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> REQUEST_PIPELINE_MAX_DEPTH; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Float> SCALER_AVAILABLE_MAX_DIGITAL_ZOOM; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SCALER_CROPPING_TYPE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.StreamConfigurationMap> SCALER_STREAM_CONFIGURATION_MAP; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> SENSOR_AVAILABLE_TEST_PATTERN_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.BlackLevelPattern> SENSOR_BLACK_LEVEL_PATTERN; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_CALIBRATION_TRANSFORM1; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_CALIBRATION_TRANSFORM2; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_COLOR_TRANSFORM1; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_COLOR_TRANSFORM2; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_FORWARD_MATRIX1; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.hardware.camera2.params.ColorSpaceTransform> SENSOR_FORWARD_MATRIX2; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.graphics.Rect> SENSOR_INFO_ACTIVE_ARRAY_SIZE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_COLOR_FILTER_ARRANGEMENT; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Long>> SENSOR_INFO_EXPOSURE_TIME_RANGE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Long> SENSOR_INFO_MAX_FRAME_DURATION; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.SizeF> SENSOR_INFO_PHYSICAL_SIZE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Size> SENSOR_INFO_PIXEL_ARRAY_SIZE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<android.util.Range<java.lang.Integer>> SENSOR_INFO_SENSITIVITY_RANGE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_TIMESTAMP_SOURCE; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_INFO_WHITE_LEVEL; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_MAX_ANALOG_SENSITIVITY; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_ORIENTATION; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SENSOR_REFERENCE_ILLUMINANT1; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Byte> SENSOR_REFERENCE_ILLUMINANT2; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<boolean[]> STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> STATISTICS_INFO_MAX_FACE_COUNT; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> SYNC_MAX_LATENCY; + field public static final android.hardware.camera2.CameraCharacteristics.Key<int[]> TONEMAP_AVAILABLE_TONE_MAP_MODES; + field public static final android.hardware.camera2.CameraCharacteristics.Key<java.lang.Integer> TONEMAP_MAX_CURVE_POINTS; } public static final class CameraCharacteristics.Key { @@ -12856,56 +12865,56 @@ package android.hardware.camera2 { method public T get(android.hardware.camera2.CaptureRequest.Key<T>); method public java.lang.Object getTag(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.hardware.camera2.CaptureRequest.Key BLACK_LEVEL_LOCK; - field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_ABERRATION_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_GAINS; - field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key COLOR_CORRECTION_TRANSFORM; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_ANTIBANDING_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_EXPOSURE_COMPENSATION; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_LOCK; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_PRECAPTURE_TRIGGER; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_REGIONS; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AE_TARGET_FPS_RANGE; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_REGIONS; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AF_TRIGGER; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_LOCK; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_AWB_REGIONS; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_CAPTURE_INTENT; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_EFFECT_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_SCENE_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key CONTROL_VIDEO_STABILIZATION_MODE; - field public static final android.os.Parcelable.Creator CREATOR; - field public static final android.hardware.camera2.CaptureRequest.Key EDGE_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key FLASH_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key HOT_PIXEL_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key JPEG_GPS_LOCATION; - field public static final android.hardware.camera2.CaptureRequest.Key JPEG_ORIENTATION; - field public static final android.hardware.camera2.CaptureRequest.Key JPEG_QUALITY; - field public static final android.hardware.camera2.CaptureRequest.Key JPEG_THUMBNAIL_QUALITY; - field public static final android.hardware.camera2.CaptureRequest.Key JPEG_THUMBNAIL_SIZE; - field public static final android.hardware.camera2.CaptureRequest.Key LENS_APERTURE; - field public static final android.hardware.camera2.CaptureRequest.Key LENS_FILTER_DENSITY; - field public static final android.hardware.camera2.CaptureRequest.Key LENS_FOCAL_LENGTH; - field public static final android.hardware.camera2.CaptureRequest.Key LENS_FOCUS_DISTANCE; - field public static final android.hardware.camera2.CaptureRequest.Key LENS_OPTICAL_STABILIZATION_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key NOISE_REDUCTION_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key SCALER_CROP_REGION; - field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_EXPOSURE_TIME; - field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_FRAME_DURATION; - field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_SENSITIVITY; - field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_TEST_PATTERN_DATA; - field public static final android.hardware.camera2.CaptureRequest.Key SENSOR_TEST_PATTERN_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key SHADING_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_FACE_DETECT_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_HOT_PIXEL_MAP_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key STATISTICS_LENS_SHADING_MAP_MODE; - field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_CURVE; - field public static final android.hardware.camera2.CaptureRequest.Key TONEMAP_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> BLACK_LEVEL_LOCK; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> COLOR_CORRECTION_ABERRATION_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.RggbChannelVector> COLOR_CORRECTION_GAINS; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> COLOR_CORRECTION_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.ColorSpaceTransform> COLOR_CORRECTION_TRANSFORM; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_AE_ANTIBANDING_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_AE_EXPOSURE_COMPENSATION; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> CONTROL_AE_LOCK; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_AE_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_AE_PRECAPTURE_TRIGGER; + field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS; + field public static final android.hardware.camera2.CaptureRequest.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_TARGET_FPS_RANGE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_AF_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_AF_TRIGGER; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> CONTROL_AWB_LOCK; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_AWB_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_EFFECT_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_SCENE_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE; + field public static final android.os.Parcelable.Creator<android.hardware.camera2.CaptureRequest> CREATOR; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> EDGE_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> FLASH_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> HOT_PIXEL_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<android.location.Location> JPEG_GPS_LOCATION; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> JPEG_ORIENTATION; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Byte> JPEG_QUALITY; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Byte> JPEG_THUMBNAIL_QUALITY; + field public static final android.hardware.camera2.CaptureRequest.Key<android.util.Size> JPEG_THUMBNAIL_SIZE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> LENS_APERTURE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> LENS_FILTER_DENSITY; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> LENS_FOCAL_LENGTH; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Float> LENS_FOCUS_DISTANCE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> NOISE_REDUCTION_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<android.graphics.Rect> SCALER_CROP_REGION; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_EXPOSURE_TIME; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Long> SENSOR_FRAME_DURATION; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> SENSOR_SENSITIVITY; + field public static final android.hardware.camera2.CaptureRequest.Key<int[]> SENSOR_TEST_PATTERN_DATA; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> SENSOR_TEST_PATTERN_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> SHADING_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_FACE_DETECT_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE; + field public static final android.hardware.camera2.CaptureRequest.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE; + field public static final android.hardware.camera2.CaptureRequest.Key<java.lang.Integer> TONEMAP_MODE; } public static final class CaptureRequest.Builder { @@ -12928,71 +12937,71 @@ package android.hardware.camera2 { method public long getFrameNumber(); method public android.hardware.camera2.CaptureRequest getRequest(); method public int getSequenceId(); - field public static final android.hardware.camera2.CaptureResult.Key BLACK_LEVEL_LOCK; - field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_ABERRATION_MODE; - field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_GAINS; - field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_MODE; - field public static final android.hardware.camera2.CaptureResult.Key COLOR_CORRECTION_TRANSFORM; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_ANTIBANDING_MODE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_EXPOSURE_COMPENSATION; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_LOCK; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_MODE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_PRECAPTURE_TRIGGER; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_REGIONS; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_STATE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AE_TARGET_FPS_RANGE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_MODE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_REGIONS; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_STATE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AF_TRIGGER; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_LOCK; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_MODE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_REGIONS; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_AWB_STATE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_CAPTURE_INTENT; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_EFFECT_MODE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_MODE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_SCENE_MODE; - field public static final android.hardware.camera2.CaptureResult.Key CONTROL_VIDEO_STABILIZATION_MODE; - field public static final android.hardware.camera2.CaptureResult.Key EDGE_MODE; - field public static final android.hardware.camera2.CaptureResult.Key FLASH_MODE; - field public static final android.hardware.camera2.CaptureResult.Key FLASH_STATE; - field public static final android.hardware.camera2.CaptureResult.Key HOT_PIXEL_MODE; - field public static final android.hardware.camera2.CaptureResult.Key JPEG_GPS_LOCATION; - field public static final android.hardware.camera2.CaptureResult.Key JPEG_ORIENTATION; - field public static final android.hardware.camera2.CaptureResult.Key JPEG_QUALITY; - field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_QUALITY; - field public static final android.hardware.camera2.CaptureResult.Key JPEG_THUMBNAIL_SIZE; - field public static final android.hardware.camera2.CaptureResult.Key LENS_APERTURE; - field public static final android.hardware.camera2.CaptureResult.Key LENS_FILTER_DENSITY; - field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCAL_LENGTH; - field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCUS_DISTANCE; - field public static final android.hardware.camera2.CaptureResult.Key LENS_FOCUS_RANGE; - field public static final android.hardware.camera2.CaptureResult.Key LENS_OPTICAL_STABILIZATION_MODE; - field public static final android.hardware.camera2.CaptureResult.Key LENS_STATE; - field public static final android.hardware.camera2.CaptureResult.Key NOISE_REDUCTION_MODE; - field public static final android.hardware.camera2.CaptureResult.Key REQUEST_PIPELINE_DEPTH; - field public static final android.hardware.camera2.CaptureResult.Key SCALER_CROP_REGION; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_EXPOSURE_TIME; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_FRAME_DURATION; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_GREEN_SPLIT; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NEUTRAL_COLOR_POINT; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_NOISE_PROFILE; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_ROLLING_SHUTTER_SKEW; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_SENSITIVITY; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_DATA; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TEST_PATTERN_MODE; - field public static final android.hardware.camera2.CaptureResult.Key SENSOR_TIMESTAMP; - field public static final android.hardware.camera2.CaptureResult.Key SHADING_MODE; - field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_FACES; - field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_FACE_DETECT_MODE; - field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_HOT_PIXEL_MAP; - field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_HOT_PIXEL_MAP_MODE; - field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_CORRECTION_MAP; - field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_LENS_SHADING_MAP_MODE; - field public static final android.hardware.camera2.CaptureResult.Key STATISTICS_SCENE_FLICKER; - field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_CURVE; - field public static final android.hardware.camera2.CaptureResult.Key TONEMAP_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> BLACK_LEVEL_LOCK; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> COLOR_CORRECTION_ABERRATION_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.RggbChannelVector> COLOR_CORRECTION_GAINS; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> COLOR_CORRECTION_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.ColorSpaceTransform> COLOR_CORRECTION_TRANSFORM; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AE_ANTIBANDING_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AE_EXPOSURE_COMPENSATION; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> CONTROL_AE_LOCK; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AE_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AE_PRECAPTURE_TRIGGER; + field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AE_REGIONS; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AE_STATE; + field public static final android.hardware.camera2.CaptureResult.Key<android.util.Range<java.lang.Integer>> CONTROL_AE_TARGET_FPS_RANGE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AF_REGIONS; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_STATE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AF_TRIGGER; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> CONTROL_AWB_LOCK; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AWB_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.MeteringRectangle[]> CONTROL_AWB_REGIONS; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_AWB_STATE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_CAPTURE_INTENT; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_EFFECT_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_SCENE_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> CONTROL_VIDEO_STABILIZATION_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> EDGE_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> FLASH_STATE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> HOT_PIXEL_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<android.location.Location> JPEG_GPS_LOCATION; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> JPEG_ORIENTATION; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> JPEG_QUALITY; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> JPEG_THUMBNAIL_QUALITY; + field public static final android.hardware.camera2.CaptureResult.Key<android.util.Size> JPEG_THUMBNAIL_SIZE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_APERTURE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FILTER_DENSITY; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCAL_LENGTH; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> LENS_FOCUS_DISTANCE; + field public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Float, java.lang.Float>> LENS_FOCUS_RANGE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_OPTICAL_STABILIZATION_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> LENS_STATE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> NOISE_REDUCTION_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Byte> REQUEST_PIPELINE_DEPTH; + field public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Rect> SCALER_CROP_REGION; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_EXPOSURE_TIME; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_FRAME_DURATION; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Float> SENSOR_GREEN_SPLIT; + field public static final android.hardware.camera2.CaptureResult.Key<android.util.Rational[]> SENSOR_NEUTRAL_COLOR_POINT; + field public static final android.hardware.camera2.CaptureResult.Key<android.util.Pair<java.lang.Double, java.lang.Double>[]> SENSOR_NOISE_PROFILE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_ROLLING_SHUTTER_SKEW; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> SENSOR_SENSITIVITY; + field public static final android.hardware.camera2.CaptureResult.Key<int[]> SENSOR_TEST_PATTERN_DATA; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> SENSOR_TEST_PATTERN_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Long> SENSOR_TIMESTAMP; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> SHADING_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.Face[]> STATISTICS_FACES; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_FACE_DETECT_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<android.graphics.Point[]> STATISTICS_HOT_PIXEL_MAP; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Boolean> STATISTICS_HOT_PIXEL_MAP_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.LensShadingMap> STATISTICS_LENS_SHADING_CORRECTION_MAP; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_LENS_SHADING_MAP_MODE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> STATISTICS_SCENE_FLICKER; + field public static final android.hardware.camera2.CaptureResult.Key<android.hardware.camera2.params.TonemapCurve> TONEMAP_CURVE; + field public static final android.hardware.camera2.CaptureResult.Key<java.lang.Integer> TONEMAP_MODE; } public static final class CaptureResult.Key { @@ -13195,7 +13204,7 @@ package android.hardware.usb { method public java.lang.String getUri(); method public java.lang.String getVersion(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbAccessory> CREATOR; } public class UsbConfiguration implements android.os.Parcelable { @@ -13208,7 +13217,7 @@ package android.hardware.usb { method public boolean isRemoteWakeup(); method public boolean isSelfPowered(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbConfiguration> CREATOR; } public final class UsbConstants { @@ -13267,7 +13276,7 @@ package android.hardware.usb { method public java.lang.String getSerialNumber(); method public int getVendorId(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbDevice> CREATOR; } public class UsbDeviceConnection { @@ -13296,7 +13305,7 @@ package android.hardware.usb { method public int getMaxPacketSize(); method public int getType(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbEndpoint> CREATOR; } public class UsbInterface implements android.os.Parcelable { @@ -13310,7 +13319,7 @@ package android.hardware.usb { method public int getInterfaceSubclass(); method public java.lang.String getName(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.hardware.usb.UsbInterface> CREATOR; } public class UsbManager { @@ -13667,7 +13676,7 @@ package android.location { method public void setThoroughfare(java.lang.String); method public void setUrl(java.lang.String); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.location.Address> CREATOR; } public class Criteria implements android.os.Parcelable { @@ -13700,7 +13709,7 @@ package android.location { field public static final int ACCURACY_HIGH = 3; // 0x3 field public static final int ACCURACY_LOW = 1; // 0x1 field public static final int ACCURACY_MEDIUM = 2; // 0x2 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.location.Criteria> CREATOR; field public static final int NO_REQUIREMENT = 0; // 0x0 field public static final int POWER_HIGH = 3; // 0x3 field public static final int POWER_LOW = 1; // 0x1 @@ -13786,7 +13795,7 @@ package android.location { method public void setSpeed(float); method public void setTime(long); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.location.Location> CREATOR; field public static final int FORMAT_DEGREES = 0; // 0x0 field public static final int FORMAT_MINUTES = 1; // 0x1 field public static final int FORMAT_SECONDS = 2; // 0x2 @@ -13896,7 +13905,7 @@ package android.media { field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4 field public static final int CONTENT_TYPE_SPEECH = 1; // 0x1 field public static final int CONTENT_TYPE_UNKNOWN = 0; // 0x0 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR; field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1 field public static final int FLAG_HW_AV_SYNC = 16; // 0x10 field public static final int USAGE_ALARM = 4; // 0x4 @@ -14767,7 +14776,7 @@ package android.media { method public java.lang.CharSequence getSubtitle(); method public java.lang.CharSequence getTitle(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.MediaDescription> CREATOR; } public static class MediaDescription.Builder { @@ -14967,7 +14976,7 @@ package android.media { method public java.util.Set<java.lang.String> keySet(); method public int size(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.MediaMetadata> CREATOR; field public static final java.lang.String METADATA_KEY_ALBUM = "android.media.metadata.ALBUM"; field public static final java.lang.String METADATA_KEY_ALBUM_ART = "android.media.metadata.ALBUM_ART"; field public static final java.lang.String METADATA_KEY_ALBUM_ARTIST = "android.media.metadata.ALBUM_ARTIST"; @@ -15468,7 +15477,7 @@ package android.media { method public static android.media.Rating newThumbRating(boolean); method public static android.media.Rating newUnratedRating(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.Rating> CREATOR; field public static final int RATING_3_STARS = 3; // 0x3 field public static final int RATING_4_STARS = 4; // 0x4 field public static final int RATING_5_STARS = 5; // 0x5 @@ -16118,7 +16127,7 @@ package android.media.browse { method public boolean isBrowsable(); method public boolean isPlayable(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.browse.MediaBrowser.MediaItem> CREATOR; field public static final int FLAG_BROWSABLE = 1; // 0x1 field public static final int FLAG_PLAYABLE = 2; // 0x2 } @@ -16320,14 +16329,14 @@ package android.media.session { method public android.media.MediaDescription getDescription(); method public long getQueueId(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.session.MediaSession.QueueItem> CREATOR; field public static final int UNKNOWN_ID = -1; // 0xffffffff } public static final class MediaSession.Token implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.session.MediaSession.Token> CREATOR; } public final class MediaSessionManager { @@ -16366,7 +16375,7 @@ package android.media.session { field public static final long ACTION_SKIP_TO_PREVIOUS = 16L; // 0x10L field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L field public static final long ACTION_STOP = 1L; // 0x1L - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR; field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL field public static final int STATE_BUFFERING = 6; // 0x6 field public static final int STATE_CONNECTING = 8; // 0x8 @@ -16403,7 +16412,7 @@ package android.media.session { method public int getIcon(); method public java.lang.CharSequence getName(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState.CustomAction> CREATOR; } public static final class PlaybackState.CustomAction.Builder { @@ -16542,15 +16551,21 @@ package android.media.tv { method public static java.lang.String[] decode(java.lang.String); method public static java.lang.String encode(java.lang.String...); field public static final java.lang.String ANIMAL_WILDLIFE = "ANIMAL_WILDLIFE"; + field public static final java.lang.String ARTS = "ARTS"; field public static final java.lang.String COMEDY = "COMEDY"; field public static final java.lang.String DRAMA = "DRAMA"; field public static final java.lang.String EDUCATION = "EDUCATION"; + field public static final java.lang.String ENTERTAINMENT = "ENTERTAINMENT"; field public static final java.lang.String FAMILY_KIDS = "FAMILY_KIDS"; field public static final java.lang.String GAMING = "GAMING"; + field public static final java.lang.String LIFE_STYLE = "LIFE_STYLE"; field public static final java.lang.String MOVIES = "MOVIES"; + field public static final java.lang.String MUSIC = "MUSIC"; field public static final java.lang.String NEWS = "NEWS"; + field public static final java.lang.String PREMIER = "PREMIER"; field public static final java.lang.String SHOPPING = "SHOPPING"; field public static final java.lang.String SPORTS = "SPORTS"; + field public static final java.lang.String TECH_SCIENCE = "TECH_SCIENCE"; field public static final java.lang.String TRAVEL = "TRAVEL"; } @@ -16566,7 +16581,7 @@ package android.media.tv { method public android.graphics.drawable.Drawable loadIcon(android.content.Context); method public java.lang.CharSequence loadLabel(android.content.Context); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.tv.TvInputInfo> CREATOR; field public static final java.lang.String EXTRA_INPUT_ID = "android.media.tv.extra.INPUT_ID"; field public static final int TYPE_COMPONENT = 1004; // 0x3ec field public static final int TYPE_COMPOSITE = 1001; // 0x3e9 @@ -16664,7 +16679,7 @@ package android.media.tv { method public final int getVideoHeight(); method public final int getVideoWidth(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.media.tv.TvTrackInfo> CREATOR; field public static final int TYPE_AUDIO = 0; // 0x0 field public static final int TYPE_SUBTITLE = 2; // 0x2 field public static final int TYPE_VIDEO = 1; // 0x1 @@ -16936,7 +16951,7 @@ package android.net { method public int getPrefixLength(); method public byte[] getRawAddress(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR; } public class LinkAddress implements android.os.Parcelable { @@ -16946,7 +16961,7 @@ package android.net { method public int getPrefixLength(); method public int getScope(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.LinkAddress> CREATOR; } public final class LinkProperties implements android.os.Parcelable { @@ -16958,7 +16973,7 @@ package android.net { method public java.util.List<android.net.LinkAddress> getLinkAddresses(); method public java.util.List<android.net.RouteInfo> getRoutes(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.LinkProperties> CREATOR; } public class LocalServerSocket { @@ -17030,6 +17045,7 @@ package android.net { } public class Network implements android.os.Parcelable { + method public void bindSocket(java.net.DatagramSocket) throws java.io.IOException; method public void bindSocket(java.net.Socket) throws java.io.IOException; method public int describeContents(); method public java.net.InetAddress[] getAllByName(java.lang.String) throws java.net.UnknownHostException; @@ -17037,7 +17053,7 @@ package android.net { method public javax.net.SocketFactory getSocketFactory(); method public java.net.URLConnection openConnection(java.net.URL) throws java.io.IOException; method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.Network> CREATOR; } public final class NetworkCapabilities implements android.os.Parcelable { @@ -17048,7 +17064,7 @@ package android.net { method public boolean hasCapability(int); method public boolean hasTransport(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR; field public static final int NET_CAPABILITY_CBS = 5; // 0x5 field public static final int NET_CAPABILITY_DUN = 2; // 0x2 field public static final int NET_CAPABILITY_EIMS = 10; // 0xa @@ -17122,7 +17138,7 @@ package android.net { public class NetworkRequest implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.NetworkRequest> CREATOR; } public static class NetworkRequest.Builder { @@ -17149,7 +17165,7 @@ package android.net { field public static final java.lang.String PROXY_CHANGE_ACTION = "android.intent.action.PROXY_CHANGE"; } - public class ProxyInfo implements android.os.Parcelable { + public deprecated class ProxyInfo implements android.os.Parcelable { method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int); method public static android.net.ProxyInfo buildDirectProxy(java.lang.String, int, java.util.List<java.lang.String>); method public static android.net.ProxyInfo buildPacProxy(android.net.Uri); @@ -17159,7 +17175,7 @@ package android.net { method public android.net.Uri getPacFileUrl(); method public int getPort(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.ProxyInfo> CREATOR; } public abstract class PskKeyManager { @@ -17183,7 +17199,7 @@ package android.net { method public boolean isDefaultRoute(); method public boolean matches(java.net.InetAddress); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.RouteInfo> CREATOR; } public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory { @@ -17196,7 +17212,7 @@ package android.net { method public static javax.net.SocketFactory getDefault(int); method public static javax.net.ssl.SSLSocketFactory getDefault(int, android.net.SSLSessionCache); method public java.lang.String[] getDefaultCipherSuites(); - method public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache); + method public static deprecated org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory(int, android.net.SSLSessionCache); method public static javax.net.ssl.SSLSocketFactory getInsecure(int, android.net.SSLSessionCache); method public byte[] getNpnSelectedProtocol(java.net.Socket); method public java.lang.String[] getSupportedCipherSuites(); @@ -17282,7 +17298,7 @@ package android.net { method public abstract java.lang.String toString(); method public static android.net.Uri withAppendedPath(android.net.Uri, java.lang.String); method public static void writeToParcel(android.os.Parcel, android.net.Uri); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.Uri> CREATOR; field public static final android.net.Uri EMPTY; } @@ -17414,7 +17430,7 @@ package android.net { package android.net.http { - public final class AndroidHttpClient implements org.apache.http.client.HttpClient { + public final deprecated class AndroidHttpClient implements org.apache.http.client.HttpClient { method public void close(); method public void disableCurlLogging(); method public void enableCurlLogging(java.lang.String, int); @@ -17432,8 +17448,8 @@ package android.net.http { method public org.apache.http.params.HttpParams getParams(); method public static java.io.InputStream getUngzippedContent(org.apache.http.HttpEntity) throws java.io.IOException; method public static void modifyRequestToAcceptGzipResponse(org.apache.http.HttpRequest); - method public static android.net.http.AndroidHttpClient newInstance(java.lang.String, android.content.Context); - method public static android.net.http.AndroidHttpClient newInstance(java.lang.String); + method public static deprecated android.net.http.AndroidHttpClient newInstance(java.lang.String, android.content.Context); + method public static deprecated android.net.http.AndroidHttpClient newInstance(java.lang.String); method public static long parseDate(java.lang.String); field public static long DEFAULT_SYNC_MIN_GZIP_BYTES; } @@ -17556,7 +17572,7 @@ package android.net.nsd { method public void setServiceName(java.lang.String); method public void setServiceType(java.lang.String); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.nsd.NsdServiceInfo> CREATOR; } } @@ -17721,7 +17737,7 @@ package android.net.sip { method public java.lang.String getUriString(); method public java.lang.String getUserName(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.sip.SipProfile> CREATOR; } public static class SipProfile.Builder { @@ -17920,7 +17936,7 @@ package android.net.wifi { method public void setPhase2Method(int); method public void setSubjectMatch(java.lang.String); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR; } public static final class WifiEnterpriseConfig.Eap { @@ -18056,7 +18072,7 @@ package android.net.wifi { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); field public java.lang.String BSSID; - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.wifi.WpsInfo> CREATOR; field public static final int DISPLAY = 1; // 0x1 field public static final int INVALID = 4; // 0x4 field public static final int KEYPAD = 2; // 0x2 @@ -18075,7 +18091,7 @@ package android.net.wifi.p2p { ctor public WifiP2pConfig(android.net.wifi.p2p.WifiP2pConfig); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pConfig> CREATOR; field public java.lang.String deviceAddress; field public int groupOwnerIntent; field public android.net.wifi.WpsInfo wps; @@ -18093,7 +18109,7 @@ package android.net.wifi.p2p { method public void writeToParcel(android.os.Parcel, int); field public static final int AVAILABLE = 3; // 0x3 field public static final int CONNECTED = 0; // 0x0 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pDevice> CREATOR; field public static final int FAILED = 2; // 0x2 field public static final int INVITED = 1; // 0x1 field public static final int UNAVAILABLE = 4; // 0x4 @@ -18111,7 +18127,7 @@ package android.net.wifi.p2p { method public android.net.wifi.p2p.WifiP2pDevice get(java.lang.String); method public java.util.Collection<android.net.wifi.p2p.WifiP2pDevice> getDeviceList(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pDeviceList> CREATOR; } public class WifiP2pGroup implements android.os.Parcelable { @@ -18125,7 +18141,7 @@ package android.net.wifi.p2p { method public java.lang.String getPassphrase(); method public boolean isGroupOwner(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroup> CREATOR; } public class WifiP2pInfo implements android.os.Parcelable { @@ -18133,7 +18149,7 @@ package android.net.wifi.p2p { ctor public WifiP2pInfo(android.net.wifi.p2p.WifiP2pInfo); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pInfo> CREATOR; field public boolean groupFormed; field public java.net.InetAddress groupOwnerAddress; field public boolean isGroupOwner; @@ -18280,7 +18296,7 @@ package android.nfc { method public android.nfc.NdefRecord[] getRecords(); method public byte[] toByteArray(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.nfc.NdefMessage> CREATOR; } public final class NdefRecord implements android.os.Parcelable { @@ -18301,7 +18317,7 @@ package android.nfc { method public java.lang.String toMimeType(); method public android.net.Uri toUri(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.nfc.NdefRecord> CREATOR; field public static final byte[] RTD_ALTERNATIVE_CARRIER; field public static final byte[] RTD_HANDOVER_CARRIER; field public static final byte[] RTD_HANDOVER_REQUEST; @@ -18385,7 +18401,7 @@ package android.nfc { method public byte[] getId(); method public java.lang.String[] getTechList(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.nfc.Tag> CREATOR; } public class TagLostException extends java.io.IOException { @@ -21399,6 +21415,7 @@ package android.os { field public static final int KITKAT = 19; // 0x13 field public static final int KITKAT_WATCH = 20; // 0x14 field public static final int LOLLIPOP = 21; // 0x15 + field public static final int LOLLIPOP_MR1 = 22; // 0x16 } public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable { @@ -21469,7 +21486,7 @@ package android.os { method public void readFromParcel(android.os.Parcel); method public void setClassLoader(java.lang.ClassLoader); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.Bundle> CREATOR; field public static final android.os.Bundle EMPTY; } @@ -21597,7 +21614,7 @@ package android.os { method public int getTotalSwappablePss(); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.Debug.MemoryInfo> CREATOR; field public int dalvikPrivateDirty; field public int dalvikPss; field public int dalvikSharedDirty; @@ -21638,7 +21655,7 @@ package android.os { method public java.lang.String getText(int); method public long getTimeMillis(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.DropBoxManager.Entry> CREATOR; } public class Environment { @@ -21824,7 +21841,7 @@ package android.os { method public void setData(android.os.Bundle); method public void setTarget(android.os.Handler); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.Message> CREATOR; field public int arg1; field public int arg2; field public java.lang.Object obj; @@ -21851,7 +21868,7 @@ package android.os { method public void send(android.os.Message) throws android.os.RemoteException; method public static void writeMessengerOrNullToParcel(android.os.Messenger, android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.Messenger> CREATOR; } public class NetworkOnMainThreadException extends java.lang.RuntimeException { @@ -21970,7 +21987,7 @@ package android.os { method public final void writeTypedArray(T[], int); method public final void writeTypedList(java.util.List<T>); method public final void writeValue(java.lang.Object); - field public static final android.os.Parcelable.Creator STRING_CREATOR; + field public static final android.os.Parcelable.Creator<java.lang.String> STRING_CREATOR; } public class ParcelFileDescriptor implements java.io.Closeable android.os.Parcelable { @@ -21998,7 +22015,7 @@ package android.os { method public static android.os.ParcelFileDescriptor open(java.io.File, int, android.os.Handler, android.os.ParcelFileDescriptor.OnCloseListener) throws java.io.IOException; method public static int parseMode(java.lang.String); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.ParcelFileDescriptor> CREATOR; field public static final int MODE_APPEND = 33554432; // 0x2000000 field public static final int MODE_CREATE = 134217728; // 0x8000000 field public static final int MODE_READ_ONLY = 268435456; // 0x10000000 @@ -22036,7 +22053,7 @@ package android.os { method public static android.os.ParcelUuid fromString(java.lang.String); method public java.util.UUID getUuid(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.ParcelUuid> CREATOR; } public abstract interface Parcelable { @@ -22063,7 +22080,7 @@ package android.os { method public final int getType(); method public boolean match(java.lang.String); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.PatternMatcher> CREATOR; field public static final int PATTERN_LITERAL = 0; // 0x0 field public static final int PATTERN_PREFIX = 1; // 0x1 field public static final int PATTERN_SIMPLE_GLOB = 2; // 0x2 @@ -22078,7 +22095,7 @@ package android.os { method public android.os.PersistableBundle getPersistableBundle(java.lang.String); method public void putPersistableBundle(java.lang.String, android.os.PersistableBundle); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.PersistableBundle> CREATOR; field public static final android.os.PersistableBundle EMPTY; } @@ -22182,7 +22199,7 @@ package android.os { method protected void onReceiveResult(int, android.os.Bundle); method public void send(int, android.os.Bundle); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.ResultReceiver> CREATOR; } public class StatFs { @@ -22294,7 +22311,7 @@ package android.os { 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); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.UserHandle> CREATOR; } public class UserManager { @@ -22361,7 +22378,7 @@ package android.os { method public boolean remove(android.os.WorkSource); method public void set(android.os.WorkSource); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.os.WorkSource> CREATOR; } } @@ -22566,7 +22583,7 @@ package android.preference { public static class Preference.BaseSavedState extends android.view.AbsSavedState { ctor public Preference.BaseSavedState(android.os.Parcel); ctor public Preference.BaseSavedState(android.os.Parcelable); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.preference.Preference.BaseSavedState> CREATOR; } public static abstract interface Preference.OnPreferenceChangeListener { @@ -22626,7 +22643,7 @@ package android.preference { method public java.lang.CharSequence getTitle(android.content.res.Resources); method public void readFromParcel(android.os.Parcel); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.preference.PreferenceActivity.Header> CREATOR; field public java.lang.CharSequence breadCrumbShortTitle; field public int breadCrumbShortTitleRes; field public java.lang.CharSequence breadCrumbTitle; @@ -22778,7 +22795,7 @@ package android.print { method public int getStart(); method public void writeToParcel(android.os.Parcel, int); field public static final android.print.PageRange ALL_PAGES; - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.print.PageRange> CREATOR; } public final class PrintAttributes implements android.os.Parcelable { @@ -22790,7 +22807,7 @@ package android.print { method public void writeToParcel(android.os.Parcel, int); field public static final int COLOR_MODE_COLOR = 2; // 0x2 field public static final int COLOR_MODE_MONOCHROME = 1; // 0x1 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.print.PrintAttributes> CREATOR; } public static final class PrintAttributes.Builder { @@ -22944,7 +22961,7 @@ package android.print { field public static final int CONTENT_TYPE_DOCUMENT = 0; // 0x0 field public static final int CONTENT_TYPE_PHOTO = 1; // 0x1 field public static final int CONTENT_TYPE_UNKNOWN = -1; // 0xffffffff - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.print.PrintDocumentInfo> CREATOR; field public static final int PAGE_COUNT_UNKNOWN = -1; // 0xffffffff } @@ -22971,7 +22988,7 @@ package android.print { public final class PrintJobId implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.print.PrintJobId> CREATOR; } public final class PrintJobInfo implements android.os.Parcelable { @@ -22985,7 +23002,7 @@ package android.print { method public android.print.PrinterId getPrinterId(); method public int getState(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.print.PrintJobInfo> CREATOR; field public static final int STATE_BLOCKED = 4; // 0x4 field public static final int STATE_CANCELED = 7; // 0x7 field public static final int STATE_COMPLETED = 5; // 0x5 @@ -23018,7 +23035,7 @@ package android.print { method public android.print.PrintAttributes.Margins getMinMargins(); method public java.util.List<android.print.PrintAttributes.Resolution> getResolutions(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.print.PrinterCapabilitiesInfo> CREATOR; } public static final class PrinterCapabilitiesInfo.Builder { @@ -23034,7 +23051,7 @@ package android.print { method public int describeContents(); method public java.lang.String getLocalId(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.print.PrinterId> CREATOR; } public final class PrinterInfo implements android.os.Parcelable { @@ -23045,7 +23062,7 @@ package android.print { method public java.lang.String getName(); method public int getStatus(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.print.PrinterInfo> CREATOR; field public static final int STATUS_BUSY = 2; // 0x2 field public static final int STATUS_IDLE = 1; // 0x1 field public static final int STATUS_UNAVAILABLE = 3; // 0x3 @@ -25516,6 +25533,7 @@ package android.provider { field public static final java.lang.String STATUS = "st"; field public static final java.lang.String SUBJECT = "sub"; field public static final java.lang.String SUBJECT_CHARSET = "sub_cs"; + field public static final java.lang.String SUB_ID = "sub_id"; field public static final java.lang.String TEXT_ONLY = "text_only"; field public static final java.lang.String THREAD_ID = "thread_id"; field public static final java.lang.String TRANSACTION_ID = "tr_id"; @@ -25548,6 +25566,7 @@ package android.provider { field public static final java.lang.String PROXY = "proxy"; field public static final java.lang.String ROAMING_PROTOCOL = "roaming_protocol"; field public static final java.lang.String SERVER = "server"; + field public static final java.lang.String SUB_ID = "sub_id"; field public static final java.lang.String TYPE = "type"; field public static final java.lang.String USER = "user"; } @@ -25580,6 +25599,10 @@ package android.provider { public static final class Telephony.Mms.Intents { field public static final java.lang.String CONTENT_CHANGED_ACTION = "android.intent.action.CONTENT_CHANGED"; field public static final java.lang.String DELETED_CONTENTS = "deleted_contents"; + field public static final java.lang.String EXTRA_MMS_CONTENT_URI = "android.provider.Telephony.extra.MMS_CONTENT_URI"; + field public static final java.lang.String EXTRA_MMS_LOCATION_URL = "android.provider.Telephony.extra.MMS_LOCATION_URL"; + field public static final java.lang.String MMS_DOWNLOAD_ACTION = "android.provider.Telephony.MMS_DOWNLOAD"; + field public static final java.lang.String MMS_SEND_ACTION = "android.provider.Telephony.MMS_SEND"; } public static final class Telephony.Mms.Outbox implements android.provider.Telephony.BaseMmsColumns { @@ -25644,6 +25667,7 @@ package android.provider { field public static final java.lang.String MSG_TYPE = "msg_type"; field public static final java.lang.String PROTO_TYPE = "proto_type"; field public static final java.lang.String RETRY_INDEX = "retry_index"; + field public static final java.lang.String SUB_ID = "pending_sub_id"; } public static final class Telephony.Sms implements android.provider.BaseColumns android.provider.Telephony.TextBasedSmsColumns { @@ -25683,8 +25707,10 @@ package android.provider { 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"; + field public static final java.lang.String SMS_FILTER_ACTION = "android.provider.Telephony.SMS_FILTER"; field public static final java.lang.String SMS_RECEIVED_ACTION = "android.provider.Telephony.SMS_RECEIVED"; field public static final java.lang.String SMS_REJECTED_ACTION = "android.provider.Telephony.SMS_REJECTED"; + field public static final java.lang.String SMS_SEND_ACTION = "android.provider.Telephony.SMS_SEND"; field public static final java.lang.String SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED_ACTION = "android.provider.Telephony.SMS_SERVICE_CATEGORY_PROGRAM_DATA_RECEIVED"; field public static final java.lang.String WAP_PUSH_DELIVER_ACTION = "android.provider.Telephony.WAP_PUSH_DELIVER"; field public static final java.lang.String WAP_PUSH_RECEIVED_ACTION = "android.provider.Telephony.WAP_PUSH_RECEIVED"; @@ -25727,6 +25753,7 @@ package android.provider { field public static final int STATUS_NONE = -1; // 0xffffffff field public static final int STATUS_PENDING = 32; // 0x20 field public static final java.lang.String SUBJECT = "subject"; + field public static final java.lang.String SUB_ID = "sub_id"; field public static final java.lang.String THREAD_ID = "thread_id"; field public static final java.lang.String TYPE = "type"; } @@ -26951,7 +26978,7 @@ package android.service.notification { method public java.lang.String[] getOrderedKeys(); method public boolean getRanking(java.lang.String, android.service.notification.NotificationListenerService.Ranking); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.service.notification.NotificationListenerService.RankingMap> CREATOR; } public class StatusBarNotification implements android.os.Parcelable { @@ -26971,7 +26998,7 @@ package android.service.notification { method public boolean isClearable(); method public boolean isOngoing(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.service.notification.StatusBarNotification> CREATOR; } } @@ -27387,7 +27414,7 @@ package android.speech.tts { method public int getQuality(); method public boolean isNetworkConnectionRequired(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.speech.tts.Voice> CREATOR; field public static final int LATENCY_HIGH = 400; // 0x190 field public static final int LATENCY_LOW = 200; // 0xc8 field public static final int LATENCY_NORMAL = 300; // 0x12c @@ -28037,16 +28064,338 @@ package android.system { package android.telecom { + public final class AudioState implements android.os.Parcelable { + ctor public AudioState(boolean, int, int); + ctor public AudioState(android.telecom.AudioState); + method public int describeContents(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telecom.AudioState> CREATOR; + field public static final int ROUTE_BLUETOOTH = 2; // 0x2 + field public static final int ROUTE_EARPIECE = 1; // 0x1 + field public static final int ROUTE_SPEAKER = 8; // 0x8 + field public static final int ROUTE_WIRED_HEADSET = 4; // 0x4 + field public static final int ROUTE_WIRED_OR_EARPIECE = 5; // 0x5 + field public final boolean isMuted; + field public final int route; + field public final int supportedRouteMask; + } + + public abstract class Conference { + ctor public Conference(android.telecom.PhoneAccountHandle); + method public final boolean addConnection(android.telecom.Connection); + method public final void destroy(); + method public final android.telecom.AudioState getAudioState(); + method public final int getCapabilities(); + method public final java.util.List<android.telecom.Connection> getConferenceableConnections(); + method public final java.util.List<android.telecom.Connection> getConnections(); + method public final android.telecom.PhoneAccountHandle getPhoneAccountHandle(); + method public final int getState(); + method public void onAudioStateChanged(android.telecom.AudioState); + method public void onDisconnect(); + method public void onHold(); + method public void onMerge(android.telecom.Connection); + method public void onMerge(); + method public void onPlayDtmfTone(char); + method public void onSeparate(android.telecom.Connection); + method public void onStopDtmfTone(); + method public void onSwap(); + method public void onUnhold(); + method public final void removeConnection(android.telecom.Connection); + method public final void setActive(); + method public final void setCapabilities(int); + method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>); + method public final void setDisconnected(android.telecom.DisconnectCause); + method public final void setOnHold(); + } + + public abstract class Connection { + ctor public Connection(); + method public static android.telecom.Connection createCanceledConnection(); + method public static android.telecom.Connection createFailedConnection(android.telecom.DisconnectCause); + method public final void destroy(); + method public final android.net.Uri getAddress(); + method public final int getAddressPresentation(); + method public final boolean getAudioModeIsVoip(); + method public final android.telecom.AudioState getAudioState(); + method public final int getCallCapabilities(); + method public final java.lang.String getCallerDisplayName(); + method public final int getCallerDisplayNamePresentation(); + method public final android.telecom.Conference getConference(); + method public final java.util.List<android.telecom.Connection> getConferenceableConnections(); + method public final android.telecom.DisconnectCause getDisconnectCause(); + method public final int getState(); + method public final android.telecom.StatusHints getStatusHints(); + method public final boolean isRingbackRequested(); + method public void onAbort(); + method public void onAnswer(); + method public void onAudioStateChanged(android.telecom.AudioState); + method public void onConferenceChanged(); + method public void onDisconnect(); + method public void onHold(); + method public void onPlayDtmfTone(char); + method public void onPostDialContinue(boolean); + method public void onReject(); + method public void onSeparate(); + method public void onStateChanged(int); + method public void onStopDtmfTone(); + method public void onUnhold(); + method public final void setActive(); + method public final void setAddress(android.net.Uri, int); + method public final void setAudioModeIsVoip(boolean); + method public final void setCallCapabilities(int); + method public final void setCallerDisplayName(java.lang.String, int); + method public final void setConferenceableConnections(java.util.List<android.telecom.Connection>); + method public final void setConnectionService(android.telecom.ConnectionService); + method public final void setDialing(); + method public final void setDisconnected(android.telecom.DisconnectCause); + method public final void setInitialized(); + method public final void setInitializing(); + method public final void setOnHold(); + method public final void setPostDialWait(java.lang.String); + method public final void setRingbackRequested(boolean); + method public final void setRinging(); + method public final void setStatusHints(android.telecom.StatusHints); + method public static java.lang.String stateToString(int); + field public static final int STATE_ACTIVE = 4; // 0x4 + field public static final int STATE_DIALING = 3; // 0x3 + field public static final int STATE_DISCONNECTED = 6; // 0x6 + field public static final int STATE_HOLDING = 5; // 0x5 + field public static final int STATE_INITIALIZING = 0; // 0x0 + field public static final int STATE_NEW = 1; // 0x1 + field public static final int STATE_RINGING = 2; // 0x2 + } + + public final class ConnectionRequest implements android.os.Parcelable { + ctor public ConnectionRequest(android.telecom.PhoneAccountHandle, android.net.Uri, android.os.Bundle); + method public int describeContents(); + method public android.telecom.PhoneAccountHandle getAccountHandle(); + method public android.net.Uri getAddress(); + method public android.os.Bundle getExtras(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telecom.ConnectionRequest> CREATOR; + } + + public abstract class ConnectionService extends android.app.Service { + ctor public ConnectionService(); + method public final void addConference(android.telecom.Conference); + method public final void conferenceRemoteConnections(android.telecom.RemoteConnection, android.telecom.RemoteConnection); + method public final android.telecom.RemoteConnection createRemoteIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public final android.telecom.RemoteConnection createRemoteOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public final java.util.Collection<android.telecom.Connection> getAllConnections(); + method public final android.os.IBinder onBind(android.content.Intent); + method public void onConference(android.telecom.Connection, android.telecom.Connection); + method public android.telecom.Connection onCreateIncomingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public android.telecom.Connection onCreateOutgoingConnection(android.telecom.PhoneAccountHandle, android.telecom.ConnectionRequest); + method public void onRemoteConferenceAdded(android.telecom.RemoteConference); + field public static final java.lang.String SERVICE_INTERFACE = "android.telecom.ConnectionService"; + } + + public final class DisconnectCause implements android.os.Parcelable { + ctor public DisconnectCause(int); + ctor public DisconnectCause(int, java.lang.String); + ctor public DisconnectCause(int, java.lang.CharSequence, java.lang.CharSequence, java.lang.String); + ctor public DisconnectCause(int, java.lang.CharSequence, java.lang.CharSequence, java.lang.String, int); + method public int describeContents(); + method public int getCode(); + method public java.lang.CharSequence getDescription(); + method public java.lang.CharSequence getLabel(); + method public java.lang.String getReason(); + method public int getTone(); + method public void writeToParcel(android.os.Parcel, int); + field public static final int BUSY = 7; // 0x7 + field public static final int CANCELED = 4; // 0x4 + field public static final android.os.Parcelable.Creator<android.telecom.DisconnectCause> CREATOR; + field public static final int ERROR = 1; // 0x1 + field public static final int LOCAL = 2; // 0x2 + field public static final int MISSED = 5; // 0x5 + field public static final int OTHER = 9; // 0x9 + field public static final int REJECTED = 6; // 0x6 + field public static final int REMOTE = 3; // 0x3 + field public static final int RESTRICTED = 8; // 0x8 + field public static final int UNKNOWN = 0; // 0x0 + } + + public class GatewayInfo implements android.os.Parcelable { + method public int describeContents(); + method public android.net.Uri getGatewayAddress(); + method public java.lang.String getGatewayProviderPackageName(); + method public android.net.Uri getOriginalAddress(); + method public boolean isEmpty(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telecom.GatewayInfo> CREATOR; + } + + public class PhoneAccount implements android.os.Parcelable { + method public static android.telecom.PhoneAccount.Builder builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence); + method public int describeContents(); + method public android.telecom.PhoneAccountHandle getAccountHandle(); + method public android.net.Uri getAddress(); + method public int getCapabilities(); + method public int getColor(); + method public android.graphics.drawable.Drawable getIcon(android.content.Context); + method public int getIconResId(); + method public java.lang.CharSequence getLabel(); + method public java.lang.CharSequence getShortDescription(); + method public android.net.Uri getSubscriptionAddress(); + method public java.util.List<java.lang.String> getSupportedUriSchemes(); + method public boolean hasCapabilities(int); + method public boolean supportsUriScheme(java.lang.String); + method public void writeToParcel(android.os.Parcel, int); + field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1 + field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10 + field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4 + field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR; + field public static final int NO_COLOR = -1; // 0xffffffff + field public static final java.lang.String SCHEME_SIP = "sip"; + field public static final java.lang.String SCHEME_TEL = "tel"; + field public static final java.lang.String SCHEME_VOICEMAIL = "voicemail"; + } + + public static class PhoneAccount.Builder { + ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence); + ctor public PhoneAccount.Builder(android.telecom.PhoneAccount); + method public android.telecom.PhoneAccount build(); + method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri); + method public android.telecom.PhoneAccount.Builder setCapabilities(int); + method public android.telecom.PhoneAccount.Builder setColor(int); + method public android.telecom.PhoneAccount.Builder setIconResId(int); + method public android.telecom.PhoneAccount.Builder setShortDescription(java.lang.CharSequence); + method public android.telecom.PhoneAccount.Builder setSubscriptionAddress(android.net.Uri); + method public android.telecom.PhoneAccount.Builder setSupportedUriSchemes(java.util.List<java.lang.String>); + } + + public class PhoneAccountHandle implements android.os.Parcelable { + ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String); + method public int describeContents(); + method public android.content.ComponentName getComponentName(); + method public java.lang.String getId(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccountHandle> CREATOR; + } + + public final class PhoneCapabilities { + method public static java.lang.String toString(int); + field public static final int ADD_CALL = 16; // 0x10 + field public static final int ALL = 12543; // 0x30ff + field public static final int DISCONNECT_FROM_CONFERENCE = 8192; // 0x2000 + field public static final int HOLD = 1; // 0x1 + field public static final int MANAGE_CONFERENCE = 128; // 0x80 + field public static final int MERGE_CONFERENCE = 4; // 0x4 + field public static final int MUTE = 64; // 0x40 + field public static final int RESPOND_VIA_TEXT = 32; // 0x20 + field public static final int SEPARATE_FROM_CONFERENCE = 4096; // 0x1000 + field public static final int SUPPORT_HOLD = 2; // 0x2 + field public static final int SWAP_CONFERENCE = 8; // 0x8 + } + + public final class RemoteConference { + method public void disconnect(); + method public final int getCallCapabilities(); + method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections(); + method public final java.util.List<android.telecom.RemoteConnection> getConnections(); + method public android.telecom.DisconnectCause getDisconnectCause(); + method public final int getState(); + method public void hold(); + method public void merge(); + method public void playDtmfTone(char); + method public final void registerCallback(android.telecom.RemoteConference.Callback); + method public void separate(android.telecom.RemoteConnection); + method public void setAudioState(android.telecom.AudioState); + method public void stopDtmfTone(); + method public void swap(); + method public void unhold(); + method public final void unregisterCallback(android.telecom.RemoteConference.Callback); + } + + public static abstract class RemoteConference.Callback { + ctor public RemoteConference.Callback(); + method public void onCapabilitiesChanged(android.telecom.RemoteConference, int); + method public void onConferenceableConnectionsChanged(android.telecom.RemoteConference, java.util.List<android.telecom.RemoteConnection>); + method public void onConnectionAdded(android.telecom.RemoteConference, android.telecom.RemoteConnection); + method public void onConnectionRemoved(android.telecom.RemoteConference, android.telecom.RemoteConnection); + method public void onDestroyed(android.telecom.RemoteConference); + method public void onDisconnected(android.telecom.RemoteConference, android.telecom.DisconnectCause); + method public void onStateChanged(android.telecom.RemoteConference, int, int); + } + + public final class RemoteConnection { + method public void abort(); + method public void answer(); + method public void disconnect(); + method public android.net.Uri getAddress(); + method public int getAddressPresentation(); + method public int getCallCapabilities(); + method public java.lang.CharSequence getCallerDisplayName(); + method public int getCallerDisplayNamePresentation(); + method public android.telecom.RemoteConference getConference(); + method public java.util.List<android.telecom.RemoteConnection> getConferenceableConnections(); + method public android.telecom.DisconnectCause getDisconnectCause(); + method public int getState(); + method public android.telecom.StatusHints getStatusHints(); + method public void hold(); + method public boolean isRingbackRequested(); + method public boolean isVoipAudioMode(); + method public void playDtmfTone(char); + method public void postDialContinue(boolean); + method public void registerCallback(android.telecom.RemoteConnection.Callback); + method public void reject(); + method public void setAudioState(android.telecom.AudioState); + method public void stopDtmfTone(); + method public void unhold(); + method public void unregisterCallback(android.telecom.RemoteConnection.Callback); + } + + public static abstract class RemoteConnection.Callback { + ctor public RemoteConnection.Callback(); + method public void onAddressChanged(android.telecom.RemoteConnection, android.net.Uri, int); + method public void onCallCapabilitiesChanged(android.telecom.RemoteConnection, int); + method public void onCallerDisplayNameChanged(android.telecom.RemoteConnection, java.lang.String, int); + method public void onConferenceChanged(android.telecom.RemoteConnection, android.telecom.RemoteConference); + method public void onConferenceableConnectionsChanged(android.telecom.RemoteConnection, java.util.List<android.telecom.RemoteConnection>); + method public void onDestroyed(android.telecom.RemoteConnection); + method public void onDisconnected(android.telecom.RemoteConnection, android.telecom.DisconnectCause); + method public void onPostDialWait(android.telecom.RemoteConnection, java.lang.String); + method public void onRingbackRequested(android.telecom.RemoteConnection, boolean); + method public void onStateChanged(android.telecom.RemoteConnection, int); + method public void onStatusHintsChanged(android.telecom.RemoteConnection, android.telecom.StatusHints); + method public void onVoipAudioChanged(android.telecom.RemoteConnection, boolean); + } + + public final class StatusHints implements android.os.Parcelable { + ctor public StatusHints(android.content.ComponentName, java.lang.CharSequence, int, android.os.Bundle); + method public int describeContents(); + method public android.os.Bundle getExtras(); + method public android.graphics.drawable.Drawable getIcon(android.content.Context); + method public int getIconResId(); + method public java.lang.CharSequence getLabel(); + method public android.content.ComponentName getPackageName(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telecom.StatusHints> CREATOR; + } + public class TelecomManager { + method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle); method public void cancelMissedCallsNotification(); + method public void clearAccounts(); + method public android.telecom.PhoneAccountHandle getConnectionManager(); + method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle); + method public java.util.List<android.telecom.PhoneAccountHandle> getPhoneAccountsForPackage(); method public boolean handleMmi(java.lang.String); + method public boolean hasMultipleCallCapableAccounts(); method public boolean isInCall(); + method public void registerPhoneAccount(android.telecom.PhoneAccount); method public void showInCallScreen(boolean); + method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle); + field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS"; + field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"; field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS"; field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ',' field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';' + field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER"; field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE"; field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE"; + field public static final java.lang.String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE"; + field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE"; field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE"; field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS"; field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE"; @@ -28068,7 +28417,7 @@ package android.telephony { method public int getNetworkId(); method public int getSystemId(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityCdma> CREATOR; } public final class CellIdentityGsm implements android.os.Parcelable { @@ -28079,7 +28428,7 @@ package android.telephony { method public int getMnc(); method public deprecated int getPsc(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityGsm> CREATOR; } public final class CellIdentityLte implements android.os.Parcelable { @@ -28090,7 +28439,7 @@ package android.telephony { method public int getPci(); method public int getTac(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityLte> CREATOR; } public final class CellIdentityWcdma implements android.os.Parcelable { @@ -28101,7 +28450,7 @@ package android.telephony { method public int getMnc(); method public int getPsc(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellIdentityWcdma> CREATOR; } public abstract class CellInfo implements android.os.Parcelable { @@ -28109,35 +28458,35 @@ package android.telephony { method public long getTimeStamp(); method public boolean isRegistered(); method public abstract void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellInfo> CREATOR; } public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable { method public android.telephony.CellIdentityCdma getCellIdentity(); method public android.telephony.CellSignalStrengthCdma getCellSignalStrength(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellInfoCdma> CREATOR; } public final class CellInfoGsm extends android.telephony.CellInfo implements android.os.Parcelable { method public android.telephony.CellIdentityGsm getCellIdentity(); method public android.telephony.CellSignalStrengthGsm getCellSignalStrength(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellInfoGsm> CREATOR; } public final class CellInfoLte extends android.telephony.CellInfo implements android.os.Parcelable { method public android.telephony.CellIdentityLte getCellIdentity(); method public android.telephony.CellSignalStrengthLte getCellSignalStrength(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellInfoLte> CREATOR; } public final class CellInfoWcdma extends android.telephony.CellInfo implements android.os.Parcelable { method public android.telephony.CellIdentityWcdma getCellIdentity(); method public android.telephony.CellSignalStrengthWcdma getCellSignalStrength(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellInfoWcdma> CREATOR; } public abstract class CellLocation { @@ -28169,7 +28518,7 @@ package android.telephony { method public int getLevel(); method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthCdma> CREATOR; } public final class CellSignalStrengthGsm extends android.telephony.CellSignalStrength implements android.os.Parcelable { @@ -28180,7 +28529,7 @@ package android.telephony { method public int getLevel(); method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR; } public final class CellSignalStrengthLte extends android.telephony.CellSignalStrength implements android.os.Parcelable { @@ -28192,7 +28541,7 @@ package android.telephony { method public int getTimingAdvance(); method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthLte> CREATOR; } public final class CellSignalStrengthWcdma extends android.telephony.CellSignalStrength implements android.os.Parcelable { @@ -28203,7 +28552,7 @@ package android.telephony { method public int getLevel(); method public int hashCode(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthWcdma> CREATOR; } public class IccOpenLogicalChannelResponse implements android.os.Parcelable { @@ -28212,7 +28561,7 @@ package android.telephony { method public byte[] getSelectResponse(); method public int getStatus(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.IccOpenLogicalChannelResponse> CREATOR; field public static final int INVALID_CHANNEL = -1; // 0xffffffff field public static final int STATUS_MISSING_RESOURCE = 2; // 0x2 field public static final int STATUS_NO_ERROR = 1; // 0x1 @@ -28234,7 +28583,7 @@ package android.telephony { method public deprecated void setCid(int); method public deprecated void setRssi(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.NeighboringCellInfo> CREATOR; field public static final int UNKNOWN_CID = -1; // 0xffffffff field public static final int UNKNOWN_RSSI = 99; // 0x63 } @@ -28341,7 +28690,7 @@ package android.telephony { method public void setStateOff(); method public void setStateOutOfService(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.telephony.ServiceState> CREATOR; field public static final int STATE_EMERGENCY_ONLY = 2; // 0x2 field public static final int STATE_IN_SERVICE = 0; // 0x0 field public static final int STATE_OUT_OF_SERVICE = 1; // 0x1 @@ -28366,11 +28715,18 @@ package android.telephony { method public void downloadMultimediaMessage(android.content.Context, java.lang.String, android.net.Uri, android.os.Bundle, android.app.PendingIntent); method public android.os.Bundle getCarrierConfigValues(); method public static android.telephony.SmsManager getDefault(); + method public static android.telephony.SmsManager getSmsManagerForSubscriber(int); + method public int getSubId(); + method public void injectSmsPdu(byte[], java.lang.String, android.app.PendingIntent); method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent); method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent); method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>); method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent); + method public void updateMmsDownloadStatus(android.content.Context, int, int, android.net.Uri); + method public void updateMmsSendStatus(android.content.Context, int, byte[], int, android.net.Uri); + method public void updateSmsSendStatus(int, boolean); field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA"; + field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS"; field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled"; field public static final java.lang.String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars"; field public static final java.lang.String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars"; @@ -28476,6 +28832,47 @@ package android.telephony { field public byte[] encodedScAddress; } + public class SubInfoRecord implements android.os.Parcelable { + ctor public SubInfoRecord(); + ctor public SubInfoRecord(int, java.lang.String, int, java.lang.String, int, int, java.lang.String, int, int, int[], int, int); + method public int describeContents(); + method public int getColor(); + method public android.graphics.drawable.BitmapDrawable getIconDrawable(); + method public java.lang.String getLabel(); + method public void writeToParcel(android.os.Parcel, int); + field public static final android.os.Parcelable.Creator<android.telephony.SubInfoRecord> CREATOR; + field public int color; + field public int dataRoaming; + field public java.lang.String displayName; + field public int displayNumberFormat; + field public java.lang.String iccId; + field public int mcc; + field public int mnc; + field public int nameSource; + field public java.lang.String number; + field public int[] simIconRes; + field public int slotId; + field public int subId; + } + + public class SubscriptionManager implements android.provider.BaseColumns { + method public static java.util.List<android.telephony.SubInfoRecord> getActiveSubInfoList(); + method public static int getDefaultSmsSubId(); + method public static int getSlotId(int); + method public static android.telephony.SubInfoRecord getSubInfoForSubscriber(int); + method public static java.util.List<android.telephony.SubInfoRecord> getSubInfoUsingSlotId(int); + method public static boolean isValidSubId(int); + field public static final int ASK_USER_SUB_ID = -1001; // 0xfffffc17 + field public static final int DEFAULT_PHONE_ID = 2147483647; // 0x7fffffff + field public static final int DEFAULT_SUB_ID = 2147483647; // 0x7fffffff + field public static final int INVALID_PHONE_ID = -1000; // 0xfffffc18 + field public static final int INVALID_SLOT_ID = -1000; // 0xfffffc18 + field public static final int INVALID_SUB_ID = -1000; // 0xfffffc18 + field public static final java.lang.String MCC = "mcc"; + field public static final java.lang.String MNC = "mnc"; + field public static final int SIM_NOT_INSERTED = -1; // 0xffffffff + } + public class TelephonyManager { method public java.util.List<android.telephony.CellInfo> getAllCellInfo(); method public int getCallState(); @@ -28502,6 +28899,7 @@ package android.telephony { method public java.lang.String getSubscriberId(); method public java.lang.String getVoiceMailAlphaTag(); method public java.lang.String getVoiceMailNumber(); + method public int hasCarrierPrivileges(); method public boolean hasIccCard(); method public boolean iccCloseLogicalChannel(int); method public byte[] iccExchangeSimIO(int, int, int, int, int, java.lang.String); @@ -28512,11 +28910,18 @@ package android.telephony { method public boolean isSmsCapable(); method public void listen(android.telephony.PhoneStateListener, int); method public java.lang.String sendEnvelopeWithStatus(java.lang.String); + method public boolean setGlobalPreferredNetworkType(); + method public void setLine1NumberForDisplay(java.lang.String, java.lang.String); + method public boolean setOperatorBrandOverride(java.lang.String); field public static final java.lang.String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE"; field public static final java.lang.String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE"; field public static final int CALL_STATE_IDLE = 0; // 0x0 field public static final int CALL_STATE_OFFHOOK = 2; // 0x2 field public static final int CALL_STATE_RINGING = 1; // 0x1 + field public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; // 0xfffffffe + field public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; // 0x1 + field public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; // 0x0 + field public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; // 0xffffffff field public static final int DATA_ACTIVITY_DORMANT = 4; // 0x4 field public static final int DATA_ACTIVITY_IN = 1; // 0x1 field public static final int DATA_ACTIVITY_INOUT = 3; // 0x3 @@ -29806,7 +30211,7 @@ package android.text { field public static final int CAP_MODE_CHARACTERS = 4096; // 0x1000 field public static final int CAP_MODE_SENTENCES = 16384; // 0x4000 field public static final int CAP_MODE_WORDS = 8192; // 0x2000 - field public static final android.os.Parcelable.Creator CHAR_SEQUENCE_CREATOR; + field public static final android.os.Parcelable.Creator<java.lang.CharSequence> CHAR_SEQUENCE_CREATOR; } public static abstract interface TextUtils.EllipsizeCallback { @@ -29944,7 +30349,7 @@ package android.text.format { method public static java.lang.String formatShortFileSize(android.content.Context, long); } - public class Time { + public deprecated class Time { ctor public Time(java.lang.String); ctor public Time(); ctor public Time(android.text.format.Time); @@ -30530,7 +30935,7 @@ package android.text.style { method public void updateDrawState(android.text.TextPaint); method public void writeToParcel(android.os.Parcel, int); field public static final java.lang.String ACTION_SUGGESTION_PICKED = "android.text.style.SUGGESTION_PICKED"; - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.text.style.SuggestionSpan> CREATOR; field public static final int FLAG_AUTO_CORRECTION = 4; // 0x4 field public static final int FLAG_EASY_CORRECT = 1; // 0x1 field public static final int FLAG_MISSPELLED = 2; // 0x2 @@ -30914,6 +31319,7 @@ package android.transition { ctor public ChangeBounds(android.content.Context, android.util.AttributeSet); method public void captureEndValues(android.transition.TransitionValues); method public void captureStartValues(android.transition.TransitionValues); + method public boolean getResizeClip(); method public deprecated void setReparent(boolean); method public void setResizeClip(boolean); } @@ -31110,7 +31516,7 @@ package android.transition { public class TransitionValues { ctor public TransitionValues(); - field public final java.util.Map values; + field public final java.util.Map<java.lang.String, java.lang.Object> values; field public android.view.View view; } @@ -31315,7 +31721,7 @@ package android.util { field public final int mTag; } - public class FloatMath { + public deprecated class FloatMath { method public static float ceil(float); method public static float cos(float); method public static float exp(float); @@ -31818,7 +32224,7 @@ package android.view { method public int describeContents(); method public final android.os.Parcelable getSuperState(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.AbsSavedState> CREATOR; field public static final android.view.AbsSavedState EMPTY_STATE; } @@ -31951,7 +32357,7 @@ package android.view { field public static final int ACTION_DRAG_LOCATION = 2; // 0x2 field public static final int ACTION_DRAG_STARTED = 1; // 0x1 field public static final int ACTION_DROP = 3; // 0x3 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR; } public class FocusFinder { @@ -32088,7 +32494,7 @@ package android.view { method public boolean isVirtual(); method public boolean supportsSource(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.InputDevice> CREATOR; field public static final int KEYBOARD_TYPE_ALPHABETIC = 2; // 0x2 field public static final int KEYBOARD_TYPE_NONE = 0; // 0x0 field public static final int KEYBOARD_TYPE_NON_ALPHABETIC = 1; // 0x1 @@ -32142,7 +32548,7 @@ package android.view { method public abstract long getEventTime(); method public abstract int getSource(); method public boolean isFromSource(int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.InputEvent> CREATOR; } public final class InputQueue { @@ -32174,7 +32580,7 @@ package android.view { field public static final deprecated int BUILT_IN_KEYBOARD = 0; // 0x0 field public static final int COMBINING_ACCENT = -2147483648; // 0x80000000 field public static final int COMBINING_ACCENT_MASK = 2147483647; // 0x7fffffff - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.KeyCharacterMap> CREATOR; field public static final int FULL = 4; // 0x4 field public static final char HEX_INPUT = 61184; // 0xef00 '\uef00' field public static final int MODIFIER_BEHAVIOR_CHORDED = 0; // 0x0 @@ -32266,7 +32672,7 @@ package android.view { field public static final int ACTION_DOWN = 0; // 0x0 field public static final int ACTION_MULTIPLE = 2; // 0x2 field public static final int ACTION_UP = 1; // 0x1 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.KeyEvent> CREATOR; field public static final int FLAG_CANCELED = 32; // 0x20 field public static final int FLAG_CANCELED_LONG_PRESS = 256; // 0x100 field public static final int FLAG_EDITOR_ACTION = 16; // 0x10 @@ -32866,7 +33272,7 @@ package android.view { field public static final int BUTTON_PRIMARY = 1; // 0x1 field public static final int BUTTON_SECONDARY = 2; // 0x2 field public static final int BUTTON_TERTIARY = 4; // 0x4 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.MotionEvent> CREATOR; field public static final int EDGE_BOTTOM = 2; // 0x2 field public static final int EDGE_LEFT = 4; // 0x4 field public static final int EDGE_RIGHT = 8; // 0x8 @@ -32987,12 +33393,13 @@ package android.view { method public int describeContents(); method public boolean isValid(); method public android.graphics.Canvas lockCanvas(android.graphics.Rect) throws java.lang.IllegalArgumentException, android.view.Surface.OutOfResourcesException; + method public android.graphics.Canvas lockHardwareCanvas(); method public void readFromParcel(android.os.Parcel); method public void release(); method public deprecated void unlockCanvas(android.graphics.Canvas); method public void unlockCanvasAndPost(android.graphics.Canvas); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.Surface> CREATOR; field public static final int ROTATION_0 = 0; // 0x0 field public static final int ROTATION_180 = 2; // 0x2 field public static final int ROTATION_270 = 3; // 0x3 @@ -33586,7 +33993,7 @@ package android.view { field public static final int ACCESSIBILITY_LIVE_REGION_ASSERTIVE = 2; // 0x2 field public static final int ACCESSIBILITY_LIVE_REGION_NONE = 0; // 0x0 field public static final int ACCESSIBILITY_LIVE_REGION_POLITE = 1; // 0x1 - field public static final android.util.Property ALPHA; + field public static final android.util.Property<android.view.View, java.lang.Float> ALPHA; field public static final int DRAWING_CACHE_QUALITY_AUTO = 0; // 0x0 field public static final int DRAWING_CACHE_QUALITY_HIGH = 1048576; // 0x100000 field public static final int DRAWING_CACHE_QUALITY_LOW = 524288; // 0x80000 @@ -33652,11 +34059,11 @@ package android.view { field protected static final int[] PRESSED_SELECTED_WINDOW_FOCUSED_STATE_SET; field protected static final int[] PRESSED_STATE_SET; field protected static final int[] PRESSED_WINDOW_FOCUSED_STATE_SET; - field public static final android.util.Property ROTATION; - field public static final android.util.Property ROTATION_X; - field public static final android.util.Property ROTATION_Y; - field public static final android.util.Property SCALE_X; - field public static final android.util.Property SCALE_Y; + field public static final android.util.Property<android.view.View, java.lang.Float> ROTATION; + field public static final android.util.Property<android.view.View, java.lang.Float> ROTATION_X; + field public static final android.util.Property<android.view.View, java.lang.Float> ROTATION_Y; + field public static final android.util.Property<android.view.View, java.lang.Float> SCALE_X; + field public static final android.util.Property<android.view.View, java.lang.Float> SCALE_Y; field public static final int SCREEN_STATE_OFF = 0; // 0x0 field public static final int SCREEN_STATE_ON = 1; // 0x1 field public static final int SCROLLBARS_INSIDE_INSET = 16777216; // 0x1000000 @@ -33697,15 +34104,15 @@ package android.view { field public static final int TEXT_DIRECTION_LOCALE = 5; // 0x5 field public static final int TEXT_DIRECTION_LTR = 3; // 0x3 field public static final int TEXT_DIRECTION_RTL = 4; // 0x4 - field public static final android.util.Property TRANSLATION_X; - field public static final android.util.Property TRANSLATION_Y; - field public static final android.util.Property TRANSLATION_Z; + field public static final android.util.Property<android.view.View, java.lang.Float> TRANSLATION_X; + field public static final android.util.Property<android.view.View, java.lang.Float> TRANSLATION_Y; + field public static final android.util.Property<android.view.View, java.lang.Float> TRANSLATION_Z; field protected static final java.lang.String VIEW_LOG_TAG = "View"; field public static final int VISIBLE = 0; // 0x0 field protected static final int[] WINDOW_FOCUSED_STATE_SET; - field public static final android.util.Property X; - field public static final android.util.Property Y; - field public static final android.util.Property Z; + field public static final android.util.Property<android.view.View, java.lang.Float> X; + field public static final android.util.Property<android.view.View, java.lang.Float> Y; + field public static final android.util.Property<android.view.View, java.lang.Float> Z; } public static class View.AccessibilityDelegate { @@ -33724,7 +34131,7 @@ package android.view { public static class View.BaseSavedState extends android.view.AbsSavedState { ctor public View.BaseSavedState(android.os.Parcel); ctor public View.BaseSavedState(android.os.Parcelable); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.View.BaseSavedState> CREATOR; } public static class View.DragShadowBuilder { @@ -34421,7 +34828,7 @@ package android.view { public final class WindowAnimationFrameStats extends android.view.FrameStats implements android.os.Parcelable { method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.WindowAnimationFrameStats> CREATOR; } public final class WindowContentFrameStats extends android.view.FrameStats implements android.os.Parcelable { @@ -34429,7 +34836,7 @@ package android.view { method public long getFramePostedTimeNano(int); method public long getFrameReadyTimeNano(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.WindowContentFrameStats> CREATOR; } public class WindowId implements android.os.Parcelable { @@ -34438,7 +34845,7 @@ package android.view { method public void registerFocusObserver(android.view.WindowId.FocusObserver); method public void unregisterFocusObserver(android.view.WindowId.FocusObserver); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.WindowId> CREATOR; } public static abstract class WindowId.FocusObserver { @@ -34503,7 +34910,7 @@ package android.view { field public static final float BRIGHTNESS_OVERRIDE_FULL = 1.0f; field public static final float BRIGHTNESS_OVERRIDE_NONE = -1.0f; field public static final float BRIGHTNESS_OVERRIDE_OFF = 0.0f; - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.WindowManager.LayoutParams> CREATOR; field public static final int DIM_AMOUNT_CHANGED = 32; // 0x20 field public static final int FIRST_APPLICATION_WINDOW = 1; // 0x1 field public static final int FIRST_SUB_WINDOW = 1000; // 0x3e8 @@ -34521,6 +34928,7 @@ package android.view { field public static final int FLAG_HARDWARE_ACCELERATED = 16777216; // 0x1000000 field public static final int FLAG_IGNORE_CHEEK_PRESSES = 32768; // 0x8000 field public static final int FLAG_KEEP_SCREEN_ON = 128; // 0x80 + field public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 1073741824; // 0x40000000 field public static final int FLAG_LAYOUT_INSET_DECOR = 65536; // 0x10000 field public static final int FLAG_LAYOUT_IN_OVERSCAN = 33554432; // 0x2000000 field public static final int FLAG_LAYOUT_IN_SCREEN = 256; // 0x100 @@ -34570,6 +34978,7 @@ package android.view { field public static final int SOFT_INPUT_STATE_UNSPECIFIED = 0; // 0x0 field public static final int SOFT_INPUT_STATE_VISIBLE = 4; // 0x4 field public static final int TITLE_CHANGED = 64; // 0x40 + field public static final int TYPE_ACCESSIBILITY_OVERLAY = 2032; // 0x7f0 field public static final int TYPE_APPLICATION = 2; // 0x2 field public static final int TYPE_APPLICATION_ATTACHED_DIALOG = 1003; // 0x3eb field public static final int TYPE_APPLICATION_MEDIA = 1001; // 0x3e9 @@ -34649,7 +35058,7 @@ package android.view.accessibility { field public static final int CONTENT_CHANGE_TYPE_SUBTREE = 1; // 0x1 field public static final int CONTENT_CHANGE_TYPE_TEXT = 2; // 0x2 field public static final int CONTENT_CHANGE_TYPE_UNDEFINED = 0; // 0x0 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityEvent> CREATOR; field public static final int INVALID_POSITION = -1; // 0xffffffff field public static final deprecated int MAX_TEXT_LENGTH = 500; // 0x1f4 field public static final int TYPES_ALL_MASK = -1; // 0xffffffff @@ -34841,7 +35250,7 @@ package android.view.accessibility { field public static final int ACTION_SELECT = 4; // 0x4 field public static final int ACTION_SET_SELECTION = 131072; // 0x20000 field public static final int ACTION_SET_TEXT = 2097152; // 0x200000 - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityNodeInfo> CREATOR; field public static final int FOCUS_ACCESSIBILITY = 2; // 0x2 field public static final int FOCUS_INPUT = 1; // 0x1 field public static final int MOVEMENT_GRANULARITY_CHARACTER = 1; // 0x1 @@ -34988,7 +35397,8 @@ package android.view.accessibility { method public static android.view.accessibility.AccessibilityWindowInfo obtain(android.view.accessibility.AccessibilityWindowInfo); method public void recycle(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.accessibility.AccessibilityWindowInfo> CREATOR; + field public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; // 0x4 field public static final int TYPE_APPLICATION = 1; // 0x1 field public static final int TYPE_INPUT_METHOD = 2; // 0x2 field public static final int TYPE_SYSTEM = 3; // 0x3 @@ -35035,13 +35445,13 @@ package android.view.accessibility { package android.view.animation { - public class AccelerateDecelerateInterpolator implements android.view.animation.Interpolator { + public class AccelerateDecelerateInterpolator extends android.view.animation.BaseInterpolator { ctor public AccelerateDecelerateInterpolator(); ctor public AccelerateDecelerateInterpolator(android.content.Context, android.util.AttributeSet); method public float getInterpolation(float); } - public class AccelerateInterpolator implements android.view.animation.Interpolator { + public class AccelerateInterpolator extends android.view.animation.BaseInterpolator { ctor public AccelerateInterpolator(); ctor public AccelerateInterpolator(float); ctor public AccelerateInterpolator(android.content.Context, android.util.AttributeSet); @@ -35143,14 +35553,14 @@ package android.view.animation { method public static android.view.animation.Animation makeOutAnimation(android.content.Context, boolean); } - public class AnticipateInterpolator implements android.view.animation.Interpolator { + public class AnticipateInterpolator extends android.view.animation.BaseInterpolator { ctor public AnticipateInterpolator(); ctor public AnticipateInterpolator(float); ctor public AnticipateInterpolator(android.content.Context, android.util.AttributeSet); method public float getInterpolation(float); } - public class AnticipateOvershootInterpolator implements android.view.animation.Interpolator { + public class AnticipateOvershootInterpolator extends android.view.animation.BaseInterpolator { ctor public AnticipateOvershootInterpolator(); ctor public AnticipateOvershootInterpolator(float); ctor public AnticipateOvershootInterpolator(float, float); @@ -35158,19 +35568,23 @@ package android.view.animation { method public float getInterpolation(float); } - public class BounceInterpolator implements android.view.animation.Interpolator { + public abstract class BaseInterpolator implements android.view.animation.Interpolator { + ctor public BaseInterpolator(); + } + + public class BounceInterpolator extends android.view.animation.BaseInterpolator { ctor public BounceInterpolator(); ctor public BounceInterpolator(android.content.Context, android.util.AttributeSet); method public float getInterpolation(float); } - public class CycleInterpolator implements android.view.animation.Interpolator { + public class CycleInterpolator extends android.view.animation.BaseInterpolator { ctor public CycleInterpolator(float); ctor public CycleInterpolator(android.content.Context, android.util.AttributeSet); method public float getInterpolation(float); } - public class DecelerateInterpolator implements android.view.animation.Interpolator { + public class DecelerateInterpolator extends android.view.animation.BaseInterpolator { ctor public DecelerateInterpolator(); ctor public DecelerateInterpolator(float); ctor public DecelerateInterpolator(android.content.Context, android.util.AttributeSet); @@ -35245,20 +35659,20 @@ package android.view.animation { field public int index; } - public class LinearInterpolator implements android.view.animation.Interpolator { + public class LinearInterpolator extends android.view.animation.BaseInterpolator { ctor public LinearInterpolator(); ctor public LinearInterpolator(android.content.Context, android.util.AttributeSet); method public float getInterpolation(float); } - public class OvershootInterpolator implements android.view.animation.Interpolator { + public class OvershootInterpolator extends android.view.animation.BaseInterpolator { ctor public OvershootInterpolator(); ctor public OvershootInterpolator(float); ctor public OvershootInterpolator(android.content.Context, android.util.AttributeSet); method public float getInterpolation(float); } - public class PathInterpolator implements android.view.animation.Interpolator { + public class PathInterpolator extends android.view.animation.BaseInterpolator { ctor public PathInterpolator(android.graphics.Path); ctor public PathInterpolator(float, float); ctor public PathInterpolator(float, float, float, float); @@ -35350,7 +35764,7 @@ package android.view.inputmethod { method public int getPosition(); method public java.lang.CharSequence getText(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.CompletionInfo> CREATOR; } public final class CorrectionInfo implements android.os.Parcelable { @@ -35360,7 +35774,7 @@ package android.view.inputmethod { method public int getOffset(); method public java.lang.CharSequence getOldText(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.CorrectionInfo> CREATOR; } public final class CursorAnchorInfo implements android.os.Parcelable { @@ -35379,7 +35793,7 @@ package android.view.inputmethod { method public int getSelectionEnd(); method public int getSelectionStart(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.CursorAnchorInfo> CREATOR; field public static final int FLAG_HAS_INVISIBLE_REGION = 2; // 0x2 field public static final int FLAG_HAS_VISIBLE_REGION = 1; // 0x1 field public static final int FLAG_IS_RTL = 4; // 0x4 @@ -35402,7 +35816,7 @@ package android.view.inputmethod { method public void dump(android.util.Printer, java.lang.String); method public final void makeCompatible(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.EditorInfo> CREATOR; field public static final int IME_ACTION_DONE = 6; // 0x6 field public static final int IME_ACTION_GO = 2; // 0x2 field public static final int IME_ACTION_NEXT = 5; // 0x5 @@ -35440,7 +35854,7 @@ package android.view.inputmethod { ctor public ExtractedText(); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.ExtractedText> CREATOR; field public static final int FLAG_SELECTING = 2; // 0x2 field public static final int FLAG_SINGLE_LINE = 1; // 0x1 field public int flags; @@ -35456,7 +35870,7 @@ package android.view.inputmethod { ctor public ExtractedTextRequest(); method public int describeContents(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.ExtractedTextRequest> CREATOR; field public int flags; field public int hintMaxChars; field public int hintMaxLines; @@ -35472,7 +35886,7 @@ package android.view.inputmethod { method public int getPid(); method public int getUid(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputBinding> CREATOR; } public abstract interface InputConnection { @@ -35570,7 +35984,7 @@ package android.view.inputmethod { method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodInfo> CREATOR; } public final class InputMethodManager { @@ -35657,7 +36071,7 @@ package android.view.inputmethod { method public boolean isAuxiliary(); method public boolean overridesImplicitlyEnabledSubtype(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.inputmethod.InputMethodSubtype> CREATOR; } public static class InputMethodSubtype.InputMethodSubtypeBuilder { @@ -35687,7 +36101,7 @@ package android.view.textservice { method public int getSuggestionsCount(); method public android.view.textservice.SuggestionsInfo getSuggestionsInfoAt(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.textservice.SentenceSuggestionsInfo> CREATOR; } public final class SpellCheckerInfo implements android.os.Parcelable { @@ -35702,7 +36116,7 @@ package android.view.textservice { method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager); method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.textservice.SpellCheckerInfo> CREATOR; } public class SpellCheckerSession { @@ -35731,7 +36145,7 @@ package android.view.textservice { method public java.lang.String getLocale(); method public int getNameResId(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.textservice.SpellCheckerSubtype> CREATOR; } public final class SuggestionsInfo implements android.os.Parcelable { @@ -35746,7 +36160,7 @@ package android.view.textservice { method public int getSuggestionsCount(); method public void setCookieAndSequence(int, int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.textservice.SuggestionsInfo> CREATOR; field public static final int RESULT_ATTR_HAS_RECOMMENDED_SUGGESTIONS = 4; // 0x4 field public static final int RESULT_ATTR_IN_THE_DICTIONARY = 1; // 0x1 field public static final int RESULT_ATTR_LOOKS_LIKE_TYPO = 2; // 0x2 @@ -35763,7 +36177,7 @@ package android.view.textservice { method public int getSequence(); method public java.lang.String getText(); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.view.textservice.TextInfo> CREATOR; } public final class TextServicesManager { @@ -37743,6 +38157,7 @@ package android.widget { public class PopupMenu { ctor public PopupMenu(android.content.Context, android.view.View); ctor public PopupMenu(android.content.Context, android.view.View, int); + ctor public PopupMenu(android.content.Context, android.view.View, int, int, int); method public void dismiss(); method public android.view.View.OnTouchListener getDragToOpenListener(); method public android.view.Menu getMenu(); @@ -37783,6 +38198,7 @@ package android.widget { method public int getSoftInputMode(); method public int getWidth(); method public boolean isAboveAnchor(); + method public boolean isAttachedInDecor(); method public boolean isClippingEnabled(); method public boolean isFocusable(); method public boolean isOutsideTouchable(); @@ -37790,6 +38206,7 @@ package android.widget { method public boolean isSplitTouchEnabled(); method public boolean isTouchable(); method public void setAnimationStyle(int); + method public void setAttachedInDecor(boolean); method public void setBackgroundDrawable(android.graphics.drawable.Drawable); method public void setClippingEnabled(boolean); method public void setContentView(android.view.View); @@ -38039,7 +38456,7 @@ package android.widget { method public void showNext(int); method public void showPrevious(int); method public void writeToParcel(android.os.Parcel, int); - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.widget.RemoteViews> CREATOR; } public static class RemoteViews.ActionException extends java.lang.RuntimeException { @@ -38737,7 +39154,7 @@ package android.widget { } public static class TextView.SavedState extends android.view.View.BaseSavedState { - field public static final android.os.Parcelable.Creator CREATOR; + field public static final android.os.Parcelable.Creator<android.widget.TextView.SavedState> CREATOR; } public class TimePicker extends android.widget.FrameLayout { @@ -40463,7 +40880,7 @@ package java.lang { method public static java.lang.Boolean valueOf(boolean); field public static final java.lang.Boolean FALSE; field public static final java.lang.Boolean TRUE; - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Boolean> TYPE; } public final class Byte extends java.lang.Number implements java.lang.Comparable { @@ -40485,7 +40902,7 @@ package java.lang { field public static final byte MAX_VALUE = 127; // 0x7f field public static final byte MIN_VALUE = -128; // 0xffffff80 field public static final int SIZE = 8; // 0x8 - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Byte> TYPE; } public abstract interface CharSequence { @@ -40641,7 +41058,7 @@ package java.lang { field public static final byte START_PUNCTUATION = 21; // 0x15 field public static final byte SURROGATE = 19; // 0x13 field public static final byte TITLECASE_LETTER = 3; // 0x3 - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Character> TYPE; field public static final byte UNASSIGNED = 0; // 0x0 field public static final byte UPPERCASE_LETTER = 1; // 0x1 } @@ -41037,7 +41454,7 @@ package java.lang { field public static final double NaN = (0.0/0.0); field public static final double POSITIVE_INFINITY = (1.0/0.0); field public static final int SIZE = 64; // 0x40 - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Double> TYPE; } public abstract class Enum implements java.lang.Comparable java.io.Serializable { @@ -41111,7 +41528,7 @@ package java.lang { field public static final float NaN = (0.0f/0.0f); field public static final float POSITIVE_INFINITY = (1.0f/0.0f); field public static final int SIZE = 32; // 0x20 - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Float> TYPE; } public class IllegalAccessError extends java.lang.IncompatibleClassChangeError { @@ -41209,7 +41626,7 @@ package java.lang { field public static final int MAX_VALUE = 2147483647; // 0x7fffffff field public static final int MIN_VALUE = -2147483648; // 0x80000000 field public static final int SIZE = 32; // 0x20 - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Integer> TYPE; } public class InternalError extends java.lang.VirtualMachineError { @@ -41268,7 +41685,7 @@ package java.lang { field public static final long MAX_VALUE = 9223372036854775807L; // 0x7fffffffffffffffL field public static final long MIN_VALUE = -9223372036854775808L; // 0x8000000000000000L field public static final int SIZE = 64; // 0x40 - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Long> TYPE; } public final class Math { @@ -41576,7 +41993,7 @@ package java.lang { field public static final short MAX_VALUE = 32767; // 0x7fff field public static final short MIN_VALUE = -32768; // 0xffff8000 field public static final int SIZE = 16; // 0x10 - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Short> TYPE; } public class StackOverflowError extends java.lang.VirtualMachineError { @@ -41730,7 +42147,7 @@ package java.lang { method public static java.lang.String valueOf(long); method public static java.lang.String valueOf(java.lang.Object); method public static java.lang.String valueOf(boolean); - field public static final java.util.Comparator CASE_INSENSITIVE_ORDER; + field public static final java.util.Comparator<java.lang.String> CASE_INSENSITIVE_ORDER; } public final class StringBuffer extends java.lang.AbstractStringBuilder implements java.lang.Appendable java.lang.CharSequence java.io.Serializable { @@ -42017,7 +42434,7 @@ package java.lang { } public final class Void { - field public static final java.lang.Class TYPE; + field public static final java.lang.Class<java.lang.Void> TYPE; } } @@ -48502,9 +48919,9 @@ package java.util { method public java.util.ResourceBundle newBundle(java.lang.String, java.util.Locale, java.lang.String, java.lang.ClassLoader, boolean) throws java.io.IOException, java.lang.IllegalAccessException, java.lang.InstantiationException; method public java.lang.String toBundleName(java.lang.String, java.util.Locale); method public final java.lang.String toResourceName(java.lang.String, java.lang.String); - field public static final java.util.List FORMAT_CLASS; - field public static final java.util.List FORMAT_DEFAULT; - field public static final java.util.List FORMAT_PROPERTIES; + field public static final java.util.List<java.lang.String> FORMAT_CLASS; + field public static final java.util.List<java.lang.String> FORMAT_DEFAULT; + field public static final java.util.List<java.lang.String> FORMAT_PROPERTIES; field public static final long TTL_DONT_CACHE = -1L; // 0xffffffffffffffffL field public static final long TTL_NO_EXPIRATION_CONTROL = -2L; // 0xfffffffffffffffeL } @@ -50094,7 +50511,7 @@ package java.util.jar { method public java.lang.Object remove(java.lang.Object); method public int size(); method public java.util.Collection<java.lang.Object> values(); - field protected java.util.Map map; + field protected java.util.Map<java.lang.Object, java.lang.Object> map; } public static class Attributes.Name { @@ -53915,9 +54332,9 @@ package junit.framework { method public void startTest(junit.framework.Test); method public synchronized void stop(); method public synchronized boolean wasSuccessful(); - field protected java.util.Vector fErrors; - field protected java.util.Vector fFailures; - field protected java.util.Vector fListeners; + field protected java.util.Vector<junit.framework.TestFailure> fErrors; + field protected java.util.Vector<junit.framework.TestFailure> fFailures; + field protected java.util.Vector<junit.framework.TestListener> fListeners; field protected int fRunTests; } @@ -53993,7 +54410,7 @@ package junit.runner { package org.apache.commons.logging { - public abstract interface Log { + public abstract deprecated interface Log { method public abstract void debug(java.lang.Object); method public abstract void debug(java.lang.Object, java.lang.Throwable); method public abstract void error(java.lang.Object); @@ -54018,26 +54435,26 @@ package org.apache.commons.logging { package org.apache.http { - public class ConnectionClosedException extends java.io.IOException { + public deprecated class ConnectionClosedException extends java.io.IOException { ctor public ConnectionClosedException(java.lang.String); } - public abstract interface ConnectionReuseStrategy { + public abstract deprecated interface ConnectionReuseStrategy { method public abstract boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public abstract interface FormattedHeader implements org.apache.http.Header { + public abstract deprecated interface FormattedHeader implements org.apache.http.Header { method public abstract org.apache.http.util.CharArrayBuffer getBuffer(); method public abstract int getValuePos(); } - public abstract interface Header { + public abstract deprecated interface Header { method public abstract org.apache.http.HeaderElement[] getElements() throws org.apache.http.ParseException; method public abstract java.lang.String getName(); method public abstract java.lang.String getValue(); } - public abstract interface HeaderElement { + public abstract deprecated interface HeaderElement { method public abstract java.lang.String getName(); method public abstract org.apache.http.NameValuePair getParameter(int); method public abstract org.apache.http.NameValuePair getParameterByName(java.lang.String); @@ -54046,17 +54463,17 @@ package org.apache.http { method public abstract java.lang.String getValue(); } - public abstract interface HeaderElementIterator implements java.util.Iterator { + public abstract deprecated interface HeaderElementIterator implements java.util.Iterator { method public abstract boolean hasNext(); method public abstract org.apache.http.HeaderElement nextElement(); } - public abstract interface HeaderIterator implements java.util.Iterator { + public abstract deprecated interface HeaderIterator implements java.util.Iterator { method public abstract boolean hasNext(); method public abstract org.apache.http.Header nextHeader(); } - public abstract interface HttpClientConnection implements org.apache.http.HttpConnection { + public abstract deprecated interface HttpClientConnection implements org.apache.http.HttpConnection { method public abstract void flush() throws java.io.IOException; method public abstract boolean isResponseAvailable(int) throws java.io.IOException; method public abstract void receiveResponseEntity(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException; @@ -54065,7 +54482,7 @@ package org.apache.http { method public abstract void sendRequestHeader(org.apache.http.HttpRequest) throws org.apache.http.HttpException, java.io.IOException; } - public abstract interface HttpConnection { + public abstract deprecated interface HttpConnection { method public abstract void close() throws java.io.IOException; method public abstract org.apache.http.HttpConnectionMetrics getMetrics(); method public abstract int getSocketTimeout(); @@ -54075,7 +54492,7 @@ package org.apache.http { method public abstract void shutdown() throws java.io.IOException; } - public abstract interface HttpConnectionMetrics { + public abstract deprecated interface HttpConnectionMetrics { method public abstract java.lang.Object getMetric(java.lang.String); method public abstract long getReceivedBytesCount(); method public abstract long getRequestCount(); @@ -54084,7 +54501,7 @@ package org.apache.http { method public abstract void reset(); } - public abstract interface HttpEntity { + public abstract deprecated interface HttpEntity { method public abstract void consumeContent() throws java.io.IOException; method public abstract java.io.InputStream getContent() throws java.io.IOException, java.lang.IllegalStateException; method public abstract org.apache.http.Header getContentEncoding(); @@ -54096,19 +54513,19 @@ package org.apache.http { method public abstract void writeTo(java.io.OutputStream) throws java.io.IOException; } - public abstract interface HttpEntityEnclosingRequest implements org.apache.http.HttpRequest { + public abstract deprecated interface HttpEntityEnclosingRequest implements org.apache.http.HttpRequest { method public abstract boolean expectContinue(); method public abstract org.apache.http.HttpEntity getEntity(); method public abstract void setEntity(org.apache.http.HttpEntity); } - public class HttpException extends java.lang.Exception { + public deprecated class HttpException extends java.lang.Exception { ctor public HttpException(); ctor public HttpException(java.lang.String); ctor public HttpException(java.lang.String, java.lang.Throwable); } - public final class HttpHost implements java.lang.Cloneable { + public final deprecated class HttpHost implements java.lang.Cloneable { ctor public HttpHost(java.lang.String, int, java.lang.String); ctor public HttpHost(java.lang.String, int); ctor public HttpHost(java.lang.String); @@ -54126,14 +54543,14 @@ package org.apache.http { field protected final java.lang.String schemeName; } - public abstract interface HttpInetConnection implements org.apache.http.HttpConnection { + public abstract deprecated interface HttpInetConnection implements org.apache.http.HttpConnection { method public abstract java.net.InetAddress getLocalAddress(); method public abstract int getLocalPort(); method public abstract java.net.InetAddress getRemoteAddress(); method public abstract int getRemotePort(); } - public abstract interface HttpMessage { + public abstract deprecated interface HttpMessage { method public abstract void addHeader(org.apache.http.Header); method public abstract void addHeader(java.lang.String, java.lang.String); method public abstract boolean containsHeader(java.lang.String); @@ -54153,20 +54570,20 @@ package org.apache.http { method public abstract void setParams(org.apache.http.params.HttpParams); } - public abstract interface HttpRequest implements org.apache.http.HttpMessage { + public abstract deprecated interface HttpRequest implements org.apache.http.HttpMessage { method public abstract org.apache.http.RequestLine getRequestLine(); } - public abstract interface HttpRequestFactory { + public abstract deprecated interface HttpRequestFactory { method public abstract org.apache.http.HttpRequest newHttpRequest(org.apache.http.RequestLine) throws org.apache.http.MethodNotSupportedException; method public abstract org.apache.http.HttpRequest newHttpRequest(java.lang.String, java.lang.String) throws org.apache.http.MethodNotSupportedException; } - public abstract interface HttpRequestInterceptor { + public abstract deprecated interface HttpRequestInterceptor { method public abstract void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public abstract interface HttpResponse implements org.apache.http.HttpMessage { + public abstract deprecated interface HttpResponse implements org.apache.http.HttpMessage { method public abstract org.apache.http.HttpEntity getEntity(); method public abstract java.util.Locale getLocale(); method public abstract org.apache.http.StatusLine getStatusLine(); @@ -54179,16 +54596,16 @@ package org.apache.http { method public abstract void setStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String); } - public abstract interface HttpResponseFactory { + public abstract deprecated interface HttpResponseFactory { method public abstract org.apache.http.HttpResponse newHttpResponse(org.apache.http.ProtocolVersion, int, org.apache.http.protocol.HttpContext); method public abstract org.apache.http.HttpResponse newHttpResponse(org.apache.http.StatusLine, org.apache.http.protocol.HttpContext); } - public abstract interface HttpResponseInterceptor { + public abstract deprecated interface HttpResponseInterceptor { method public abstract void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public abstract interface HttpServerConnection implements org.apache.http.HttpConnection { + public abstract deprecated interface HttpServerConnection implements org.apache.http.HttpConnection { method public abstract void flush() throws java.io.IOException; method public abstract void receiveRequestEntity(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.HttpException, java.io.IOException; method public abstract org.apache.http.HttpRequest receiveRequestHeader() throws org.apache.http.HttpException, java.io.IOException; @@ -54196,7 +54613,7 @@ package org.apache.http { method public abstract void sendResponseHeader(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException; } - public abstract interface HttpStatus { + public abstract deprecated interface HttpStatus { field public static final int SC_ACCEPTED = 202; // 0xca field public static final int SC_BAD_GATEWAY = 502; // 0x1f6 field public static final int SC_BAD_REQUEST = 400; // 0x190 @@ -54247,7 +54664,7 @@ package org.apache.http { field public static final int SC_USE_PROXY = 305; // 0x131 } - public final class HttpVersion extends org.apache.http.ProtocolVersion implements java.io.Serializable { + public final deprecated class HttpVersion extends org.apache.http.ProtocolVersion implements java.io.Serializable { ctor public HttpVersion(int, int); field public static final java.lang.String HTTP = "HTTP"; field public static final org.apache.http.HttpVersion HTTP_0_9; @@ -54255,37 +54672,37 @@ package org.apache.http { field public static final org.apache.http.HttpVersion HTTP_1_1; } - public class MalformedChunkCodingException extends java.io.IOException { + public deprecated class MalformedChunkCodingException extends java.io.IOException { ctor public MalformedChunkCodingException(); ctor public MalformedChunkCodingException(java.lang.String); } - public class MethodNotSupportedException extends org.apache.http.HttpException { + public deprecated class MethodNotSupportedException extends org.apache.http.HttpException { ctor public MethodNotSupportedException(java.lang.String); ctor public MethodNotSupportedException(java.lang.String, java.lang.Throwable); } - public abstract interface NameValuePair { + public abstract deprecated interface NameValuePair { method public abstract java.lang.String getName(); method public abstract java.lang.String getValue(); } - public class NoHttpResponseException extends java.io.IOException { + public deprecated class NoHttpResponseException extends java.io.IOException { ctor public NoHttpResponseException(java.lang.String); } - public class ParseException extends java.lang.RuntimeException { + public deprecated class ParseException extends java.lang.RuntimeException { ctor public ParseException(); ctor public ParseException(java.lang.String); } - public class ProtocolException extends org.apache.http.HttpException { + public deprecated class ProtocolException extends org.apache.http.HttpException { ctor public ProtocolException(); ctor public ProtocolException(java.lang.String); ctor public ProtocolException(java.lang.String, java.lang.Throwable); } - public class ProtocolVersion implements java.lang.Cloneable java.io.Serializable { + public deprecated class ProtocolVersion implements java.lang.Cloneable java.io.Serializable { ctor public ProtocolVersion(java.lang.String, int, int); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public int compareToVersion(org.apache.http.ProtocolVersion); @@ -54303,28 +54720,28 @@ package org.apache.http { field protected final java.lang.String protocol; } - public abstract interface ReasonPhraseCatalog { + public abstract deprecated interface ReasonPhraseCatalog { method public abstract java.lang.String getReason(int, java.util.Locale); } - public abstract interface RequestLine { + public abstract deprecated interface RequestLine { method public abstract java.lang.String getMethod(); method public abstract org.apache.http.ProtocolVersion getProtocolVersion(); method public abstract java.lang.String getUri(); } - public abstract interface StatusLine { + public abstract deprecated interface StatusLine { method public abstract org.apache.http.ProtocolVersion getProtocolVersion(); method public abstract java.lang.String getReasonPhrase(); method public abstract int getStatusCode(); } - public abstract interface TokenIterator implements java.util.Iterator { + public abstract deprecated interface TokenIterator implements java.util.Iterator { method public abstract boolean hasNext(); method public abstract java.lang.String nextToken(); } - public class UnsupportedHttpVersionException extends org.apache.http.ProtocolException { + public deprecated class UnsupportedHttpVersionException extends org.apache.http.ProtocolException { ctor public UnsupportedHttpVersionException(); ctor public UnsupportedHttpVersionException(java.lang.String); } @@ -54333,14 +54750,14 @@ package org.apache.http { package org.apache.http.auth { - public final class AUTH { + public final deprecated class AUTH { field public static final java.lang.String PROXY_AUTH = "Proxy-Authenticate"; field public static final java.lang.String PROXY_AUTH_RESP = "Proxy-Authorization"; field public static final java.lang.String WWW_AUTH = "WWW-Authenticate"; field public static final java.lang.String WWW_AUTH_RESP = "Authorization"; } - public abstract interface AuthScheme { + public abstract deprecated interface AuthScheme { method public abstract org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException; method public abstract java.lang.String getParameter(java.lang.String); method public abstract java.lang.String getRealm(); @@ -54350,11 +54767,11 @@ package org.apache.http.auth { method public abstract void processChallenge(org.apache.http.Header) throws org.apache.http.auth.MalformedChallengeException; } - public abstract interface AuthSchemeFactory { + public abstract deprecated interface AuthSchemeFactory { method public abstract org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams); } - public final class AuthSchemeRegistry { + public final deprecated class AuthSchemeRegistry { ctor public AuthSchemeRegistry(); method public synchronized org.apache.http.auth.AuthScheme getAuthScheme(java.lang.String, org.apache.http.params.HttpParams) throws java.lang.IllegalStateException; method public synchronized java.util.List<java.lang.String> getSchemeNames(); @@ -54363,7 +54780,7 @@ package org.apache.http.auth { method public synchronized void unregister(java.lang.String); } - public class AuthScope { + public deprecated class AuthScope { ctor public AuthScope(java.lang.String, int, java.lang.String, java.lang.String); ctor public AuthScope(java.lang.String, int, java.lang.String); ctor public AuthScope(java.lang.String, int); @@ -54380,7 +54797,7 @@ package org.apache.http.auth { field public static final java.lang.String ANY_SCHEME; } - public class AuthState { + public deprecated class AuthState { ctor public AuthState(); method public org.apache.http.auth.AuthScheme getAuthScheme(); method public org.apache.http.auth.AuthScope getAuthScope(); @@ -54392,35 +54809,35 @@ package org.apache.http.auth { method public void setCredentials(org.apache.http.auth.Credentials); } - public class AuthenticationException extends org.apache.http.ProtocolException { + public deprecated class AuthenticationException extends org.apache.http.ProtocolException { ctor public AuthenticationException(); ctor public AuthenticationException(java.lang.String); ctor public AuthenticationException(java.lang.String, java.lang.Throwable); } - public final class BasicUserPrincipal implements java.security.Principal { + public final deprecated class BasicUserPrincipal implements java.security.Principal { ctor public BasicUserPrincipal(java.lang.String); method public java.lang.String getName(); } - public abstract interface Credentials { + public abstract deprecated interface Credentials { method public abstract java.lang.String getPassword(); method public abstract java.security.Principal getUserPrincipal(); } - public class InvalidCredentialsException extends org.apache.http.auth.AuthenticationException { + public deprecated class InvalidCredentialsException extends org.apache.http.auth.AuthenticationException { ctor public InvalidCredentialsException(); ctor public InvalidCredentialsException(java.lang.String); ctor public InvalidCredentialsException(java.lang.String, java.lang.Throwable); } - public class MalformedChallengeException extends org.apache.http.ProtocolException { + public deprecated class MalformedChallengeException extends org.apache.http.ProtocolException { ctor public MalformedChallengeException(); ctor public MalformedChallengeException(java.lang.String); ctor public MalformedChallengeException(java.lang.String, java.lang.Throwable); } - public class NTCredentials implements org.apache.http.auth.Credentials { + public deprecated class NTCredentials implements org.apache.http.auth.Credentials { ctor public NTCredentials(java.lang.String); ctor public NTCredentials(java.lang.String, java.lang.String, java.lang.String, java.lang.String); method public java.lang.String getDomain(); @@ -54430,14 +54847,14 @@ package org.apache.http.auth { method public java.lang.String getWorkstation(); } - public class NTUserPrincipal implements java.security.Principal { + public deprecated class NTUserPrincipal implements java.security.Principal { ctor public NTUserPrincipal(java.lang.String, java.lang.String); method public java.lang.String getDomain(); method public java.lang.String getName(); method public java.lang.String getUsername(); } - public class UsernamePasswordCredentials implements org.apache.http.auth.Credentials { + public deprecated class UsernamePasswordCredentials implements org.apache.http.auth.Credentials { ctor public UsernamePasswordCredentials(java.lang.String); ctor public UsernamePasswordCredentials(java.lang.String, java.lang.String); method public java.lang.String getPassword(); @@ -54449,16 +54866,16 @@ package org.apache.http.auth { package org.apache.http.auth.params { - public abstract interface AuthPNames { + public abstract deprecated interface AuthPNames { field public static final java.lang.String CREDENTIAL_CHARSET = "http.auth.credential-charset"; } - public class AuthParamBean extends org.apache.http.params.HttpAbstractParamBean { + public deprecated class AuthParamBean extends org.apache.http.params.HttpAbstractParamBean { ctor public AuthParamBean(org.apache.http.params.HttpParams); method public void setCredentialCharset(java.lang.String); } - public final class AuthParams { + public final deprecated class AuthParams { method public static java.lang.String getCredentialCharset(org.apache.http.params.HttpParams); method public static void setCredentialCharset(org.apache.http.params.HttpParams, java.lang.String); } @@ -54467,39 +54884,39 @@ package org.apache.http.auth.params { package org.apache.http.client { - public abstract interface AuthenticationHandler { + public abstract deprecated interface AuthenticationHandler { method public abstract java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException; method public abstract boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); method public abstract org.apache.http.auth.AuthScheme selectScheme(java.util.Map<java.lang.String, org.apache.http.Header>, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.AuthenticationException; } - public class CircularRedirectException extends org.apache.http.client.RedirectException { + public deprecated class CircularRedirectException extends org.apache.http.client.RedirectException { ctor public CircularRedirectException(); ctor public CircularRedirectException(java.lang.String); ctor public CircularRedirectException(java.lang.String, java.lang.Throwable); } - public class ClientProtocolException extends java.io.IOException { + public deprecated class ClientProtocolException extends java.io.IOException { ctor public ClientProtocolException(); ctor public ClientProtocolException(java.lang.String); ctor public ClientProtocolException(java.lang.Throwable); ctor public ClientProtocolException(java.lang.String, java.lang.Throwable); } - public abstract interface CookieStore { + public abstract deprecated interface CookieStore { method public abstract void addCookie(org.apache.http.cookie.Cookie); method public abstract void clear(); method public abstract boolean clearExpired(java.util.Date); method public abstract java.util.List<org.apache.http.cookie.Cookie> getCookies(); } - public abstract interface CredentialsProvider { + public abstract deprecated interface CredentialsProvider { method public abstract void clear(); method public abstract org.apache.http.auth.Credentials getCredentials(org.apache.http.auth.AuthScope); method public abstract void setCredentials(org.apache.http.auth.AuthScope, org.apache.http.auth.Credentials); } - public abstract interface HttpClient { + public abstract deprecated interface HttpClient { method public abstract org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException; method public abstract org.apache.http.HttpResponse execute(org.apache.http.client.methods.HttpUriRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.client.ClientProtocolException, java.io.IOException; method public abstract org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest) throws org.apache.http.client.ClientProtocolException, java.io.IOException; @@ -54512,40 +54929,40 @@ package org.apache.http.client { method public abstract org.apache.http.params.HttpParams getParams(); } - public abstract interface HttpRequestRetryHandler { + public abstract deprecated interface HttpRequestRetryHandler { method public abstract boolean retryRequest(java.io.IOException, int, org.apache.http.protocol.HttpContext); } - public class HttpResponseException extends org.apache.http.client.ClientProtocolException { + public deprecated class HttpResponseException extends org.apache.http.client.ClientProtocolException { ctor public HttpResponseException(int, java.lang.String); method public int getStatusCode(); } - public class NonRepeatableRequestException extends org.apache.http.ProtocolException { + public deprecated class NonRepeatableRequestException extends org.apache.http.ProtocolException { ctor public NonRepeatableRequestException(); ctor public NonRepeatableRequestException(java.lang.String); } - public class RedirectException extends org.apache.http.ProtocolException { + public deprecated class RedirectException extends org.apache.http.ProtocolException { ctor public RedirectException(); ctor public RedirectException(java.lang.String); ctor public RedirectException(java.lang.String, java.lang.Throwable); } - public abstract interface RedirectHandler { + public abstract deprecated interface RedirectHandler { method public abstract java.net.URI getLocationURI(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.ProtocolException; method public abstract boolean isRedirectRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public abstract interface RequestDirector { + public abstract deprecated interface RequestDirector { method public abstract org.apache.http.HttpResponse execute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public abstract interface ResponseHandler { + public abstract deprecated interface ResponseHandler { method public abstract T handleResponse(org.apache.http.HttpResponse) throws org.apache.http.client.ClientProtocolException, java.io.IOException; } - public abstract interface UserTokenHandler { + public abstract deprecated interface UserTokenHandler { method public abstract java.lang.Object getUserToken(org.apache.http.protocol.HttpContext); } @@ -54553,7 +54970,7 @@ package org.apache.http.client { package org.apache.http.client.entity { - public class UrlEncodedFormEntity extends org.apache.http.entity.StringEntity { + public deprecated class UrlEncodedFormEntity extends org.apache.http.entity.StringEntity { ctor public UrlEncodedFormEntity(java.util.List<? extends org.apache.http.NameValuePair>, java.lang.String) throws java.io.UnsupportedEncodingException; ctor public UrlEncodedFormEntity(java.util.List<? extends org.apache.http.NameValuePair>) throws java.io.UnsupportedEncodingException; } @@ -54562,13 +54979,13 @@ package org.apache.http.client.entity { package org.apache.http.client.methods { - public abstract interface AbortableHttpRequest { + public abstract deprecated interface AbortableHttpRequest { method public abstract void abort(); method public abstract void setConnectionRequest(org.apache.http.conn.ClientConnectionRequest) throws java.io.IOException; method public abstract void setReleaseTrigger(org.apache.http.conn.ConnectionReleaseTrigger) throws java.io.IOException; } - public class HttpDelete extends org.apache.http.client.methods.HttpRequestBase { + public deprecated class HttpDelete extends org.apache.http.client.methods.HttpRequestBase { ctor public HttpDelete(); ctor public HttpDelete(java.net.URI); ctor public HttpDelete(java.lang.String); @@ -54576,14 +54993,14 @@ package org.apache.http.client.methods { field public static final java.lang.String METHOD_NAME = "DELETE"; } - public abstract class HttpEntityEnclosingRequestBase extends org.apache.http.client.methods.HttpRequestBase implements org.apache.http.HttpEntityEnclosingRequest { + public abstract deprecated class HttpEntityEnclosingRequestBase extends org.apache.http.client.methods.HttpRequestBase implements org.apache.http.HttpEntityEnclosingRequest { ctor public HttpEntityEnclosingRequestBase(); method public boolean expectContinue(); method public org.apache.http.HttpEntity getEntity(); method public void setEntity(org.apache.http.HttpEntity); } - public class HttpGet extends org.apache.http.client.methods.HttpRequestBase { + public deprecated class HttpGet extends org.apache.http.client.methods.HttpRequestBase { ctor public HttpGet(); ctor public HttpGet(java.net.URI); ctor public HttpGet(java.lang.String); @@ -54591,7 +55008,7 @@ package org.apache.http.client.methods { field public static final java.lang.String METHOD_NAME = "GET"; } - public class HttpHead extends org.apache.http.client.methods.HttpRequestBase { + public deprecated class HttpHead extends org.apache.http.client.methods.HttpRequestBase { ctor public HttpHead(); ctor public HttpHead(java.net.URI); ctor public HttpHead(java.lang.String); @@ -54599,7 +55016,7 @@ package org.apache.http.client.methods { field public static final java.lang.String METHOD_NAME = "HEAD"; } - public class HttpOptions extends org.apache.http.client.methods.HttpRequestBase { + public deprecated class HttpOptions extends org.apache.http.client.methods.HttpRequestBase { ctor public HttpOptions(); ctor public HttpOptions(java.net.URI); ctor public HttpOptions(java.lang.String); @@ -54608,7 +55025,7 @@ package org.apache.http.client.methods { field public static final java.lang.String METHOD_NAME = "OPTIONS"; } - public class HttpPost extends org.apache.http.client.methods.HttpEntityEnclosingRequestBase { + public deprecated class HttpPost extends org.apache.http.client.methods.HttpEntityEnclosingRequestBase { ctor public HttpPost(); ctor public HttpPost(java.net.URI); ctor public HttpPost(java.lang.String); @@ -54616,7 +55033,7 @@ package org.apache.http.client.methods { field public static final java.lang.String METHOD_NAME = "POST"; } - public class HttpPut extends org.apache.http.client.methods.HttpEntityEnclosingRequestBase { + public deprecated class HttpPut extends org.apache.http.client.methods.HttpEntityEnclosingRequestBase { ctor public HttpPut(); ctor public HttpPut(java.net.URI); ctor public HttpPut(java.lang.String); @@ -54624,7 +55041,7 @@ package org.apache.http.client.methods { field public static final java.lang.String METHOD_NAME = "PUT"; } - public abstract class HttpRequestBase extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.client.methods.AbortableHttpRequest java.lang.Cloneable org.apache.http.client.methods.HttpUriRequest { + public abstract deprecated class HttpRequestBase extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.client.methods.AbortableHttpRequest java.lang.Cloneable org.apache.http.client.methods.HttpUriRequest { ctor public HttpRequestBase(); method public void abort(); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; @@ -54638,7 +55055,7 @@ package org.apache.http.client.methods { method public void setURI(java.net.URI); } - public class HttpTrace extends org.apache.http.client.methods.HttpRequestBase { + public deprecated class HttpTrace extends org.apache.http.client.methods.HttpRequestBase { ctor public HttpTrace(); ctor public HttpTrace(java.net.URI); ctor public HttpTrace(java.lang.String); @@ -54646,7 +55063,7 @@ package org.apache.http.client.methods { field public static final java.lang.String METHOD_NAME = "TRACE"; } - public abstract interface HttpUriRequest implements org.apache.http.HttpRequest { + public abstract deprecated interface HttpUriRequest implements org.apache.http.HttpRequest { method public abstract void abort() throws java.lang.UnsupportedOperationException; method public abstract java.lang.String getMethod(); method public abstract java.net.URI getURI(); @@ -54657,16 +55074,16 @@ package org.apache.http.client.methods { package org.apache.http.client.params { - public abstract interface AllClientPNames implements org.apache.http.auth.params.AuthPNames org.apache.http.client.params.ClientPNames org.apache.http.conn.params.ConnConnectionPNames org.apache.http.conn.params.ConnManagerPNames org.apache.http.conn.params.ConnRoutePNames org.apache.http.cookie.params.CookieSpecPNames org.apache.http.params.CoreConnectionPNames org.apache.http.params.CoreProtocolPNames { + public abstract deprecated interface AllClientPNames implements org.apache.http.auth.params.AuthPNames org.apache.http.client.params.ClientPNames org.apache.http.conn.params.ConnConnectionPNames org.apache.http.conn.params.ConnManagerPNames org.apache.http.conn.params.ConnRoutePNames org.apache.http.cookie.params.CookieSpecPNames org.apache.http.params.CoreConnectionPNames org.apache.http.params.CoreProtocolPNames { } - public final class AuthPolicy { + public final deprecated class AuthPolicy { field public static final java.lang.String BASIC = "Basic"; field public static final java.lang.String DIGEST = "Digest"; field public static final java.lang.String NTLM = "NTLM"; } - public abstract interface ClientPNames { + public abstract deprecated interface ClientPNames { field public static final java.lang.String ALLOW_CIRCULAR_REDIRECTS = "http.protocol.allow-circular-redirects"; field public static final java.lang.String CONNECTION_MANAGER_FACTORY = "http.connection-manager.factory-object"; field public static final java.lang.String CONNECTION_MANAGER_FACTORY_CLASS_NAME = "http.connection-manager.factory-class-name"; @@ -54680,7 +55097,7 @@ package org.apache.http.client.params { field public static final java.lang.String VIRTUAL_HOST = "http.virtual-host"; } - public class ClientParamBean extends org.apache.http.params.HttpAbstractParamBean { + public deprecated class ClientParamBean extends org.apache.http.params.HttpAbstractParamBean { ctor public ClientParamBean(org.apache.http.params.HttpParams); method public void setAllowCircularRedirects(boolean); method public void setConnectionManagerFactory(org.apache.http.conn.ClientConnectionManagerFactory); @@ -54695,7 +55112,7 @@ package org.apache.http.client.params { method public void setVirtualHost(org.apache.http.HttpHost); } - public final class CookiePolicy { + public final deprecated class CookiePolicy { field public static final java.lang.String BEST_MATCH = "best-match"; field public static final java.lang.String BROWSER_COMPATIBILITY = "compatibility"; field public static final java.lang.String NETSCAPE = "netscape"; @@ -54703,7 +55120,7 @@ package org.apache.http.client.params { field public static final java.lang.String RFC_2965 = "rfc2965"; } - public class HttpClientParams { + public deprecated class HttpClientParams { method public static java.lang.String getCookiePolicy(org.apache.http.params.HttpParams); method public static boolean isAuthenticating(org.apache.http.params.HttpParams); method public static boolean isRedirecting(org.apache.http.params.HttpParams); @@ -54716,7 +55133,7 @@ package org.apache.http.client.params { package org.apache.http.client.protocol { - public abstract interface ClientContext { + public abstract deprecated interface ClientContext { field public static final java.lang.String AUTHSCHEME_REGISTRY = "http.authscheme-registry"; field public static final java.lang.String AUTH_SCHEME_PREF = "http.auth.scheme-pref"; field public static final java.lang.String COOKIESPEC_REGISTRY = "http.cookiespec-registry"; @@ -54729,7 +55146,7 @@ package org.apache.http.client.protocol { field public static final java.lang.String USER_TOKEN = "http.user-token"; } - public class ClientContextConfigurer implements org.apache.http.client.protocol.ClientContext { + public deprecated class ClientContextConfigurer implements org.apache.http.client.protocol.ClientContext { ctor public ClientContextConfigurer(org.apache.http.protocol.HttpContext); method public void setAuthSchemePref(java.util.List<java.lang.String>); method public void setAuthSchemeRegistry(org.apache.http.auth.AuthSchemeRegistry); @@ -54738,27 +55155,27 @@ package org.apache.http.client.protocol { method public void setCredentialsProvider(org.apache.http.client.CredentialsProvider); } - public class RequestAddCookies implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestAddCookies implements org.apache.http.HttpRequestInterceptor { ctor public RequestAddCookies(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class RequestDefaultHeaders implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestDefaultHeaders implements org.apache.http.HttpRequestInterceptor { ctor public RequestDefaultHeaders(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class RequestProxyAuthentication implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestProxyAuthentication implements org.apache.http.HttpRequestInterceptor { ctor public RequestProxyAuthentication(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class RequestTargetAuthentication implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestTargetAuthentication implements org.apache.http.HttpRequestInterceptor { ctor public RequestTargetAuthentication(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class ResponseProcessCookies implements org.apache.http.HttpResponseInterceptor { + public deprecated class ResponseProcessCookies implements org.apache.http.HttpResponseInterceptor { ctor public ResponseProcessCookies(); method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } @@ -54767,11 +55184,11 @@ package org.apache.http.client.protocol { package org.apache.http.client.utils { - public class CloneUtils { + public deprecated class CloneUtils { method public static java.lang.Object clone(java.lang.Object) throws java.lang.CloneNotSupportedException; } - public class URIUtils { + public deprecated class URIUtils { method public static java.net.URI createURI(java.lang.String, java.lang.String, int, java.lang.String, java.lang.String, java.lang.String) throws java.net.URISyntaxException; method public static java.net.URI resolve(java.net.URI, java.lang.String); method public static java.net.URI resolve(java.net.URI, java.net.URI); @@ -54779,7 +55196,7 @@ package org.apache.http.client.utils { method public static java.net.URI rewriteURI(java.net.URI, org.apache.http.HttpHost) throws java.net.URISyntaxException; } - public class URLEncodedUtils { + public deprecated class URLEncodedUtils { ctor public URLEncodedUtils(); method public static java.lang.String format(java.util.List<? extends org.apache.http.NameValuePair>, java.lang.String); method public static boolean isEncoded(org.apache.http.HttpEntity); @@ -54793,7 +55210,7 @@ package org.apache.http.client.utils { package org.apache.http.conn { - public class BasicEofSensorWatcher implements org.apache.http.conn.EofSensorWatcher { + public deprecated class BasicEofSensorWatcher implements org.apache.http.conn.EofSensorWatcher { ctor public BasicEofSensorWatcher(org.apache.http.conn.ManagedClientConnection, boolean); method public boolean eofDetected(java.io.InputStream) throws java.io.IOException; method public boolean streamAbort(java.io.InputStream) throws java.io.IOException; @@ -54802,7 +55219,7 @@ package org.apache.http.conn { field protected org.apache.http.conn.ManagedClientConnection managedConn; } - public class BasicManagedEntity extends org.apache.http.entity.HttpEntityWrapper implements org.apache.http.conn.ConnectionReleaseTrigger org.apache.http.conn.EofSensorWatcher { + public deprecated class BasicManagedEntity extends org.apache.http.entity.HttpEntityWrapper implements org.apache.http.conn.ConnectionReleaseTrigger org.apache.http.conn.EofSensorWatcher { ctor public BasicManagedEntity(org.apache.http.HttpEntity, org.apache.http.conn.ManagedClientConnection, boolean); method public void abortConnection() throws java.io.IOException; method public boolean eofDetected(java.io.InputStream) throws java.io.IOException; @@ -54814,7 +55231,7 @@ package org.apache.http.conn { field protected org.apache.http.conn.ManagedClientConnection managedConn; } - public abstract interface ClientConnectionManager { + public abstract deprecated interface ClientConnectionManager { method public abstract void closeExpiredConnections(); method public abstract void closeIdleConnections(long, java.util.concurrent.TimeUnit); method public abstract org.apache.http.conn.scheme.SchemeRegistry getSchemeRegistry(); @@ -54823,41 +55240,41 @@ package org.apache.http.conn { method public abstract void shutdown(); } - public abstract interface ClientConnectionManagerFactory { + public abstract deprecated interface ClientConnectionManagerFactory { method public abstract org.apache.http.conn.ClientConnectionManager newInstance(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry); } - public abstract interface ClientConnectionOperator { + public abstract deprecated interface ClientConnectionOperator { method public abstract org.apache.http.conn.OperatedClientConnection createConnection(); method public abstract void openConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException; method public abstract void updateSecureConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException; } - public abstract interface ClientConnectionRequest { + public abstract deprecated interface ClientConnectionRequest { method public abstract void abortRequest(); method public abstract org.apache.http.conn.ManagedClientConnection getConnection(long, java.util.concurrent.TimeUnit) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException; } - public class ConnectTimeoutException extends java.io.InterruptedIOException { + public deprecated class ConnectTimeoutException extends java.io.InterruptedIOException { ctor public ConnectTimeoutException(); ctor public ConnectTimeoutException(java.lang.String); } - public abstract interface ConnectionKeepAliveStrategy { + public abstract deprecated interface ConnectionKeepAliveStrategy { method public abstract long getKeepAliveDuration(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public class ConnectionPoolTimeoutException extends org.apache.http.conn.ConnectTimeoutException { + public deprecated class ConnectionPoolTimeoutException extends org.apache.http.conn.ConnectTimeoutException { ctor public ConnectionPoolTimeoutException(); ctor public ConnectionPoolTimeoutException(java.lang.String); } - public abstract interface ConnectionReleaseTrigger { + public abstract deprecated interface ConnectionReleaseTrigger { method public abstract void abortConnection() throws java.io.IOException; method public abstract void releaseConnection() throws java.io.IOException; } - public class EofSensorInputStream extends java.io.InputStream implements org.apache.http.conn.ConnectionReleaseTrigger { + public deprecated class EofSensorInputStream extends java.io.InputStream implements org.apache.http.conn.ConnectionReleaseTrigger { ctor public EofSensorInputStream(java.io.InputStream, org.apache.http.conn.EofSensorWatcher); method public void abortConnection() throws java.io.IOException; method protected void checkAbort() throws java.io.IOException; @@ -54869,18 +55286,18 @@ package org.apache.http.conn { field protected java.io.InputStream wrappedStream; } - public abstract interface EofSensorWatcher { + public abstract deprecated interface EofSensorWatcher { method public abstract boolean eofDetected(java.io.InputStream) throws java.io.IOException; method public abstract boolean streamAbort(java.io.InputStream) throws java.io.IOException; method public abstract boolean streamClosed(java.io.InputStream) throws java.io.IOException; } - public class HttpHostConnectException extends java.net.ConnectException { + public deprecated class HttpHostConnectException extends java.net.ConnectException { ctor public HttpHostConnectException(org.apache.http.HttpHost, java.net.ConnectException); method public org.apache.http.HttpHost getHost(); } - public abstract interface ManagedClientConnection implements org.apache.http.conn.ConnectionReleaseTrigger org.apache.http.HttpClientConnection org.apache.http.HttpInetConnection { + public abstract deprecated interface ManagedClientConnection implements org.apache.http.conn.ConnectionReleaseTrigger org.apache.http.HttpClientConnection org.apache.http.HttpInetConnection { method public abstract org.apache.http.conn.routing.HttpRoute getRoute(); method public abstract javax.net.ssl.SSLSession getSSLSession(); method public abstract java.lang.Object getState(); @@ -54896,14 +55313,14 @@ package org.apache.http.conn { method public abstract void unmarkReusable(); } - public final class MultihomePlainSocketFactory implements org.apache.http.conn.scheme.SocketFactory { + public final deprecated class MultihomePlainSocketFactory implements org.apache.http.conn.scheme.SocketFactory { method public java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws java.io.IOException; method public java.net.Socket createSocket(); method public static org.apache.http.conn.MultihomePlainSocketFactory getSocketFactory(); method public final boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException; } - public abstract interface OperatedClientConnection implements org.apache.http.HttpClientConnection org.apache.http.HttpInetConnection { + public abstract deprecated interface OperatedClientConnection implements org.apache.http.HttpClientConnection org.apache.http.HttpInetConnection { method public abstract java.net.Socket getSocket(); method public abstract org.apache.http.HttpHost getTargetHost(); method public abstract boolean isSecure(); @@ -54916,29 +55333,29 @@ package org.apache.http.conn { package org.apache.http.conn.params { - public abstract interface ConnConnectionPNames { + public abstract deprecated interface ConnConnectionPNames { field public static final java.lang.String MAX_STATUS_LINE_GARBAGE = "http.connection.max-status-line-garbage"; } - public class ConnConnectionParamBean extends org.apache.http.params.HttpAbstractParamBean { + public deprecated class ConnConnectionParamBean extends org.apache.http.params.HttpAbstractParamBean { ctor public ConnConnectionParamBean(org.apache.http.params.HttpParams); method public void setMaxStatusLineGarbage(int); } - public abstract interface ConnManagerPNames { + public abstract deprecated interface ConnManagerPNames { field public static final java.lang.String MAX_CONNECTIONS_PER_ROUTE = "http.conn-manager.max-per-route"; field public static final java.lang.String MAX_TOTAL_CONNECTIONS = "http.conn-manager.max-total"; field public static final java.lang.String TIMEOUT = "http.conn-manager.timeout"; } - public class ConnManagerParamBean extends org.apache.http.params.HttpAbstractParamBean { + public deprecated class ConnManagerParamBean extends org.apache.http.params.HttpAbstractParamBean { ctor public ConnManagerParamBean(org.apache.http.params.HttpParams); method public void setConnectionsPerRoute(org.apache.http.conn.params.ConnPerRouteBean); method public void setMaxTotalConnections(int); method public void setTimeout(long); } - public final class ConnManagerParams implements org.apache.http.conn.params.ConnManagerPNames { + public final deprecated class ConnManagerParams implements org.apache.http.conn.params.ConnManagerPNames { ctor public ConnManagerParams(); method public static org.apache.http.conn.params.ConnPerRoute getMaxConnectionsPerRoute(org.apache.http.params.HttpParams); method public static int getMaxTotalConnections(org.apache.http.params.HttpParams); @@ -54949,11 +55366,11 @@ package org.apache.http.conn.params { field public static final int DEFAULT_MAX_TOTAL_CONNECTIONS = 20; // 0x14 } - public abstract interface ConnPerRoute { + public abstract deprecated interface ConnPerRoute { method public abstract int getMaxForRoute(org.apache.http.conn.routing.HttpRoute); } - public final class ConnPerRouteBean implements org.apache.http.conn.params.ConnPerRoute { + public final deprecated class ConnPerRouteBean implements org.apache.http.conn.params.ConnPerRoute { ctor public ConnPerRouteBean(int); ctor public ConnPerRouteBean(); method public int getDefaultMax(); @@ -54964,20 +55381,20 @@ package org.apache.http.conn.params { field public static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 2; // 0x2 } - public abstract interface ConnRoutePNames { + public abstract deprecated interface ConnRoutePNames { field public static final java.lang.String DEFAULT_PROXY = "http.route.default-proxy"; field public static final java.lang.String FORCED_ROUTE = "http.route.forced-route"; field public static final java.lang.String LOCAL_ADDRESS = "http.route.local-address"; } - public class ConnRouteParamBean extends org.apache.http.params.HttpAbstractParamBean { + public deprecated class ConnRouteParamBean extends org.apache.http.params.HttpAbstractParamBean { ctor public ConnRouteParamBean(org.apache.http.params.HttpParams); method public void setDefaultProxy(org.apache.http.HttpHost); method public void setForcedRoute(org.apache.http.conn.routing.HttpRoute); method public void setLocalAddress(java.net.InetAddress); } - public class ConnRouteParams implements org.apache.http.conn.params.ConnRoutePNames { + public deprecated class ConnRouteParams implements org.apache.http.conn.params.ConnRoutePNames { method public static org.apache.http.HttpHost getDefaultProxy(org.apache.http.params.HttpParams); method public static org.apache.http.conn.routing.HttpRoute getForcedRoute(org.apache.http.params.HttpParams); method public static java.net.InetAddress getLocalAddress(org.apache.http.params.HttpParams); @@ -54992,7 +55409,7 @@ package org.apache.http.conn.params { package org.apache.http.conn.routing { - public class BasicRouteDirector implements org.apache.http.conn.routing.HttpRouteDirector { + public deprecated class BasicRouteDirector implements org.apache.http.conn.routing.HttpRouteDirector { ctor public BasicRouteDirector(); method protected int directStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo); method protected int firstStep(org.apache.http.conn.routing.RouteInfo); @@ -55000,7 +55417,7 @@ package org.apache.http.conn.routing { method protected int proxiedStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo); } - public final class HttpRoute implements java.lang.Cloneable org.apache.http.conn.routing.RouteInfo { + public final deprecated class HttpRoute implements java.lang.Cloneable org.apache.http.conn.routing.RouteInfo { ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.HttpHost[], boolean, org.apache.http.conn.routing.RouteInfo.TunnelType, org.apache.http.conn.routing.RouteInfo.LayerType); ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.HttpHost, boolean, org.apache.http.conn.routing.RouteInfo.TunnelType, org.apache.http.conn.routing.RouteInfo.LayerType); ctor public HttpRoute(org.apache.http.HttpHost, java.net.InetAddress, boolean); @@ -55022,7 +55439,7 @@ package org.apache.http.conn.routing { method public final java.lang.String toString(); } - public abstract interface HttpRouteDirector { + public abstract deprecated interface HttpRouteDirector { method public abstract int nextStep(org.apache.http.conn.routing.RouteInfo, org.apache.http.conn.routing.RouteInfo); field public static final int COMPLETE = 0; // 0x0 field public static final int CONNECT_PROXY = 2; // 0x2 @@ -55033,11 +55450,11 @@ package org.apache.http.conn.routing { field public static final int UNREACHABLE = -1; // 0xffffffff } - public abstract interface HttpRoutePlanner { + public abstract deprecated interface HttpRoutePlanner { method public abstract org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException; } - public abstract interface RouteInfo { + public abstract deprecated interface RouteInfo { method public abstract int getHopCount(); method public abstract org.apache.http.HttpHost getHopTarget(int); method public abstract org.apache.http.conn.routing.RouteInfo.LayerType getLayerType(); @@ -55064,7 +55481,7 @@ package org.apache.http.conn.routing { enum_constant public static final org.apache.http.conn.routing.RouteInfo.TunnelType TUNNELLED; } - public final class RouteTracker implements java.lang.Cloneable org.apache.http.conn.routing.RouteInfo { + public final deprecated class RouteTracker implements java.lang.Cloneable org.apache.http.conn.routing.RouteInfo { ctor public RouteTracker(org.apache.http.HttpHost, java.net.InetAddress); ctor public RouteTracker(org.apache.http.conn.routing.HttpRoute); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; @@ -55094,15 +55511,15 @@ package org.apache.http.conn.routing { package org.apache.http.conn.scheme { - public abstract interface HostNameResolver { + public abstract deprecated interface HostNameResolver { method public abstract java.net.InetAddress resolve(java.lang.String) throws java.io.IOException; } - public abstract interface LayeredSocketFactory implements org.apache.http.conn.scheme.SocketFactory { + public abstract deprecated interface LayeredSocketFactory implements org.apache.http.conn.scheme.SocketFactory { method public abstract java.net.Socket createSocket(java.net.Socket, java.lang.String, int, boolean) throws java.io.IOException, java.net.UnknownHostException; } - public final class PlainSocketFactory implements org.apache.http.conn.scheme.SocketFactory { + public final deprecated class PlainSocketFactory implements org.apache.http.conn.scheme.SocketFactory { ctor public PlainSocketFactory(org.apache.http.conn.scheme.HostNameResolver); ctor public PlainSocketFactory(); method public java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws java.io.IOException; @@ -55111,7 +55528,7 @@ package org.apache.http.conn.scheme { method public final boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException; } - public final class Scheme { + public final deprecated class Scheme { ctor public Scheme(java.lang.String, org.apache.http.conn.scheme.SocketFactory, int); method public final boolean equals(java.lang.Object); method public final int getDefaultPort(); @@ -55122,7 +55539,7 @@ package org.apache.http.conn.scheme { method public final java.lang.String toString(); } - public final class SchemeRegistry { + public final deprecated class SchemeRegistry { ctor public SchemeRegistry(); method public final synchronized org.apache.http.conn.scheme.Scheme get(java.lang.String); method public final synchronized org.apache.http.conn.scheme.Scheme getScheme(java.lang.String); @@ -55133,7 +55550,7 @@ package org.apache.http.conn.scheme { method public final synchronized org.apache.http.conn.scheme.Scheme unregister(java.lang.String); } - public abstract interface SocketFactory { + public abstract deprecated interface SocketFactory { method public abstract java.net.Socket connectSocket(java.net.Socket, java.lang.String, int, java.net.InetAddress, int, org.apache.http.params.HttpParams) throws org.apache.http.conn.ConnectTimeoutException, java.io.IOException, java.net.UnknownHostException; method public abstract java.net.Socket createSocket() throws java.io.IOException; method public abstract boolean isSecure(java.net.Socket) throws java.lang.IllegalArgumentException; @@ -55143,7 +55560,7 @@ package org.apache.http.conn.scheme { package org.apache.http.conn.ssl { - public abstract class AbstractVerifier implements org.apache.http.conn.ssl.X509HostnameVerifier { + public abstract deprecated class AbstractVerifier implements org.apache.http.conn.ssl.X509HostnameVerifier { ctor public AbstractVerifier(); method public static boolean acceptableCountryWildcard(java.lang.String); method public static int countDots(java.lang.String); @@ -55155,19 +55572,19 @@ package org.apache.http.conn.ssl { method public final void verify(java.lang.String, java.lang.String[], java.lang.String[], boolean) throws javax.net.ssl.SSLException; } - public class AllowAllHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier { + public deprecated class AllowAllHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier { ctor public AllowAllHostnameVerifier(); method public final java.lang.String toString(); method public final void verify(java.lang.String, java.lang.String[], java.lang.String[]); } - public class BrowserCompatHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier { + public deprecated class BrowserCompatHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier { ctor public BrowserCompatHostnameVerifier(); method public final java.lang.String toString(); method public final void verify(java.lang.String, java.lang.String[], java.lang.String[]) throws javax.net.ssl.SSLException; } - public class SSLSocketFactory implements org.apache.http.conn.scheme.LayeredSocketFactory { + public deprecated class SSLSocketFactory implements org.apache.http.conn.scheme.LayeredSocketFactory { ctor public SSLSocketFactory(java.lang.String, java.security.KeyStore, java.lang.String, java.security.KeyStore, java.security.SecureRandom, org.apache.http.conn.scheme.HostNameResolver) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException; ctor public SSLSocketFactory(java.security.KeyStore, java.lang.String, java.security.KeyStore) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException; ctor public SSLSocketFactory(java.security.KeyStore, java.lang.String) throws java.security.KeyManagementException, java.security.KeyStoreException, java.security.NoSuchAlgorithmException, java.security.UnrecoverableKeyException; @@ -55187,13 +55604,13 @@ package org.apache.http.conn.ssl { field public static final java.lang.String TLS = "TLS"; } - public class StrictHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier { + public deprecated class StrictHostnameVerifier extends org.apache.http.conn.ssl.AbstractVerifier { ctor public StrictHostnameVerifier(); method public final java.lang.String toString(); method public final void verify(java.lang.String, java.lang.String[], java.lang.String[]) throws javax.net.ssl.SSLException; } - public abstract interface X509HostnameVerifier implements javax.net.ssl.HostnameVerifier { + public abstract deprecated interface X509HostnameVerifier implements javax.net.ssl.HostnameVerifier { method public abstract boolean verify(java.lang.String, javax.net.ssl.SSLSession); method public abstract void verify(java.lang.String, javax.net.ssl.SSLSocket) throws java.io.IOException; method public abstract void verify(java.lang.String, java.security.cert.X509Certificate) throws javax.net.ssl.SSLException; @@ -55204,7 +55621,7 @@ package org.apache.http.conn.ssl { package org.apache.http.conn.util { - public class InetAddressUtils { + public deprecated class InetAddressUtils { method public static boolean isIPv4Address(java.lang.String); method public static boolean isIPv6Address(java.lang.String); method public static boolean isIPv6HexCompressedAddress(java.lang.String); @@ -55215,7 +55632,7 @@ package org.apache.http.conn.util { package org.apache.http.cookie { - public abstract interface ClientCookie implements org.apache.http.cookie.Cookie { + public abstract deprecated interface ClientCookie implements org.apache.http.cookie.Cookie { method public abstract boolean containsAttribute(java.lang.String); method public abstract java.lang.String getAttribute(java.lang.String); field public static final java.lang.String COMMENTURL_ATTR = "commenturl"; @@ -55230,7 +55647,7 @@ package org.apache.http.cookie { field public static final java.lang.String VERSION_ATTR = "version"; } - public abstract interface Cookie { + public abstract deprecated interface Cookie { method public abstract java.lang.String getComment(); method public abstract java.lang.String getCommentURL(); method public abstract java.lang.String getDomain(); @@ -55245,18 +55662,18 @@ package org.apache.http.cookie { method public abstract boolean isSecure(); } - public abstract interface CookieAttributeHandler { + public abstract deprecated interface CookieAttributeHandler { method public abstract boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public abstract void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; method public abstract void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class CookieIdentityComparator implements java.util.Comparator java.io.Serializable { + public deprecated class CookieIdentityComparator implements java.util.Comparator java.io.Serializable { ctor public CookieIdentityComparator(); method public int compare(org.apache.http.cookie.Cookie, org.apache.http.cookie.Cookie); } - public final class CookieOrigin { + public final deprecated class CookieOrigin { ctor public CookieOrigin(java.lang.String, int, java.lang.String, boolean); method public java.lang.String getHost(); method public java.lang.String getPath(); @@ -55264,12 +55681,12 @@ package org.apache.http.cookie { method public boolean isSecure(); } - public class CookiePathComparator implements java.util.Comparator java.io.Serializable { + public deprecated class CookiePathComparator implements java.util.Comparator java.io.Serializable { ctor public CookiePathComparator(); method public int compare(org.apache.http.cookie.Cookie, org.apache.http.cookie.Cookie); } - public abstract interface CookieSpec { + public abstract deprecated interface CookieSpec { method public abstract java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>); method public abstract int getVersion(); method public abstract org.apache.http.Header getVersionHeader(); @@ -55278,11 +55695,11 @@ package org.apache.http.cookie { method public abstract void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public abstract interface CookieSpecFactory { + public abstract deprecated interface CookieSpecFactory { method public abstract org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams); } - public final class CookieSpecRegistry { + public final deprecated class CookieSpecRegistry { ctor public CookieSpecRegistry(); method public synchronized org.apache.http.cookie.CookieSpec getCookieSpec(java.lang.String, org.apache.http.params.HttpParams) throws java.lang.IllegalStateException; method public synchronized org.apache.http.cookie.CookieSpec getCookieSpec(java.lang.String) throws java.lang.IllegalStateException; @@ -55292,20 +55709,20 @@ package org.apache.http.cookie { method public synchronized void unregister(java.lang.String); } - public class MalformedCookieException extends org.apache.http.ProtocolException { + public deprecated class MalformedCookieException extends org.apache.http.ProtocolException { ctor public MalformedCookieException(); ctor public MalformedCookieException(java.lang.String); ctor public MalformedCookieException(java.lang.String, java.lang.Throwable); } - public abstract interface SM { + public abstract deprecated interface SM { field public static final java.lang.String COOKIE = "Cookie"; field public static final java.lang.String COOKIE2 = "Cookie2"; field public static final java.lang.String SET_COOKIE = "Set-Cookie"; field public static final java.lang.String SET_COOKIE2 = "Set-Cookie2"; } - public abstract interface SetCookie implements org.apache.http.cookie.Cookie { + public abstract deprecated interface SetCookie implements org.apache.http.cookie.Cookie { method public abstract void setComment(java.lang.String); method public abstract void setDomain(java.lang.String); method public abstract void setExpiryDate(java.util.Date); @@ -55315,7 +55732,7 @@ package org.apache.http.cookie { method public abstract void setVersion(int); } - public abstract interface SetCookie2 implements org.apache.http.cookie.SetCookie { + public abstract deprecated interface SetCookie2 implements org.apache.http.cookie.SetCookie { method public abstract void setCommentURL(java.lang.String); method public abstract void setDiscard(boolean); method public abstract void setPorts(int[]); @@ -55325,12 +55742,12 @@ package org.apache.http.cookie { package org.apache.http.cookie.params { - public abstract interface CookieSpecPNames { + public abstract deprecated interface CookieSpecPNames { field public static final java.lang.String DATE_PATTERNS = "http.protocol.cookie-datepatterns"; field public static final java.lang.String SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header"; } - public class CookieSpecParamBean extends org.apache.http.params.HttpAbstractParamBean { + public deprecated class CookieSpecParamBean extends org.apache.http.params.HttpAbstractParamBean { ctor public CookieSpecParamBean(org.apache.http.params.HttpParams); method public void setDatePatterns(java.util.Collection<java.lang.String>); method public void setSingleHeader(boolean); @@ -55340,7 +55757,7 @@ package org.apache.http.cookie.params { package org.apache.http.entity { - public abstract class AbstractHttpEntity implements org.apache.http.HttpEntity { + public abstract deprecated class AbstractHttpEntity implements org.apache.http.HttpEntity { ctor protected AbstractHttpEntity(); method public void consumeContent() throws java.io.IOException, java.lang.UnsupportedOperationException; method public org.apache.http.Header getContentEncoding(); @@ -55356,7 +55773,7 @@ package org.apache.http.entity { field protected org.apache.http.Header contentType; } - public class BasicHttpEntity extends org.apache.http.entity.AbstractHttpEntity { + public deprecated class BasicHttpEntity extends org.apache.http.entity.AbstractHttpEntity { ctor public BasicHttpEntity(); method public java.io.InputStream getContent() throws java.lang.IllegalStateException; method public long getContentLength(); @@ -55367,11 +55784,11 @@ package org.apache.http.entity { method public void writeTo(java.io.OutputStream) throws java.io.IOException; } - public class BufferedHttpEntity extends org.apache.http.entity.HttpEntityWrapper { + public deprecated class BufferedHttpEntity extends org.apache.http.entity.HttpEntityWrapper { ctor public BufferedHttpEntity(org.apache.http.HttpEntity) throws java.io.IOException; } - public class ByteArrayEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable { + public deprecated class ByteArrayEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable { ctor public ByteArrayEntity(byte[]); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public java.io.InputStream getContent(); @@ -55382,17 +55799,17 @@ package org.apache.http.entity { field protected final byte[] content; } - public abstract interface ContentLengthStrategy { + public abstract deprecated interface ContentLengthStrategy { method public abstract long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException; field public static final int CHUNKED = -2; // 0xfffffffe field public static final int IDENTITY = -1; // 0xffffffff } - public abstract interface ContentProducer { + public abstract deprecated interface ContentProducer { method public abstract void writeTo(java.io.OutputStream) throws java.io.IOException; } - public class EntityTemplate extends org.apache.http.entity.AbstractHttpEntity { + public deprecated class EntityTemplate extends org.apache.http.entity.AbstractHttpEntity { ctor public EntityTemplate(org.apache.http.entity.ContentProducer); method public java.io.InputStream getContent(); method public long getContentLength(); @@ -55401,7 +55818,7 @@ package org.apache.http.entity { method public void writeTo(java.io.OutputStream) throws java.io.IOException; } - public class FileEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable { + public deprecated class FileEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable { ctor public FileEntity(java.io.File, java.lang.String); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public java.io.InputStream getContent() throws java.io.IOException; @@ -55412,7 +55829,7 @@ package org.apache.http.entity { field protected final java.io.File file; } - public class HttpEntityWrapper implements org.apache.http.HttpEntity { + public deprecated class HttpEntityWrapper implements org.apache.http.HttpEntity { ctor public HttpEntityWrapper(org.apache.http.HttpEntity); method public void consumeContent() throws java.io.IOException; method public java.io.InputStream getContent() throws java.io.IOException; @@ -55426,7 +55843,7 @@ package org.apache.http.entity { field protected org.apache.http.HttpEntity wrappedEntity; } - public class InputStreamEntity extends org.apache.http.entity.AbstractHttpEntity { + public deprecated class InputStreamEntity extends org.apache.http.entity.AbstractHttpEntity { ctor public InputStreamEntity(java.io.InputStream, long); method public java.io.InputStream getContent() throws java.io.IOException; method public long getContentLength(); @@ -55435,7 +55852,7 @@ package org.apache.http.entity { method public void writeTo(java.io.OutputStream) throws java.io.IOException; } - public class SerializableEntity extends org.apache.http.entity.AbstractHttpEntity { + public deprecated class SerializableEntity extends org.apache.http.entity.AbstractHttpEntity { ctor public SerializableEntity(java.io.Serializable, boolean) throws java.io.IOException; method public java.io.InputStream getContent() throws java.io.IOException, java.lang.IllegalStateException; method public long getContentLength(); @@ -55444,7 +55861,7 @@ package org.apache.http.entity { method public void writeTo(java.io.OutputStream) throws java.io.IOException; } - public class StringEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable { + public deprecated class StringEntity extends org.apache.http.entity.AbstractHttpEntity implements java.lang.Cloneable { ctor public StringEntity(java.lang.String, java.lang.String) throws java.io.UnsupportedEncodingException; ctor public StringEntity(java.lang.String) throws java.io.UnsupportedEncodingException; method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; @@ -55460,7 +55877,7 @@ package org.apache.http.entity { package org.apache.http.impl { - public abstract class AbstractHttpClientConnection implements org.apache.http.HttpClientConnection { + public abstract deprecated class AbstractHttpClientConnection implements org.apache.http.HttpClientConnection { ctor public AbstractHttpClientConnection(); method protected abstract void assertOpen() throws java.lang.IllegalStateException; method protected org.apache.http.impl.entity.EntityDeserializer createEntityDeserializer(); @@ -55480,7 +55897,7 @@ package org.apache.http.impl { method public void sendRequestHeader(org.apache.http.HttpRequest) throws org.apache.http.HttpException, java.io.IOException; } - public abstract class AbstractHttpServerConnection implements org.apache.http.HttpServerConnection { + public abstract deprecated class AbstractHttpServerConnection implements org.apache.http.HttpServerConnection { ctor public AbstractHttpServerConnection(); method protected abstract void assertOpen() throws java.lang.IllegalStateException; method protected org.apache.http.impl.entity.EntityDeserializer createEntityDeserializer(); @@ -55499,24 +55916,24 @@ package org.apache.http.impl { method public void sendResponseHeader(org.apache.http.HttpResponse) throws org.apache.http.HttpException, java.io.IOException; } - public class DefaultConnectionReuseStrategy implements org.apache.http.ConnectionReuseStrategy { + public deprecated class DefaultConnectionReuseStrategy implements org.apache.http.ConnectionReuseStrategy { ctor public DefaultConnectionReuseStrategy(); method protected org.apache.http.TokenIterator createTokenIterator(org.apache.http.HeaderIterator); method public boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public class DefaultHttpClientConnection extends org.apache.http.impl.SocketHttpClientConnection { + public deprecated class DefaultHttpClientConnection extends org.apache.http.impl.SocketHttpClientConnection { ctor public DefaultHttpClientConnection(); method public void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException; } - public class DefaultHttpRequestFactory implements org.apache.http.HttpRequestFactory { + public deprecated class DefaultHttpRequestFactory implements org.apache.http.HttpRequestFactory { ctor public DefaultHttpRequestFactory(); method public org.apache.http.HttpRequest newHttpRequest(org.apache.http.RequestLine) throws org.apache.http.MethodNotSupportedException; method public org.apache.http.HttpRequest newHttpRequest(java.lang.String, java.lang.String) throws org.apache.http.MethodNotSupportedException; } - public class DefaultHttpResponseFactory implements org.apache.http.HttpResponseFactory { + public deprecated class DefaultHttpResponseFactory implements org.apache.http.HttpResponseFactory { ctor public DefaultHttpResponseFactory(org.apache.http.ReasonPhraseCatalog); ctor public DefaultHttpResponseFactory(); method protected java.util.Locale determineLocale(org.apache.http.protocol.HttpContext); @@ -55525,18 +55942,18 @@ package org.apache.http.impl { field protected final org.apache.http.ReasonPhraseCatalog reasonCatalog; } - public class DefaultHttpServerConnection extends org.apache.http.impl.SocketHttpServerConnection { + public deprecated class DefaultHttpServerConnection extends org.apache.http.impl.SocketHttpServerConnection { ctor public DefaultHttpServerConnection(); method public void bind(java.net.Socket, org.apache.http.params.HttpParams) throws java.io.IOException; } - public class EnglishReasonPhraseCatalog implements org.apache.http.ReasonPhraseCatalog { + public deprecated class EnglishReasonPhraseCatalog implements org.apache.http.ReasonPhraseCatalog { ctor protected EnglishReasonPhraseCatalog(); method public java.lang.String getReason(int, java.util.Locale); field public static final org.apache.http.impl.EnglishReasonPhraseCatalog INSTANCE; } - public class HttpConnectionMetricsImpl implements org.apache.http.HttpConnectionMetrics { + public deprecated class HttpConnectionMetricsImpl implements org.apache.http.HttpConnectionMetrics { ctor public HttpConnectionMetricsImpl(org.apache.http.io.HttpTransportMetrics, org.apache.http.io.HttpTransportMetrics); method public java.lang.Object getMetric(java.lang.String); method public long getReceivedBytesCount(); @@ -55553,12 +55970,12 @@ package org.apache.http.impl { field public static final java.lang.String SENT_BYTES_COUNT = "http.sent-bytes-count"; } - public class NoConnectionReuseStrategy implements org.apache.http.ConnectionReuseStrategy { + public deprecated class NoConnectionReuseStrategy implements org.apache.http.ConnectionReuseStrategy { ctor public NoConnectionReuseStrategy(); method public boolean keepAlive(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public class SocketHttpClientConnection extends org.apache.http.impl.AbstractHttpClientConnection implements org.apache.http.HttpInetConnection { + public deprecated class SocketHttpClientConnection extends org.apache.http.impl.AbstractHttpClientConnection implements org.apache.http.HttpInetConnection { ctor public SocketHttpClientConnection(); method protected void assertNotOpen(); method protected void assertOpen(); @@ -55577,7 +55994,7 @@ package org.apache.http.impl { method public void shutdown() throws java.io.IOException; } - public class SocketHttpServerConnection extends org.apache.http.impl.AbstractHttpServerConnection implements org.apache.http.HttpInetConnection { + public deprecated class SocketHttpServerConnection extends org.apache.http.impl.AbstractHttpServerConnection implements org.apache.http.HttpInetConnection { ctor public SocketHttpServerConnection(); method protected void assertNotOpen(); method protected void assertOpen(); @@ -55600,14 +56017,14 @@ package org.apache.http.impl { package org.apache.http.impl.auth { - public abstract class AuthSchemeBase implements org.apache.http.auth.AuthScheme { + public abstract deprecated class AuthSchemeBase implements org.apache.http.auth.AuthScheme { ctor public AuthSchemeBase(); method public boolean isProxy(); method protected abstract void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException; method public void processChallenge(org.apache.http.Header) throws org.apache.http.auth.MalformedChallengeException; } - public class BasicScheme extends org.apache.http.impl.auth.RFC2617Scheme { + public deprecated class BasicScheme extends org.apache.http.impl.auth.RFC2617Scheme { ctor public BasicScheme(); method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException; method public static org.apache.http.Header authenticate(org.apache.http.auth.Credentials, java.lang.String, boolean); @@ -55616,12 +56033,12 @@ package org.apache.http.impl.auth { method public boolean isConnectionBased(); } - public class BasicSchemeFactory implements org.apache.http.auth.AuthSchemeFactory { + public deprecated class BasicSchemeFactory implements org.apache.http.auth.AuthSchemeFactory { ctor public BasicSchemeFactory(); method public org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams); } - public class DigestScheme extends org.apache.http.impl.auth.RFC2617Scheme { + public deprecated class DigestScheme extends org.apache.http.impl.auth.RFC2617Scheme { ctor public DigestScheme(); method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException; method public static java.lang.String createCnonce(); @@ -55631,23 +56048,23 @@ package org.apache.http.impl.auth { method public void overrideParamter(java.lang.String, java.lang.String); } - public class DigestSchemeFactory implements org.apache.http.auth.AuthSchemeFactory { + public deprecated class DigestSchemeFactory implements org.apache.http.auth.AuthSchemeFactory { ctor public DigestSchemeFactory(); method public org.apache.http.auth.AuthScheme newInstance(org.apache.http.params.HttpParams); } - public abstract interface NTLMEngine { + public abstract deprecated interface NTLMEngine { method public abstract java.lang.String generateType1Msg(java.lang.String, java.lang.String) throws org.apache.http.impl.auth.NTLMEngineException; method public abstract java.lang.String generateType3Msg(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String) throws org.apache.http.impl.auth.NTLMEngineException; } - public class NTLMEngineException extends org.apache.http.auth.AuthenticationException { + public deprecated class NTLMEngineException extends org.apache.http.auth.AuthenticationException { ctor public NTLMEngineException(); ctor public NTLMEngineException(java.lang.String); ctor public NTLMEngineException(java.lang.String, java.lang.Throwable); } - public class NTLMScheme extends org.apache.http.impl.auth.AuthSchemeBase { + public deprecated class NTLMScheme extends org.apache.http.impl.auth.AuthSchemeBase { ctor public NTLMScheme(org.apache.http.impl.auth.NTLMEngine); method public org.apache.http.Header authenticate(org.apache.http.auth.Credentials, org.apache.http.HttpRequest) throws org.apache.http.auth.AuthenticationException; method public java.lang.String getParameter(java.lang.String); @@ -55658,7 +56075,7 @@ package org.apache.http.impl.auth { method protected void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException; } - public abstract class RFC2617Scheme extends org.apache.http.impl.auth.AuthSchemeBase { + public abstract deprecated class RFC2617Scheme extends org.apache.http.impl.auth.AuthSchemeBase { ctor public RFC2617Scheme(); method public java.lang.String getParameter(java.lang.String); method protected java.util.Map<java.lang.String, java.lang.String> getParameters(); @@ -55666,7 +56083,7 @@ package org.apache.http.impl.auth { method protected void parseChallenge(org.apache.http.util.CharArrayBuffer, int, int) throws org.apache.http.auth.MalformedChallengeException; } - public class UnsupportedDigestAlgorithmException extends java.lang.RuntimeException { + public deprecated class UnsupportedDigestAlgorithmException extends java.lang.RuntimeException { ctor public UnsupportedDigestAlgorithmException(); ctor public UnsupportedDigestAlgorithmException(java.lang.String); ctor public UnsupportedDigestAlgorithmException(java.lang.String, java.lang.Throwable); @@ -55676,14 +56093,14 @@ package org.apache.http.impl.auth { package org.apache.http.impl.client { - public abstract class AbstractAuthenticationHandler implements org.apache.http.client.AuthenticationHandler { + public abstract deprecated class AbstractAuthenticationHandler implements org.apache.http.client.AuthenticationHandler { ctor public AbstractAuthenticationHandler(); method protected java.util.List<java.lang.String> getAuthPreferences(); method protected java.util.Map<java.lang.String, org.apache.http.Header> parseChallenges(org.apache.http.Header[]) throws org.apache.http.auth.MalformedChallengeException; method public org.apache.http.auth.AuthScheme selectScheme(java.util.Map<java.lang.String, org.apache.http.Header>, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.AuthenticationException; } - public abstract class AbstractHttpClient implements org.apache.http.client.HttpClient { + public abstract deprecated class AbstractHttpClient implements org.apache.http.client.HttpClient { ctor protected AbstractHttpClient(org.apache.http.conn.ClientConnectionManager, org.apache.http.params.HttpParams); method public synchronized void addRequestInterceptor(org.apache.http.HttpRequestInterceptor); method public synchronized void addRequestInterceptor(org.apache.http.HttpRequestInterceptor, int); @@ -55755,7 +56172,7 @@ package org.apache.http.impl.client { method public synchronized void setUserTokenHandler(org.apache.http.client.UserTokenHandler); } - public class BasicCookieStore implements org.apache.http.client.CookieStore { + public deprecated class BasicCookieStore implements org.apache.http.client.CookieStore { ctor public BasicCookieStore(); method public synchronized void addCookie(org.apache.http.cookie.Cookie); method public synchronized void addCookies(org.apache.http.cookie.Cookie[]); @@ -55764,19 +56181,19 @@ package org.apache.http.impl.client { method public synchronized java.util.List<org.apache.http.cookie.Cookie> getCookies(); } - public class BasicCredentialsProvider implements org.apache.http.client.CredentialsProvider { + public deprecated class BasicCredentialsProvider implements org.apache.http.client.CredentialsProvider { ctor public BasicCredentialsProvider(); method public synchronized void clear(); method public synchronized org.apache.http.auth.Credentials getCredentials(org.apache.http.auth.AuthScope); method public synchronized void setCredentials(org.apache.http.auth.AuthScope, org.apache.http.auth.Credentials); } - public class BasicResponseHandler implements org.apache.http.client.ResponseHandler { + public deprecated class BasicResponseHandler implements org.apache.http.client.ResponseHandler { ctor public BasicResponseHandler(); method public java.lang.String handleResponse(org.apache.http.HttpResponse) throws org.apache.http.client.HttpResponseException, java.io.IOException; } - public class ClientParamsStack extends org.apache.http.params.AbstractHttpParams { + public deprecated class ClientParamsStack extends org.apache.http.params.AbstractHttpParams { ctor public ClientParamsStack(org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams); ctor public ClientParamsStack(org.apache.http.impl.client.ClientParamsStack); ctor public ClientParamsStack(org.apache.http.impl.client.ClientParamsStack, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams, org.apache.http.params.HttpParams); @@ -55794,12 +56211,12 @@ package org.apache.http.impl.client { field protected final org.apache.http.params.HttpParams requestParams; } - public class DefaultConnectionKeepAliveStrategy implements org.apache.http.conn.ConnectionKeepAliveStrategy { + public deprecated class DefaultConnectionKeepAliveStrategy implements org.apache.http.conn.ConnectionKeepAliveStrategy { ctor public DefaultConnectionKeepAliveStrategy(); method public long getKeepAliveDuration(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public class DefaultHttpClient extends org.apache.http.impl.client.AbstractHttpClient { + public deprecated class DefaultHttpClient extends org.apache.http.impl.client.AbstractHttpClient { ctor public DefaultHttpClient(org.apache.http.conn.ClientConnectionManager, org.apache.http.params.HttpParams); ctor public DefaultHttpClient(org.apache.http.params.HttpParams); ctor public DefaultHttpClient(); @@ -55822,7 +56239,7 @@ package org.apache.http.impl.client { method protected org.apache.http.client.UserTokenHandler createUserTokenHandler(); } - public class DefaultHttpRequestRetryHandler implements org.apache.http.client.HttpRequestRetryHandler { + public deprecated class DefaultHttpRequestRetryHandler implements org.apache.http.client.HttpRequestRetryHandler { ctor public DefaultHttpRequestRetryHandler(int, boolean); ctor public DefaultHttpRequestRetryHandler(); method public int getRetryCount(); @@ -55830,19 +56247,19 @@ package org.apache.http.impl.client { method public boolean retryRequest(java.io.IOException, int, org.apache.http.protocol.HttpContext); } - public class DefaultProxyAuthenticationHandler extends org.apache.http.impl.client.AbstractAuthenticationHandler { + public deprecated class DefaultProxyAuthenticationHandler extends org.apache.http.impl.client.AbstractAuthenticationHandler { ctor public DefaultProxyAuthenticationHandler(); method public java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException; method public boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public class DefaultRedirectHandler implements org.apache.http.client.RedirectHandler { + public deprecated class DefaultRedirectHandler implements org.apache.http.client.RedirectHandler { ctor public DefaultRedirectHandler(); method public java.net.URI getLocationURI(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.ProtocolException; method public boolean isRedirectRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public class DefaultRequestDirector implements org.apache.http.client.RequestDirector { + public deprecated class DefaultRequestDirector implements org.apache.http.client.RequestDirector { ctor public DefaultRequestDirector(org.apache.http.protocol.HttpRequestExecutor, org.apache.http.conn.ClientConnectionManager, org.apache.http.ConnectionReuseStrategy, org.apache.http.conn.ConnectionKeepAliveStrategy, org.apache.http.conn.routing.HttpRoutePlanner, org.apache.http.protocol.HttpProcessor, org.apache.http.client.HttpRequestRetryHandler, org.apache.http.client.RedirectHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.AuthenticationHandler, org.apache.http.client.UserTokenHandler, org.apache.http.params.HttpParams); method protected org.apache.http.HttpRequest createConnectRequest(org.apache.http.conn.routing.HttpRoute, org.apache.http.protocol.HttpContext); method protected boolean createTunnelToProxy(org.apache.http.conn.routing.HttpRoute, int, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; @@ -55865,32 +56282,32 @@ package org.apache.http.impl.client { field protected final org.apache.http.conn.routing.HttpRoutePlanner routePlanner; } - public class DefaultTargetAuthenticationHandler extends org.apache.http.impl.client.AbstractAuthenticationHandler { + public deprecated class DefaultTargetAuthenticationHandler extends org.apache.http.impl.client.AbstractAuthenticationHandler { ctor public DefaultTargetAuthenticationHandler(); method public java.util.Map<java.lang.String, org.apache.http.Header> getChallenges(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.auth.MalformedChallengeException; method public boolean isAuthenticationRequested(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext); } - public class DefaultUserTokenHandler implements org.apache.http.client.UserTokenHandler { + public deprecated class DefaultUserTokenHandler implements org.apache.http.client.UserTokenHandler { ctor public DefaultUserTokenHandler(); method public java.lang.Object getUserToken(org.apache.http.protocol.HttpContext); } - public class EntityEnclosingRequestWrapper extends org.apache.http.impl.client.RequestWrapper implements org.apache.http.HttpEntityEnclosingRequest { + public deprecated class EntityEnclosingRequestWrapper extends org.apache.http.impl.client.RequestWrapper implements org.apache.http.HttpEntityEnclosingRequest { ctor public EntityEnclosingRequestWrapper(org.apache.http.HttpEntityEnclosingRequest) throws org.apache.http.ProtocolException; method public boolean expectContinue(); method public org.apache.http.HttpEntity getEntity(); method public void setEntity(org.apache.http.HttpEntity); } - public class RedirectLocations { + public deprecated class RedirectLocations { ctor public RedirectLocations(); method public void add(java.net.URI); method public boolean contains(java.net.URI); method public boolean remove(java.net.URI); } - public class RequestWrapper extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.client.methods.HttpUriRequest { + public deprecated class RequestWrapper extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.client.methods.HttpUriRequest { ctor public RequestWrapper(org.apache.http.HttpRequest) throws org.apache.http.ProtocolException; method public void abort() throws java.lang.UnsupportedOperationException; method public int getExecCount(); @@ -55908,7 +56325,7 @@ package org.apache.http.impl.client { method public void setURI(java.net.URI); } - public class RoutedRequest { + public deprecated class RoutedRequest { ctor public RoutedRequest(org.apache.http.impl.client.RequestWrapper, org.apache.http.conn.routing.HttpRoute); method public final org.apache.http.impl.client.RequestWrapper getRequest(); method public final org.apache.http.conn.routing.HttpRoute getRoute(); @@ -55916,7 +56333,7 @@ package org.apache.http.impl.client { field protected final org.apache.http.conn.routing.HttpRoute route; } - public class TunnelRefusedException extends org.apache.http.HttpException { + public deprecated class TunnelRefusedException extends org.apache.http.HttpException { ctor public TunnelRefusedException(java.lang.String, org.apache.http.HttpResponse); method public org.apache.http.HttpResponse getResponse(); } @@ -55925,7 +56342,7 @@ package org.apache.http.impl.client { package org.apache.http.impl.conn { - public abstract class AbstractClientConnAdapter implements org.apache.http.conn.ManagedClientConnection { + public abstract deprecated class AbstractClientConnAdapter implements org.apache.http.conn.ManagedClientConnection { ctor protected AbstractClientConnAdapter(org.apache.http.conn.ClientConnectionManager, org.apache.http.conn.OperatedClientConnection); method public void abortConnection(); method protected final void assertNotAborted() throws java.io.InterruptedIOException; @@ -55957,7 +56374,7 @@ package org.apache.http.impl.conn { method public void unmarkReusable(); } - public abstract class AbstractPoolEntry { + public abstract deprecated class AbstractPoolEntry { ctor protected AbstractPoolEntry(org.apache.http.conn.ClientConnectionOperator, org.apache.http.conn.routing.HttpRoute); method public java.lang.Object getState(); method public void layerProtocol(org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException; @@ -55973,7 +56390,7 @@ package org.apache.http.impl.conn { field protected volatile org.apache.http.conn.routing.RouteTracker tracker; } - public abstract class AbstractPooledConnAdapter extends org.apache.http.impl.conn.AbstractClientConnAdapter { + public abstract deprecated class AbstractPooledConnAdapter extends org.apache.http.impl.conn.AbstractClientConnAdapter { ctor protected AbstractPooledConnAdapter(org.apache.http.conn.ClientConnectionManager, org.apache.http.impl.conn.AbstractPoolEntry); method protected final void assertAttached(); method public void close() throws java.io.IOException; @@ -55988,7 +56405,7 @@ package org.apache.http.impl.conn { field protected volatile org.apache.http.impl.conn.AbstractPoolEntry poolEntry; } - public class DefaultClientConnection extends org.apache.http.impl.SocketHttpClientConnection implements org.apache.http.conn.OperatedClientConnection { + public deprecated class DefaultClientConnection extends org.apache.http.impl.SocketHttpClientConnection implements org.apache.http.conn.OperatedClientConnection { ctor public DefaultClientConnection(); method public final java.net.Socket getSocket(); method public final org.apache.http.HttpHost getTargetHost(); @@ -55998,7 +56415,7 @@ package org.apache.http.impl.conn { method public void update(java.net.Socket, org.apache.http.HttpHost, boolean, org.apache.http.params.HttpParams) throws java.io.IOException; } - public class DefaultClientConnectionOperator implements org.apache.http.conn.ClientConnectionOperator { + public deprecated class DefaultClientConnectionOperator implements org.apache.http.conn.ClientConnectionOperator { ctor public DefaultClientConnectionOperator(org.apache.http.conn.scheme.SchemeRegistry); method public org.apache.http.conn.OperatedClientConnection createConnection(); method public void openConnection(org.apache.http.conn.OperatedClientConnection, org.apache.http.HttpHost, java.net.InetAddress, org.apache.http.protocol.HttpContext, org.apache.http.params.HttpParams) throws java.io.IOException; @@ -56007,18 +56424,18 @@ package org.apache.http.impl.conn { field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry; } - public class DefaultHttpRoutePlanner implements org.apache.http.conn.routing.HttpRoutePlanner { + public deprecated class DefaultHttpRoutePlanner implements org.apache.http.conn.routing.HttpRoutePlanner { ctor public DefaultHttpRoutePlanner(org.apache.http.conn.scheme.SchemeRegistry); method public org.apache.http.conn.routing.HttpRoute determineRoute(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException; field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry; } - public class DefaultResponseParser extends org.apache.http.impl.io.AbstractMessageParser { + public deprecated class DefaultResponseParser extends org.apache.http.impl.io.AbstractMessageParser { ctor public DefaultResponseParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpResponseFactory, org.apache.http.params.HttpParams); method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException; } - public class IdleConnectionHandler { + public deprecated class IdleConnectionHandler { ctor public IdleConnectionHandler(); method public void add(org.apache.http.HttpConnection, long, java.util.concurrent.TimeUnit); method public void closeExpiredConnections(); @@ -56027,7 +56444,7 @@ package org.apache.http.impl.conn { method public void removeAll(); } - public class LoggingSessionInputBuffer implements org.apache.http.io.SessionInputBuffer { + public deprecated class LoggingSessionInputBuffer implements org.apache.http.io.SessionInputBuffer { ctor public LoggingSessionInputBuffer(org.apache.http.io.SessionInputBuffer, org.apache.http.impl.conn.Wire); method public org.apache.http.io.HttpTransportMetrics getMetrics(); method public boolean isDataAvailable(int) throws java.io.IOException; @@ -56038,7 +56455,7 @@ package org.apache.http.impl.conn { method public int readLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException; } - public class LoggingSessionOutputBuffer implements org.apache.http.io.SessionOutputBuffer { + public deprecated class LoggingSessionOutputBuffer implements org.apache.http.io.SessionOutputBuffer { ctor public LoggingSessionOutputBuffer(org.apache.http.io.SessionOutputBuffer, org.apache.http.impl.conn.Wire); method public void flush() throws java.io.IOException; method public org.apache.http.io.HttpTransportMetrics getMetrics(); @@ -56049,7 +56466,7 @@ package org.apache.http.impl.conn { method public void writeLine(java.lang.String) throws java.io.IOException; } - public class ProxySelectorRoutePlanner implements org.apache.http.conn.routing.HttpRoutePlanner { + public deprecated class ProxySelectorRoutePlanner implements org.apache.http.conn.routing.HttpRoutePlanner { ctor public ProxySelectorRoutePlanner(org.apache.http.conn.scheme.SchemeRegistry, java.net.ProxySelector); method protected java.net.Proxy chooseProxy(java.util.List<java.net.Proxy>, org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext); method protected org.apache.http.HttpHost determineProxy(org.apache.http.HttpHost, org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException; @@ -56061,7 +56478,7 @@ package org.apache.http.impl.conn { field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry; } - public class SingleClientConnManager implements org.apache.http.conn.ClientConnectionManager { + public deprecated class SingleClientConnManager implements org.apache.http.conn.ClientConnectionManager { ctor public SingleClientConnManager(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry); method protected final void assertStillUp() throws java.lang.IllegalStateException; method public void closeExpiredConnections(); @@ -56094,7 +56511,7 @@ package org.apache.http.impl.conn { method protected void shutdown() throws java.io.IOException; } - public class Wire { + public deprecated class Wire { ctor public Wire(org.apache.commons.logging.Log); method public boolean enabled(); method public void input(java.io.InputStream) throws java.io.IOException; @@ -56113,7 +56530,7 @@ package org.apache.http.impl.conn { package org.apache.http.impl.conn.tsccm { - public abstract class AbstractConnPool implements org.apache.http.impl.conn.tsccm.RefQueueHandler { + public abstract deprecated class AbstractConnPool implements org.apache.http.impl.conn.tsccm.RefQueueHandler { ctor protected AbstractConnPool(); method protected void closeConnection(org.apache.http.conn.OperatedClientConnection); method public void closeExpiredConnections(); @@ -56128,30 +56545,30 @@ package org.apache.http.impl.conn.tsccm { method public void shutdown(); field protected org.apache.http.impl.conn.IdleConnectionHandler idleConnHandler; field protected volatile boolean isShutDown; - field protected java.util.Set issuedConnections; + field protected java.util.Set<org.apache.http.impl.conn.tsccm.BasicPoolEntryRef> issuedConnections; field protected int numConnections; field protected final java.util.concurrent.locks.Lock poolLock; - field protected java.lang.ref.ReferenceQueue refQueue; + field protected java.lang.ref.ReferenceQueue<java.lang.Object> refQueue; } - public class BasicPoolEntry extends org.apache.http.impl.conn.AbstractPoolEntry { + public deprecated class BasicPoolEntry extends org.apache.http.impl.conn.AbstractPoolEntry { ctor public BasicPoolEntry(org.apache.http.conn.ClientConnectionOperator, org.apache.http.conn.routing.HttpRoute, java.lang.ref.ReferenceQueue<java.lang.Object>); method protected final org.apache.http.conn.OperatedClientConnection getConnection(); method protected final org.apache.http.conn.routing.HttpRoute getPlannedRoute(); method protected final org.apache.http.impl.conn.tsccm.BasicPoolEntryRef getWeakRef(); } - public class BasicPoolEntryRef extends java.lang.ref.WeakReference { + public deprecated class BasicPoolEntryRef extends java.lang.ref.WeakReference { ctor public BasicPoolEntryRef(org.apache.http.impl.conn.tsccm.BasicPoolEntry, java.lang.ref.ReferenceQueue<java.lang.Object>); method public final org.apache.http.conn.routing.HttpRoute getRoute(); } - public class BasicPooledConnAdapter extends org.apache.http.impl.conn.AbstractPooledConnAdapter { + public deprecated class BasicPooledConnAdapter extends org.apache.http.impl.conn.AbstractPooledConnAdapter { ctor protected BasicPooledConnAdapter(org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager, org.apache.http.impl.conn.AbstractPoolEntry); method protected org.apache.http.impl.conn.AbstractPoolEntry getPoolEntry(); } - public class ConnPoolByRoute extends org.apache.http.impl.conn.tsccm.AbstractConnPool { + public deprecated class ConnPoolByRoute extends org.apache.http.impl.conn.tsccm.AbstractConnPool { ctor public ConnPoolByRoute(org.apache.http.conn.ClientConnectionOperator, org.apache.http.params.HttpParams); method protected org.apache.http.impl.conn.tsccm.BasicPoolEntry createEntry(org.apache.http.impl.conn.tsccm.RouteSpecificPool, org.apache.http.conn.ClientConnectionOperator); method protected java.util.Queue<org.apache.http.impl.conn.tsccm.BasicPoolEntry> createFreeConnQueue(); @@ -56170,32 +56587,32 @@ package org.apache.http.impl.conn.tsccm { method protected org.apache.http.impl.conn.tsccm.WaitingThread newWaitingThread(java.util.concurrent.locks.Condition, org.apache.http.impl.conn.tsccm.RouteSpecificPool); method protected void notifyWaitingThread(org.apache.http.impl.conn.tsccm.RouteSpecificPool); method public org.apache.http.impl.conn.tsccm.PoolEntryRequest requestPoolEntry(org.apache.http.conn.routing.HttpRoute, java.lang.Object); - field protected java.util.Queue freeConnections; + field protected java.util.Queue<org.apache.http.impl.conn.tsccm.BasicPoolEntry> freeConnections; field protected final int maxTotalConnections; field protected final org.apache.http.conn.ClientConnectionOperator operator; - field protected final java.util.Map routeToPool; - field protected java.util.Queue waitingThreads; + field protected final java.util.Map<org.apache.http.conn.routing.HttpRoute, org.apache.http.impl.conn.tsccm.RouteSpecificPool> routeToPool; + field protected java.util.Queue<org.apache.http.impl.conn.tsccm.WaitingThread> waitingThreads; } - public abstract interface PoolEntryRequest { + public abstract deprecated interface PoolEntryRequest { method public abstract void abortRequest(); method public abstract org.apache.http.impl.conn.tsccm.BasicPoolEntry getPoolEntry(long, java.util.concurrent.TimeUnit) throws org.apache.http.conn.ConnectionPoolTimeoutException, java.lang.InterruptedException; } - public abstract interface RefQueueHandler { + public abstract deprecated interface RefQueueHandler { method public abstract void handleReference(java.lang.ref.Reference<?>); } - public class RefQueueWorker implements java.lang.Runnable { + public deprecated class RefQueueWorker implements java.lang.Runnable { ctor public RefQueueWorker(java.lang.ref.ReferenceQueue<?>, org.apache.http.impl.conn.tsccm.RefQueueHandler); method public void run(); method public void shutdown(); field protected final org.apache.http.impl.conn.tsccm.RefQueueHandler refHandler; - field protected final java.lang.ref.ReferenceQueue refQueue; + field protected final java.lang.ref.ReferenceQueue<?> refQueue; field protected volatile java.lang.Thread workerThread; } - public class RouteSpecificPool { + public deprecated class RouteSpecificPool { ctor public RouteSpecificPool(org.apache.http.conn.routing.HttpRoute, int); method public org.apache.http.impl.conn.tsccm.BasicPoolEntry allocEntry(java.lang.Object); method public void createdEntry(org.apache.http.impl.conn.tsccm.BasicPoolEntry); @@ -56211,14 +56628,14 @@ package org.apache.http.impl.conn.tsccm { method public org.apache.http.impl.conn.tsccm.WaitingThread nextThread(); method public void queueThread(org.apache.http.impl.conn.tsccm.WaitingThread); method public void removeThread(org.apache.http.impl.conn.tsccm.WaitingThread); - field protected final java.util.LinkedList freeEntries; + field protected final java.util.LinkedList<org.apache.http.impl.conn.tsccm.BasicPoolEntry> freeEntries; field protected final int maxEntries; field protected int numEntries; field protected final org.apache.http.conn.routing.HttpRoute route; - field protected final java.util.Queue waitingThreads; + field protected final java.util.Queue<org.apache.http.impl.conn.tsccm.WaitingThread> waitingThreads; } - public class ThreadSafeClientConnManager implements org.apache.http.conn.ClientConnectionManager { + public deprecated class ThreadSafeClientConnManager implements org.apache.http.conn.ClientConnectionManager { ctor public ThreadSafeClientConnManager(org.apache.http.params.HttpParams, org.apache.http.conn.scheme.SchemeRegistry); method public void closeExpiredConnections(); method public void closeIdleConnections(long, java.util.concurrent.TimeUnit); @@ -56235,7 +56652,7 @@ package org.apache.http.impl.conn.tsccm { field protected org.apache.http.conn.scheme.SchemeRegistry schemeRegistry; } - public class WaitingThread { + public deprecated class WaitingThread { ctor public WaitingThread(java.util.concurrent.locks.Condition, org.apache.http.impl.conn.tsccm.RouteSpecificPool); method public boolean await(java.util.Date) throws java.lang.InterruptedException; method public final java.util.concurrent.locks.Condition getCondition(); @@ -56245,7 +56662,7 @@ package org.apache.http.impl.conn.tsccm { method public void wakeup(); } - public class WaitingThreadAborter { + public deprecated class WaitingThreadAborter { ctor public WaitingThreadAborter(); method public void abort(); method public void setWaitingThread(org.apache.http.impl.conn.tsccm.WaitingThread); @@ -56255,13 +56672,13 @@ package org.apache.http.impl.conn.tsccm { package org.apache.http.impl.cookie { - public abstract class AbstractCookieAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { + public abstract deprecated class AbstractCookieAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public AbstractCookieAttributeHandler(); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public abstract class AbstractCookieSpec implements org.apache.http.cookie.CookieSpec { + public abstract deprecated class AbstractCookieSpec implements org.apache.http.cookie.CookieSpec { ctor public AbstractCookieSpec(); method protected org.apache.http.cookie.CookieAttributeHandler findAttribHandler(java.lang.String); method protected org.apache.http.cookie.CookieAttributeHandler getAttribHandler(java.lang.String); @@ -56269,7 +56686,7 @@ package org.apache.http.impl.cookie { method public void registerAttribHandler(java.lang.String, org.apache.http.cookie.CookieAttributeHandler); } - public class BasicClientCookie implements org.apache.http.cookie.ClientCookie java.lang.Cloneable org.apache.http.cookie.SetCookie { + public deprecated class BasicClientCookie implements org.apache.http.cookie.ClientCookie java.lang.Cloneable org.apache.http.cookie.SetCookie { ctor public BasicClientCookie(java.lang.String, java.lang.String); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public boolean containsAttribute(java.lang.String); @@ -56296,48 +56713,48 @@ package org.apache.http.impl.cookie { method public void setVersion(int); } - public class BasicClientCookie2 extends org.apache.http.impl.cookie.BasicClientCookie implements org.apache.http.cookie.SetCookie2 { + public deprecated class BasicClientCookie2 extends org.apache.http.impl.cookie.BasicClientCookie implements org.apache.http.cookie.SetCookie2 { ctor public BasicClientCookie2(java.lang.String, java.lang.String); method public void setCommentURL(java.lang.String); method public void setDiscard(boolean); method public void setPorts(int[]); } - public class BasicCommentHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { + public deprecated class BasicCommentHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { ctor public BasicCommentHandler(); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; } - public class BasicDomainHandler implements org.apache.http.cookie.CookieAttributeHandler { + public deprecated class BasicDomainHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public BasicDomainHandler(); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class BasicExpiresHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { + public deprecated class BasicExpiresHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { ctor public BasicExpiresHandler(java.lang.String[]); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; } - public class BasicMaxAgeHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { + public deprecated class BasicMaxAgeHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { ctor public BasicMaxAgeHandler(); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; } - public class BasicPathHandler implements org.apache.http.cookie.CookieAttributeHandler { + public deprecated class BasicPathHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public BasicPathHandler(); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class BasicSecureHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { + public deprecated class BasicSecureHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { ctor public BasicSecureHandler(); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; } - public class BestMatchSpec implements org.apache.http.cookie.CookieSpec { + public deprecated class BestMatchSpec implements org.apache.http.cookie.CookieSpec { ctor public BestMatchSpec(java.lang.String[], boolean); ctor public BestMatchSpec(); method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>); @@ -56348,12 +56765,12 @@ package org.apache.http.impl.cookie { method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class BestMatchSpecFactory implements org.apache.http.cookie.CookieSpecFactory { + public deprecated class BestMatchSpecFactory implements org.apache.http.cookie.CookieSpecFactory { ctor public BestMatchSpecFactory(); method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams); } - public class BrowserCompatSpec extends org.apache.http.impl.cookie.CookieSpecBase { + public deprecated class BrowserCompatSpec extends org.apache.http.impl.cookie.CookieSpecBase { ctor public BrowserCompatSpec(java.lang.String[]); ctor public BrowserCompatSpec(); method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>); @@ -56363,12 +56780,12 @@ package org.apache.http.impl.cookie { field protected static final java.lang.String[] DATE_PATTERNS; } - public class BrowserCompatSpecFactory implements org.apache.http.cookie.CookieSpecFactory { + public deprecated class BrowserCompatSpecFactory implements org.apache.http.cookie.CookieSpecFactory { ctor public BrowserCompatSpecFactory(); method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams); } - public abstract class CookieSpecBase extends org.apache.http.impl.cookie.AbstractCookieSpec { + public abstract deprecated class CookieSpecBase extends org.apache.http.impl.cookie.AbstractCookieSpec { ctor public CookieSpecBase(); method protected static java.lang.String getDefaultDomain(org.apache.http.cookie.CookieOrigin); method protected static java.lang.String getDefaultPath(org.apache.http.cookie.CookieOrigin); @@ -56377,12 +56794,12 @@ package org.apache.http.impl.cookie { method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class DateParseException extends java.lang.Exception { + public deprecated class DateParseException extends java.lang.Exception { ctor public DateParseException(); ctor public DateParseException(java.lang.String); } - public final class DateUtils { + public final deprecated class DateUtils { method public static java.lang.String formatDate(java.util.Date); method public static java.lang.String formatDate(java.util.Date, java.lang.String); method public static java.util.Date parseDate(java.lang.String) throws org.apache.http.impl.cookie.DateParseException; @@ -56394,17 +56811,17 @@ package org.apache.http.impl.cookie { field public static final java.lang.String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; } - public class NetscapeDomainHandler extends org.apache.http.impl.cookie.BasicDomainHandler { + public deprecated class NetscapeDomainHandler extends org.apache.http.impl.cookie.BasicDomainHandler { ctor public NetscapeDomainHandler(); } - public class NetscapeDraftHeaderParser { + public deprecated class NetscapeDraftHeaderParser { ctor public NetscapeDraftHeaderParser(); method public org.apache.http.HeaderElement parseHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException; field public static final org.apache.http.impl.cookie.NetscapeDraftHeaderParser DEFAULT; } - public class NetscapeDraftSpec extends org.apache.http.impl.cookie.CookieSpecBase { + public deprecated class NetscapeDraftSpec extends org.apache.http.impl.cookie.CookieSpecBase { ctor public NetscapeDraftSpec(java.lang.String[]); ctor public NetscapeDraftSpec(); method public java.util.List<org.apache.http.Header> formatCookies(java.util.List<org.apache.http.cookie.Cookie>); @@ -56414,19 +56831,19 @@ package org.apache.http.impl.cookie { field protected static final java.lang.String EXPIRES_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z"; } - public class NetscapeDraftSpecFactory implements org.apache.http.cookie.CookieSpecFactory { + public deprecated class NetscapeDraftSpecFactory implements org.apache.http.cookie.CookieSpecFactory { ctor public NetscapeDraftSpecFactory(); method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams); } - public class RFC2109DomainHandler implements org.apache.http.cookie.CookieAttributeHandler { + public deprecated class RFC2109DomainHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public RFC2109DomainHandler(); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class RFC2109Spec extends org.apache.http.impl.cookie.CookieSpecBase { + public deprecated class RFC2109Spec extends org.apache.http.impl.cookie.CookieSpecBase { ctor public RFC2109Spec(java.lang.String[], boolean); ctor public RFC2109Spec(); method protected void formatCookieAsVer(org.apache.http.util.CharArrayBuffer, org.apache.http.cookie.Cookie, int); @@ -56437,31 +56854,31 @@ package org.apache.http.impl.cookie { method public java.util.List<org.apache.http.cookie.Cookie> parse(org.apache.http.Header, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class RFC2109SpecFactory implements org.apache.http.cookie.CookieSpecFactory { + public deprecated class RFC2109SpecFactory implements org.apache.http.cookie.CookieSpecFactory { ctor public RFC2109SpecFactory(); method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams); } - public class RFC2109VersionHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { + public deprecated class RFC2109VersionHandler extends org.apache.http.impl.cookie.AbstractCookieAttributeHandler { ctor public RFC2109VersionHandler(); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; } - public class RFC2965CommentUrlAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { + public deprecated class RFC2965CommentUrlAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public RFC2965CommentUrlAttributeHandler(); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class RFC2965DiscardAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { + public deprecated class RFC2965DiscardAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public RFC2965DiscardAttributeHandler(); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class RFC2965DomainAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { + public deprecated class RFC2965DomainAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public RFC2965DomainAttributeHandler(); method public boolean domainMatch(java.lang.String, java.lang.String); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); @@ -56469,24 +56886,24 @@ package org.apache.http.impl.cookie { method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class RFC2965PortAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { + public deprecated class RFC2965PortAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public RFC2965PortAttributeHandler(); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; method public void validate(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin) throws org.apache.http.cookie.MalformedCookieException; } - public class RFC2965Spec extends org.apache.http.impl.cookie.RFC2109Spec { + public deprecated class RFC2965Spec extends org.apache.http.impl.cookie.RFC2109Spec { ctor public RFC2965Spec(); ctor public RFC2965Spec(java.lang.String[], boolean); } - public class RFC2965SpecFactory implements org.apache.http.cookie.CookieSpecFactory { + public deprecated class RFC2965SpecFactory implements org.apache.http.cookie.CookieSpecFactory { ctor public RFC2965SpecFactory(); method public org.apache.http.cookie.CookieSpec newInstance(org.apache.http.params.HttpParams); } - public class RFC2965VersionAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { + public deprecated class RFC2965VersionAttributeHandler implements org.apache.http.cookie.CookieAttributeHandler { ctor public RFC2965VersionAttributeHandler(); method public boolean match(org.apache.http.cookie.Cookie, org.apache.http.cookie.CookieOrigin); method public void parse(org.apache.http.cookie.SetCookie, java.lang.String) throws org.apache.http.cookie.MalformedCookieException; @@ -56497,24 +56914,24 @@ package org.apache.http.impl.cookie { package org.apache.http.impl.entity { - public class EntityDeserializer { + public deprecated class EntityDeserializer { ctor public EntityDeserializer(org.apache.http.entity.ContentLengthStrategy); method public org.apache.http.HttpEntity deserialize(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException; method protected org.apache.http.entity.BasicHttpEntity doDeserialize(org.apache.http.io.SessionInputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException; } - public class EntitySerializer { + public deprecated class EntitySerializer { ctor public EntitySerializer(org.apache.http.entity.ContentLengthStrategy); method protected java.io.OutputStream doSerialize(org.apache.http.io.SessionOutputBuffer, org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException; method public void serialize(org.apache.http.io.SessionOutputBuffer, org.apache.http.HttpMessage, org.apache.http.HttpEntity) throws org.apache.http.HttpException, java.io.IOException; } - public class LaxContentLengthStrategy implements org.apache.http.entity.ContentLengthStrategy { + public deprecated class LaxContentLengthStrategy implements org.apache.http.entity.ContentLengthStrategy { ctor public LaxContentLengthStrategy(); method public long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException; } - public class StrictContentLengthStrategy implements org.apache.http.entity.ContentLengthStrategy { + public deprecated class StrictContentLengthStrategy implements org.apache.http.entity.ContentLengthStrategy { ctor public StrictContentLengthStrategy(); method public long determineLength(org.apache.http.HttpMessage) throws org.apache.http.HttpException; } @@ -56523,7 +56940,7 @@ package org.apache.http.impl.entity { package org.apache.http.impl.io { - public abstract class AbstractMessageParser implements org.apache.http.io.HttpMessageParser { + public abstract deprecated class AbstractMessageParser implements org.apache.http.io.HttpMessageParser { ctor public AbstractMessageParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.params.HttpParams); method public org.apache.http.HttpMessage parse() throws org.apache.http.HttpException, java.io.IOException; method protected abstract org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException; @@ -56531,7 +56948,7 @@ package org.apache.http.impl.io { field protected final org.apache.http.message.LineParser lineParser; } - public abstract class AbstractMessageWriter implements org.apache.http.io.HttpMessageWriter { + public abstract deprecated class AbstractMessageWriter implements org.apache.http.io.HttpMessageWriter { ctor public AbstractMessageWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams); method public void write(org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException; method protected abstract void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException; @@ -56540,7 +56957,7 @@ package org.apache.http.impl.io { field protected final org.apache.http.io.SessionOutputBuffer sessionBuffer; } - public abstract class AbstractSessionInputBuffer implements org.apache.http.io.SessionInputBuffer { + public abstract deprecated class AbstractSessionInputBuffer implements org.apache.http.io.SessionInputBuffer { ctor public AbstractSessionInputBuffer(); method protected int fillBuffer() throws java.io.IOException; method public org.apache.http.io.HttpTransportMetrics getMetrics(); @@ -56553,7 +56970,7 @@ package org.apache.http.impl.io { method public java.lang.String readLine() throws java.io.IOException; } - public abstract class AbstractSessionOutputBuffer implements org.apache.http.io.SessionOutputBuffer { + public abstract deprecated class AbstractSessionOutputBuffer implements org.apache.http.io.SessionOutputBuffer { ctor public AbstractSessionOutputBuffer(); method public void flush() throws java.io.IOException; method protected void flushBuffer() throws java.io.IOException; @@ -56566,13 +56983,13 @@ package org.apache.http.impl.io { method public void writeLine(org.apache.http.util.CharArrayBuffer) throws java.io.IOException; } - public class ChunkedInputStream extends java.io.InputStream { + public deprecated class ChunkedInputStream extends java.io.InputStream { ctor public ChunkedInputStream(org.apache.http.io.SessionInputBuffer); method public org.apache.http.Header[] getFooters(); method public int read() throws java.io.IOException; } - public class ChunkedOutputStream extends java.io.OutputStream { + public deprecated class ChunkedOutputStream extends java.io.OutputStream { ctor public ChunkedOutputStream(org.apache.http.io.SessionOutputBuffer, int) throws java.io.IOException; ctor public ChunkedOutputStream(org.apache.http.io.SessionOutputBuffer) throws java.io.IOException; method public void finish() throws java.io.IOException; @@ -56582,37 +56999,37 @@ package org.apache.http.impl.io { method protected void writeClosingChunk() throws java.io.IOException; } - public class ContentLengthInputStream extends java.io.InputStream { + public deprecated class ContentLengthInputStream extends java.io.InputStream { ctor public ContentLengthInputStream(org.apache.http.io.SessionInputBuffer, long); method public int read() throws java.io.IOException; } - public class ContentLengthOutputStream extends java.io.OutputStream { + public deprecated class ContentLengthOutputStream extends java.io.OutputStream { ctor public ContentLengthOutputStream(org.apache.http.io.SessionOutputBuffer, long); method public void write(int) throws java.io.IOException; } - public class HttpRequestParser extends org.apache.http.impl.io.AbstractMessageParser { + public deprecated class HttpRequestParser extends org.apache.http.impl.io.AbstractMessageParser { ctor public HttpRequestParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpRequestFactory, org.apache.http.params.HttpParams); method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException; } - public class HttpRequestWriter extends org.apache.http.impl.io.AbstractMessageWriter { + public deprecated class HttpRequestWriter extends org.apache.http.impl.io.AbstractMessageWriter { ctor public HttpRequestWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams); method protected void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException; } - public class HttpResponseParser extends org.apache.http.impl.io.AbstractMessageParser { + public deprecated class HttpResponseParser extends org.apache.http.impl.io.AbstractMessageParser { ctor public HttpResponseParser(org.apache.http.io.SessionInputBuffer, org.apache.http.message.LineParser, org.apache.http.HttpResponseFactory, org.apache.http.params.HttpParams); method protected org.apache.http.HttpMessage parseHead(org.apache.http.io.SessionInputBuffer) throws org.apache.http.HttpException, java.io.IOException, org.apache.http.ParseException; } - public class HttpResponseWriter extends org.apache.http.impl.io.AbstractMessageWriter { + public deprecated class HttpResponseWriter extends org.apache.http.impl.io.AbstractMessageWriter { ctor public HttpResponseWriter(org.apache.http.io.SessionOutputBuffer, org.apache.http.message.LineFormatter, org.apache.http.params.HttpParams); method protected void writeHeadLine(org.apache.http.HttpMessage) throws java.io.IOException; } - public class HttpTransportMetricsImpl implements org.apache.http.io.HttpTransportMetrics { + public deprecated class HttpTransportMetricsImpl implements org.apache.http.io.HttpTransportMetrics { ctor public HttpTransportMetricsImpl(); method public long getBytesTransferred(); method public void incrementBytesTransferred(long); @@ -56620,22 +57037,22 @@ package org.apache.http.impl.io { method public void setBytesTransferred(long); } - public class IdentityInputStream extends java.io.InputStream { + public deprecated class IdentityInputStream extends java.io.InputStream { ctor public IdentityInputStream(org.apache.http.io.SessionInputBuffer); method public int read() throws java.io.IOException; } - public class IdentityOutputStream extends java.io.OutputStream { + public deprecated class IdentityOutputStream extends java.io.OutputStream { ctor public IdentityOutputStream(org.apache.http.io.SessionOutputBuffer); method public void write(int) throws java.io.IOException; } - public class SocketInputBuffer extends org.apache.http.impl.io.AbstractSessionInputBuffer { + public deprecated class SocketInputBuffer extends org.apache.http.impl.io.AbstractSessionInputBuffer { ctor public SocketInputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException; method public boolean isDataAvailable(int) throws java.io.IOException; } - public class SocketOutputBuffer extends org.apache.http.impl.io.AbstractSessionOutputBuffer { + public deprecated class SocketOutputBuffer extends org.apache.http.impl.io.AbstractSessionOutputBuffer { ctor public SocketOutputBuffer(java.net.Socket, int, org.apache.http.params.HttpParams) throws java.io.IOException; } @@ -56643,20 +57060,20 @@ package org.apache.http.impl.io { package org.apache.http.io { - public abstract interface HttpMessageParser { + public abstract deprecated interface HttpMessageParser { method public abstract org.apache.http.HttpMessage parse() throws org.apache.http.HttpException, java.io.IOException; } - public abstract interface HttpMessageWriter { + public abstract deprecated interface HttpMessageWriter { method public abstract void write(org.apache.http.HttpMessage) throws org.apache.http.HttpException, java.io.IOException; } - public abstract interface HttpTransportMetrics { + public abstract deprecated interface HttpTransportMetrics { method public abstract long getBytesTransferred(); method public abstract void reset(); } - public abstract interface SessionInputBuffer { + public abstract deprecated interface SessionInputBuffer { method public abstract org.apache.http.io.HttpTransportMetrics getMetrics(); method public abstract boolean isDataAvailable(int) throws java.io.IOException; method public abstract int read(byte[], int, int) throws java.io.IOException; @@ -56666,7 +57083,7 @@ package org.apache.http.io { method public abstract java.lang.String readLine() throws java.io.IOException; } - public abstract interface SessionOutputBuffer { + public abstract deprecated interface SessionOutputBuffer { method public abstract void flush() throws java.io.IOException; method public abstract org.apache.http.io.HttpTransportMetrics getMetrics(); method public abstract void write(byte[], int, int) throws java.io.IOException; @@ -56680,7 +57097,7 @@ package org.apache.http.io { package org.apache.http.message { - public abstract class AbstractHttpMessage implements org.apache.http.HttpMessage { + public abstract deprecated class AbstractHttpMessage implements org.apache.http.HttpMessage { ctor protected AbstractHttpMessage(org.apache.http.params.HttpParams); ctor protected AbstractHttpMessage(); method public void addHeader(org.apache.http.Header); @@ -56703,7 +57120,7 @@ package org.apache.http.message { field protected org.apache.http.params.HttpParams params; } - public class BasicHeader implements java.lang.Cloneable org.apache.http.Header { + public deprecated class BasicHeader implements java.lang.Cloneable org.apache.http.Header { ctor public BasicHeader(java.lang.String, java.lang.String); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public org.apache.http.HeaderElement[] getElements() throws org.apache.http.ParseException; @@ -56711,7 +57128,7 @@ package org.apache.http.message { method public java.lang.String getValue(); } - public class BasicHeaderElement implements java.lang.Cloneable org.apache.http.HeaderElement { + public deprecated class BasicHeaderElement implements java.lang.Cloneable org.apache.http.HeaderElement { ctor public BasicHeaderElement(java.lang.String, java.lang.String, org.apache.http.NameValuePair[]); ctor public BasicHeaderElement(java.lang.String, java.lang.String); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; @@ -56723,7 +57140,7 @@ package org.apache.http.message { method public java.lang.String getValue(); } - public class BasicHeaderElementIterator implements org.apache.http.HeaderElementIterator { + public deprecated class BasicHeaderElementIterator implements org.apache.http.HeaderElementIterator { ctor public BasicHeaderElementIterator(org.apache.http.HeaderIterator, org.apache.http.message.HeaderValueParser); ctor public BasicHeaderElementIterator(org.apache.http.HeaderIterator); method public boolean hasNext(); @@ -56732,7 +57149,7 @@ package org.apache.http.message { method public void remove() throws java.lang.UnsupportedOperationException; } - public class BasicHeaderIterator implements org.apache.http.HeaderIterator { + public deprecated class BasicHeaderIterator implements org.apache.http.HeaderIterator { ctor public BasicHeaderIterator(org.apache.http.Header[], java.lang.String); method protected boolean filterHeader(int); method protected int findNext(int); @@ -56745,7 +57162,7 @@ package org.apache.http.message { field protected java.lang.String headerName; } - public class BasicHeaderValueFormatter implements org.apache.http.message.HeaderValueFormatter { + public deprecated class BasicHeaderValueFormatter implements org.apache.http.message.HeaderValueFormatter { ctor public BasicHeaderValueFormatter(); method protected void doFormatValue(org.apache.http.util.CharArrayBuffer, java.lang.String, boolean); method protected int estimateElementsLen(org.apache.http.HeaderElement[]); @@ -56767,7 +57184,7 @@ package org.apache.http.message { field public static final java.lang.String UNSAFE_CHARS = "\"\\"; } - public class BasicHeaderValueParser implements org.apache.http.message.HeaderValueParser { + public deprecated class BasicHeaderValueParser implements org.apache.http.message.HeaderValueParser { ctor public BasicHeaderValueParser(); method protected org.apache.http.HeaderElement createHeaderElement(java.lang.String, java.lang.String, org.apache.http.NameValuePair[]); method protected org.apache.http.NameValuePair createNameValuePair(java.lang.String, java.lang.String); @@ -56783,7 +57200,7 @@ package org.apache.http.message { field public static final org.apache.http.message.BasicHeaderValueParser DEFAULT; } - public class BasicHttpEntityEnclosingRequest extends org.apache.http.message.BasicHttpRequest implements org.apache.http.HttpEntityEnclosingRequest { + public deprecated class BasicHttpEntityEnclosingRequest extends org.apache.http.message.BasicHttpRequest implements org.apache.http.HttpEntityEnclosingRequest { ctor public BasicHttpEntityEnclosingRequest(java.lang.String, java.lang.String); ctor public BasicHttpEntityEnclosingRequest(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion); ctor public BasicHttpEntityEnclosingRequest(org.apache.http.RequestLine); @@ -56792,7 +57209,7 @@ package org.apache.http.message { method public void setEntity(org.apache.http.HttpEntity); } - public class BasicHttpRequest extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.HttpRequest { + public deprecated class BasicHttpRequest extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.HttpRequest { ctor public BasicHttpRequest(java.lang.String, java.lang.String); ctor public BasicHttpRequest(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion); ctor public BasicHttpRequest(org.apache.http.RequestLine); @@ -56800,7 +57217,7 @@ package org.apache.http.message { method public org.apache.http.RequestLine getRequestLine(); } - public class BasicHttpResponse extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.HttpResponse { + public deprecated class BasicHttpResponse extends org.apache.http.message.AbstractHttpMessage implements org.apache.http.HttpResponse { ctor public BasicHttpResponse(org.apache.http.StatusLine, org.apache.http.ReasonPhraseCatalog, java.util.Locale); ctor public BasicHttpResponse(org.apache.http.StatusLine); ctor public BasicHttpResponse(org.apache.http.ProtocolVersion, int, java.lang.String); @@ -56818,7 +57235,7 @@ package org.apache.http.message { method public void setStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String); } - public class BasicLineFormatter implements org.apache.http.message.LineFormatter { + public deprecated class BasicLineFormatter implements org.apache.http.message.LineFormatter { ctor public BasicLineFormatter(); method public org.apache.http.util.CharArrayBuffer appendProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.ProtocolVersion); method protected void doFormatHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.Header); @@ -56836,7 +57253,7 @@ package org.apache.http.message { field public static final org.apache.http.message.BasicLineFormatter DEFAULT; } - public class BasicLineParser implements org.apache.http.message.LineParser { + public deprecated class BasicLineParser implements org.apache.http.message.LineParser { ctor public BasicLineParser(org.apache.http.ProtocolVersion); ctor public BasicLineParser(); method protected org.apache.http.ProtocolVersion createProtocolVersion(int, int); @@ -56856,7 +57273,7 @@ package org.apache.http.message { field protected final org.apache.http.ProtocolVersion protocol; } - public class BasicListHeaderIterator implements org.apache.http.HeaderIterator { + public deprecated class BasicListHeaderIterator implements org.apache.http.HeaderIterator { ctor public BasicListHeaderIterator(java.util.List, java.lang.String); method protected boolean filterHeader(int); method protected int findNext(int); @@ -56870,14 +57287,14 @@ package org.apache.http.message { field protected int lastIndex; } - public class BasicNameValuePair implements java.lang.Cloneable org.apache.http.NameValuePair { + public deprecated class BasicNameValuePair implements java.lang.Cloneable org.apache.http.NameValuePair { ctor public BasicNameValuePair(java.lang.String, java.lang.String); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public java.lang.String getName(); method public java.lang.String getValue(); } - public class BasicRequestLine implements java.lang.Cloneable org.apache.http.RequestLine { + public deprecated class BasicRequestLine implements java.lang.Cloneable org.apache.http.RequestLine { ctor public BasicRequestLine(java.lang.String, java.lang.String, org.apache.http.ProtocolVersion); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public java.lang.String getMethod(); @@ -56885,7 +57302,7 @@ package org.apache.http.message { method public java.lang.String getUri(); } - public class BasicStatusLine implements java.lang.Cloneable org.apache.http.StatusLine { + public deprecated class BasicStatusLine implements java.lang.Cloneable org.apache.http.StatusLine { ctor public BasicStatusLine(org.apache.http.ProtocolVersion, int, java.lang.String); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public org.apache.http.ProtocolVersion getProtocolVersion(); @@ -56893,7 +57310,7 @@ package org.apache.http.message { method public int getStatusCode(); } - public class BasicTokenIterator implements org.apache.http.TokenIterator { + public deprecated class BasicTokenIterator implements org.apache.http.TokenIterator { ctor public BasicTokenIterator(org.apache.http.HeaderIterator); method protected java.lang.String createToken(java.lang.String, int, int); method protected int findNext(int) throws org.apache.http.ParseException; @@ -56915,7 +57332,7 @@ package org.apache.http.message { field protected int searchPos; } - public class BufferedHeader implements java.lang.Cloneable org.apache.http.FormattedHeader { + public deprecated class BufferedHeader implements java.lang.Cloneable org.apache.http.FormattedHeader { ctor public BufferedHeader(org.apache.http.util.CharArrayBuffer) throws org.apache.http.ParseException; method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; method public org.apache.http.util.CharArrayBuffer getBuffer(); @@ -56925,7 +57342,7 @@ package org.apache.http.message { method public int getValuePos(); } - public class HeaderGroup implements java.lang.Cloneable { + public deprecated class HeaderGroup implements java.lang.Cloneable { ctor public HeaderGroup(); method public void addHeader(org.apache.http.Header); method public void clear(); @@ -56944,28 +57361,28 @@ package org.apache.http.message { method public void updateHeader(org.apache.http.Header); } - public abstract interface HeaderValueFormatter { + public abstract deprecated interface HeaderValueFormatter { method public abstract org.apache.http.util.CharArrayBuffer formatElements(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement[], boolean); method public abstract org.apache.http.util.CharArrayBuffer formatHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.HeaderElement, boolean); method public abstract org.apache.http.util.CharArrayBuffer formatNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair, boolean); method public abstract org.apache.http.util.CharArrayBuffer formatParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.NameValuePair[], boolean); } - public abstract interface HeaderValueParser { + public abstract deprecated interface HeaderValueParser { method public abstract org.apache.http.HeaderElement[] parseElements(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException; method public abstract org.apache.http.HeaderElement parseHeaderElement(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException; method public abstract org.apache.http.NameValuePair parseNameValuePair(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException; method public abstract org.apache.http.NameValuePair[] parseParameters(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException; } - public abstract interface LineFormatter { + public abstract deprecated interface LineFormatter { method public abstract org.apache.http.util.CharArrayBuffer appendProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.ProtocolVersion); method public abstract org.apache.http.util.CharArrayBuffer formatHeader(org.apache.http.util.CharArrayBuffer, org.apache.http.Header); method public abstract org.apache.http.util.CharArrayBuffer formatRequestLine(org.apache.http.util.CharArrayBuffer, org.apache.http.RequestLine); method public abstract org.apache.http.util.CharArrayBuffer formatStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.StatusLine); } - public abstract interface LineParser { + public abstract deprecated interface LineParser { method public abstract boolean hasProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor); method public abstract org.apache.http.Header parseHeader(org.apache.http.util.CharArrayBuffer) throws org.apache.http.ParseException; method public abstract org.apache.http.ProtocolVersion parseProtocolVersion(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException; @@ -56973,7 +57390,7 @@ package org.apache.http.message { method public abstract org.apache.http.StatusLine parseStatusLine(org.apache.http.util.CharArrayBuffer, org.apache.http.message.ParserCursor) throws org.apache.http.ParseException; } - public class ParserCursor { + public deprecated class ParserCursor { ctor public ParserCursor(int, int); method public boolean atEnd(); method public int getLowerBound(); @@ -56986,7 +57403,7 @@ package org.apache.http.message { package org.apache.http.params { - public abstract class AbstractHttpParams implements org.apache.http.params.HttpParams { + public abstract deprecated class AbstractHttpParams implements org.apache.http.params.HttpParams { ctor protected AbstractHttpParams(); method public boolean getBooleanParameter(java.lang.String, boolean); method public double getDoubleParameter(java.lang.String, double); @@ -57000,7 +57417,7 @@ package org.apache.http.params { method public org.apache.http.params.HttpParams setLongParameter(java.lang.String, long); } - public final class BasicHttpParams extends org.apache.http.params.AbstractHttpParams implements java.lang.Cloneable java.io.Serializable { + public final deprecated class BasicHttpParams extends org.apache.http.params.AbstractHttpParams implements java.lang.Cloneable java.io.Serializable { ctor public BasicHttpParams(); method public void clear(); method public java.lang.Object clone() throws java.lang.CloneNotSupportedException; @@ -57014,7 +57431,7 @@ package org.apache.http.params { method public void setParameters(java.lang.String[], java.lang.Object); } - public abstract interface CoreConnectionPNames { + public abstract deprecated interface CoreConnectionPNames { field public static final java.lang.String CONNECTION_TIMEOUT = "http.connection.timeout"; field public static final java.lang.String MAX_HEADER_COUNT = "http.connection.max-header-count"; field public static final java.lang.String MAX_LINE_LENGTH = "http.connection.max-line-length"; @@ -57025,7 +57442,7 @@ package org.apache.http.params { field public static final java.lang.String TCP_NODELAY = "http.tcp.nodelay"; } - public abstract interface CoreProtocolPNames { + public abstract deprecated interface CoreProtocolPNames { field public static final java.lang.String HTTP_CONTENT_CHARSET = "http.protocol.content-charset"; field public static final java.lang.String HTTP_ELEMENT_CHARSET = "http.protocol.element-charset"; field public static final java.lang.String ORIGIN_SERVER = "http.origin-server"; @@ -57036,7 +57453,7 @@ package org.apache.http.params { field public static final java.lang.String WAIT_FOR_CONTINUE = "http.protocol.wait-for-continue"; } - public final class DefaultedHttpParams extends org.apache.http.params.AbstractHttpParams { + public final deprecated class DefaultedHttpParams extends org.apache.http.params.AbstractHttpParams { ctor public DefaultedHttpParams(org.apache.http.params.HttpParams, org.apache.http.params.HttpParams); method public org.apache.http.params.HttpParams copy(); method public org.apache.http.params.HttpParams getDefaults(); @@ -57045,12 +57462,12 @@ package org.apache.http.params { method public org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object); } - public abstract class HttpAbstractParamBean { + public abstract deprecated class HttpAbstractParamBean { ctor public HttpAbstractParamBean(org.apache.http.params.HttpParams); field protected final org.apache.http.params.HttpParams params; } - public class HttpConnectionParamBean extends org.apache.http.params.HttpAbstractParamBean { + public deprecated class HttpConnectionParamBean extends org.apache.http.params.HttpAbstractParamBean { ctor public HttpConnectionParamBean(org.apache.http.params.HttpParams); method public void setConnectionTimeout(int); method public void setLinger(int); @@ -57060,7 +57477,7 @@ package org.apache.http.params { method public void setTcpNoDelay(boolean); } - public final class HttpConnectionParams implements org.apache.http.params.CoreConnectionPNames { + public final deprecated class HttpConnectionParams implements org.apache.http.params.CoreConnectionPNames { method public static int getConnectionTimeout(org.apache.http.params.HttpParams); method public static int getLinger(org.apache.http.params.HttpParams); method public static int getSoTimeout(org.apache.http.params.HttpParams); @@ -57075,7 +57492,7 @@ package org.apache.http.params { method public static void setTcpNoDelay(org.apache.http.params.HttpParams, boolean); } - public abstract interface HttpParams { + public abstract deprecated interface HttpParams { method public abstract org.apache.http.params.HttpParams copy(); method public abstract boolean getBooleanParameter(java.lang.String, boolean); method public abstract double getDoubleParameter(java.lang.String, double); @@ -57092,7 +57509,7 @@ package org.apache.http.params { method public abstract org.apache.http.params.HttpParams setParameter(java.lang.String, java.lang.Object); } - public class HttpProtocolParamBean extends org.apache.http.params.HttpAbstractParamBean { + public deprecated class HttpProtocolParamBean extends org.apache.http.params.HttpAbstractParamBean { ctor public HttpProtocolParamBean(org.apache.http.params.HttpParams); method public void setContentCharset(java.lang.String); method public void setHttpElementCharset(java.lang.String); @@ -57101,7 +57518,7 @@ package org.apache.http.params { method public void setVersion(org.apache.http.HttpVersion); } - public final class HttpProtocolParams implements org.apache.http.params.CoreProtocolPNames { + public final deprecated class HttpProtocolParams implements org.apache.http.params.CoreProtocolPNames { method public static java.lang.String getContentCharset(org.apache.http.params.HttpParams); method public static java.lang.String getHttpElementCharset(org.apache.http.params.HttpParams); method public static java.lang.String getUserAgent(org.apache.http.params.HttpParams); @@ -57118,7 +57535,7 @@ package org.apache.http.params { package org.apache.http.protocol { - public class BasicHttpContext implements org.apache.http.protocol.HttpContext { + public deprecated class BasicHttpContext implements org.apache.http.protocol.HttpContext { ctor public BasicHttpContext(); ctor public BasicHttpContext(org.apache.http.protocol.HttpContext); method public java.lang.Object getAttribute(java.lang.String); @@ -57126,7 +57543,7 @@ package org.apache.http.protocol { method public void setAttribute(java.lang.String, java.lang.Object); } - public final class BasicHttpProcessor implements java.lang.Cloneable org.apache.http.protocol.HttpProcessor org.apache.http.protocol.HttpRequestInterceptorList org.apache.http.protocol.HttpResponseInterceptorList { + public final deprecated class BasicHttpProcessor implements java.lang.Cloneable org.apache.http.protocol.HttpProcessor org.apache.http.protocol.HttpRequestInterceptorList org.apache.http.protocol.HttpResponseInterceptorList { ctor public BasicHttpProcessor(); method public final void addInterceptor(org.apache.http.HttpRequestInterceptor); method public final void addInterceptor(org.apache.http.HttpRequestInterceptor, int); @@ -57155,7 +57572,7 @@ package org.apache.http.protocol { field protected java.util.List responseInterceptors; } - public final class DefaultedHttpContext implements org.apache.http.protocol.HttpContext { + public final deprecated class DefaultedHttpContext implements org.apache.http.protocol.HttpContext { ctor public DefaultedHttpContext(org.apache.http.protocol.HttpContext, org.apache.http.protocol.HttpContext); method public java.lang.Object getAttribute(java.lang.String); method public org.apache.http.protocol.HttpContext getDefaults(); @@ -57163,7 +57580,7 @@ package org.apache.http.protocol { method public void setAttribute(java.lang.String, java.lang.Object); } - public abstract interface ExecutionContext { + public abstract deprecated interface ExecutionContext { field public static final java.lang.String HTTP_CONNECTION = "http.connection"; field public static final java.lang.String HTTP_PROXY_HOST = "http.proxy_host"; field public static final java.lang.String HTTP_REQUEST = "http.request"; @@ -57172,7 +57589,7 @@ package org.apache.http.protocol { field public static final java.lang.String HTTP_TARGET_HOST = "http.target_host"; } - public final class HTTP { + public final deprecated class HTTP { method public static boolean isWhitespace(char); field public static final java.lang.String ASCII = "ASCII"; field public static final java.lang.String CHARSET_PARAM = "; charset="; @@ -57206,28 +57623,28 @@ package org.apache.http.protocol { field public static final java.lang.String UTF_8 = "UTF-8"; } - public abstract interface HttpContext { + public abstract deprecated interface HttpContext { method public abstract java.lang.Object getAttribute(java.lang.String); method public abstract java.lang.Object removeAttribute(java.lang.String); method public abstract void setAttribute(java.lang.String, java.lang.Object); field public static final java.lang.String RESERVED_PREFIX = "http."; } - public class HttpDateGenerator { + public deprecated class HttpDateGenerator { ctor public HttpDateGenerator(); method public synchronized java.lang.String getCurrentDate(); field public static final java.util.TimeZone GMT; field public static final java.lang.String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; } - public abstract interface HttpExpectationVerifier { + public abstract deprecated interface HttpExpectationVerifier { method public abstract void verify(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException; } - public abstract interface HttpProcessor implements org.apache.http.HttpRequestInterceptor org.apache.http.HttpResponseInterceptor { + public abstract deprecated interface HttpProcessor implements org.apache.http.HttpRequestInterceptor org.apache.http.HttpResponseInterceptor { } - public class HttpRequestExecutor { + public deprecated class HttpRequestExecutor { ctor public HttpRequestExecutor(); method protected boolean canResponseHaveBody(org.apache.http.HttpRequest, org.apache.http.HttpResponse); method protected org.apache.http.HttpResponse doReceiveResponse(org.apache.http.HttpRequest, org.apache.http.HttpClientConnection, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; @@ -57237,11 +57654,11 @@ package org.apache.http.protocol { method public void preProcess(org.apache.http.HttpRequest, org.apache.http.protocol.HttpProcessor, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public abstract interface HttpRequestHandler { + public abstract deprecated interface HttpRequestHandler { method public abstract void handle(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class HttpRequestHandlerRegistry implements org.apache.http.protocol.HttpRequestHandlerResolver { + public deprecated class HttpRequestHandlerRegistry implements org.apache.http.protocol.HttpRequestHandlerResolver { ctor public HttpRequestHandlerRegistry(); method public org.apache.http.protocol.HttpRequestHandler lookup(java.lang.String); method protected deprecated boolean matchUriRequestPattern(java.lang.String, java.lang.String); @@ -57250,11 +57667,11 @@ package org.apache.http.protocol { method public void unregister(java.lang.String); } - public abstract interface HttpRequestHandlerResolver { + public abstract deprecated interface HttpRequestHandlerResolver { method public abstract org.apache.http.protocol.HttpRequestHandler lookup(java.lang.String); } - public abstract interface HttpRequestInterceptorList { + public abstract deprecated interface HttpRequestInterceptorList { method public abstract void addRequestInterceptor(org.apache.http.HttpRequestInterceptor); method public abstract void addRequestInterceptor(org.apache.http.HttpRequestInterceptor, int); method public abstract void clearRequestInterceptors(); @@ -57264,7 +57681,7 @@ package org.apache.http.protocol { method public abstract void setInterceptors(java.util.List); } - public abstract interface HttpResponseInterceptorList { + public abstract deprecated interface HttpResponseInterceptorList { method public abstract void addResponseInterceptor(org.apache.http.HttpResponseInterceptor); method public abstract void addResponseInterceptor(org.apache.http.HttpResponseInterceptor, int); method public abstract void clearResponseInterceptors(); @@ -57274,7 +57691,7 @@ package org.apache.http.protocol { method public abstract void setInterceptors(java.util.List); } - public class HttpService { + public deprecated class HttpService { ctor public HttpService(org.apache.http.protocol.HttpProcessor, org.apache.http.ConnectionReuseStrategy, org.apache.http.HttpResponseFactory); method protected void doService(org.apache.http.HttpRequest, org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; method public org.apache.http.params.HttpParams getParams(); @@ -57288,61 +57705,61 @@ package org.apache.http.protocol { method public void setResponseFactory(org.apache.http.HttpResponseFactory); } - public class RequestConnControl implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestConnControl implements org.apache.http.HttpRequestInterceptor { ctor public RequestConnControl(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class RequestContent implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestContent implements org.apache.http.HttpRequestInterceptor { ctor public RequestContent(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class RequestDate implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestDate implements org.apache.http.HttpRequestInterceptor { ctor public RequestDate(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class RequestExpectContinue implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestExpectContinue implements org.apache.http.HttpRequestInterceptor { ctor public RequestExpectContinue(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class RequestTargetHost implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestTargetHost implements org.apache.http.HttpRequestInterceptor { ctor public RequestTargetHost(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class RequestUserAgent implements org.apache.http.HttpRequestInterceptor { + public deprecated class RequestUserAgent implements org.apache.http.HttpRequestInterceptor { ctor public RequestUserAgent(); method public void process(org.apache.http.HttpRequest, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class ResponseConnControl implements org.apache.http.HttpResponseInterceptor { + public deprecated class ResponseConnControl implements org.apache.http.HttpResponseInterceptor { ctor public ResponseConnControl(); method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class ResponseContent implements org.apache.http.HttpResponseInterceptor { + public deprecated class ResponseContent implements org.apache.http.HttpResponseInterceptor { ctor public ResponseContent(); method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class ResponseDate implements org.apache.http.HttpResponseInterceptor { + public deprecated class ResponseDate implements org.apache.http.HttpResponseInterceptor { ctor public ResponseDate(); method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class ResponseServer implements org.apache.http.HttpResponseInterceptor { + public deprecated class ResponseServer implements org.apache.http.HttpResponseInterceptor { ctor public ResponseServer(); method public void process(org.apache.http.HttpResponse, org.apache.http.protocol.HttpContext) throws org.apache.http.HttpException, java.io.IOException; } - public class SyncBasicHttpContext extends org.apache.http.protocol.BasicHttpContext { + public deprecated class SyncBasicHttpContext extends org.apache.http.protocol.BasicHttpContext { ctor public SyncBasicHttpContext(org.apache.http.protocol.HttpContext); } - public class UriPatternMatcher { + public deprecated class UriPatternMatcher { ctor public UriPatternMatcher(); method public java.lang.Object lookup(java.lang.String); method protected boolean matchUriRequestPattern(java.lang.String, java.lang.String); @@ -57355,7 +57772,7 @@ package org.apache.http.protocol { package org.apache.http.util { - public final class ByteArrayBuffer { + public final deprecated class ByteArrayBuffer { ctor public ByteArrayBuffer(int); method public void append(byte[], int, int); method public void append(int); @@ -57372,7 +57789,7 @@ package org.apache.http.util { method public byte[] toByteArray(); } - public final class CharArrayBuffer { + public final deprecated class CharArrayBuffer { ctor public CharArrayBuffer(int); method public void append(char[], int, int); method public void append(java.lang.String); @@ -57398,7 +57815,7 @@ package org.apache.http.util { method public char[] toCharArray(); } - public final class EncodingUtils { + public final deprecated class EncodingUtils { method public static byte[] getAsciiBytes(java.lang.String); method public static java.lang.String getAsciiString(byte[], int, int); method public static java.lang.String getAsciiString(byte[]); @@ -57407,18 +57824,18 @@ package org.apache.http.util { method public static java.lang.String getString(byte[], java.lang.String); } - public final class EntityUtils { + public final deprecated class EntityUtils { method public static java.lang.String getContentCharSet(org.apache.http.HttpEntity) throws org.apache.http.ParseException; method public static byte[] toByteArray(org.apache.http.HttpEntity) throws java.io.IOException; method public static java.lang.String toString(org.apache.http.HttpEntity, java.lang.String) throws java.io.IOException, org.apache.http.ParseException; method public static java.lang.String toString(org.apache.http.HttpEntity) throws java.io.IOException, org.apache.http.ParseException; } - public final class ExceptionUtils { + public final deprecated class ExceptionUtils { method public static void initCause(java.lang.Throwable, java.lang.Throwable); } - public final class LangUtils { + public final deprecated class LangUtils { method public static boolean equals(java.lang.Object, java.lang.Object); method public static boolean equals(java.lang.Object[], java.lang.Object[]); method public static int hashCode(int, int); @@ -57428,7 +57845,7 @@ package org.apache.http.util { field public static final int HASH_SEED = 17; // 0x11 } - public class VersionInfo { + public deprecated class VersionInfo { ctor protected VersionInfo(java.lang.String, java.lang.String, java.lang.String, java.lang.String, java.lang.String); method protected static final org.apache.http.util.VersionInfo fromMap(java.lang.String, java.util.Map, java.lang.ClassLoader); method public final java.lang.String getClassloader(); @@ -58507,7 +58924,7 @@ package org.xmlpull.v1 { method public void setValidating(boolean); field public static final java.lang.String PROPERTY_NAME = "org.xmlpull.v1.XmlPullParserFactory"; field protected java.lang.String classNamesLocation; - field protected java.util.HashMap features; + field protected java.util.HashMap<java.lang.String, java.lang.Boolean> features; field protected java.util.ArrayList parserClasses; field protected java.util.ArrayList serializerClasses; } diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java index 13ceb4a..1e1b33f 100644 --- a/core/java/android/accessibilityservice/AccessibilityService.java +++ b/core/java/android/accessibilityservice/AccessibilityService.java @@ -24,13 +24,18 @@ import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.util.Log; +import android.view.Display; import android.view.KeyEvent; +import android.view.View; +import android.view.ViewGroup; +import android.view.WindowManager; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityInteractionClient; import android.view.accessibility.AccessibilityNodeInfo; import android.view.accessibility.AccessibilityWindowInfo; import com.android.internal.os.HandlerCaller; +import com.android.internal.os.SomeArgs; import java.util.List; @@ -366,7 +371,7 @@ public abstract class AccessibilityService extends Service { public void onAccessibilityEvent(AccessibilityEvent event); public void onInterrupt(); public void onServiceConnected(); - public void onSetConnectionId(int connectionId); + public void init(int connectionId, IBinder windowToken); public boolean onGesture(int gestureId); public boolean onKeyEvent(KeyEvent event); } @@ -375,6 +380,10 @@ public abstract class AccessibilityService extends Service { private AccessibilityServiceInfo mInfo; + private IBinder mWindowToken; + + private WindowManager mWindowManager; + /** * Callback for {@link android.view.accessibility.AccessibilityEvent}s. * @@ -611,6 +620,18 @@ public abstract class AccessibilityService extends Service { } } + @Override + public Object getSystemService(String name) { + if (Context.WINDOW_SERVICE.equals(name)) { + if (mWindowManager == null) { + WindowManager wrapped = (WindowManager) super.getSystemService(name); + mWindowManager = new LocalWindowManager(wrapped); + } + return mWindowManager; + } + return super.getSystemService(name); + } + /** * Implement to return the implementation of the internal accessibility * service interface. @@ -634,8 +655,9 @@ public abstract class AccessibilityService extends Service { } @Override - public void onSetConnectionId( int connectionId) { + public void init(int connectionId, IBinder windowToken) { mConnectionId = connectionId; + mWindowToken = windowToken; } @Override @@ -658,7 +680,7 @@ public abstract class AccessibilityService extends Service { */ public static class IAccessibilityServiceClientWrapper extends IAccessibilityServiceClient.Stub implements HandlerCaller.Callback { - private static final int DO_SET_SET_CONNECTION = 1; + private static final int DO_INIT = 1; private static final int DO_ON_INTERRUPT = 2; private static final int DO_ON_ACCESSIBILITY_EVENT = 3; private static final int DO_ON_GESTURE = 4; @@ -677,9 +699,10 @@ public abstract class AccessibilityService extends Service { mCaller = new HandlerCaller(context, looper, this, true /*asyncHandler*/); } - public void setConnection(IAccessibilityServiceConnection connection, int connectionId) { - Message message = mCaller.obtainMessageIO(DO_SET_SET_CONNECTION, connectionId, - connection); + public void init(IAccessibilityServiceConnection connection, int connectionId, + IBinder windowToken) { + Message message = mCaller.obtainMessageIOO(DO_INIT, connectionId, + connection, windowToken); mCaller.sendMessage(message); } @@ -730,20 +753,24 @@ public abstract class AccessibilityService extends Service { mCallback.onInterrupt(); } return; - case DO_SET_SET_CONNECTION: { + case DO_INIT: { mConnectionId = message.arg1; + SomeArgs args = (SomeArgs) message.obj; IAccessibilityServiceConnection connection = - (IAccessibilityServiceConnection) message.obj; + (IAccessibilityServiceConnection) args.arg1; + IBinder windowToken = (IBinder) args.arg2; + args.recycle(); if (connection != null) { AccessibilityInteractionClient.getInstance().addConnection(mConnectionId, connection); - mCallback.onSetConnectionId(mConnectionId); + mCallback.init(mConnectionId, windowToken); mCallback.onServiceConnected(); } else { AccessibilityInteractionClient.getInstance().removeConnection( mConnectionId); + mConnectionId = AccessibilityInteractionClient.NO_ID; AccessibilityInteractionClient.getInstance().clearCache(); - mCallback.onSetConnectionId(AccessibilityInteractionClient.NO_ID); + mCallback.init(AccessibilityInteractionClient.NO_ID, null); } } return; @@ -785,4 +812,53 @@ public abstract class AccessibilityService extends Service { } } } + + private class LocalWindowManager implements WindowManager { + private final WindowManager mImpl; + + private LocalWindowManager(WindowManager impl) { + mImpl = impl; + } + + @Override + public Display getDefaultDisplay() { + return mImpl.getDefaultDisplay(); + } + + @Override + public void addView(View view, ViewGroup.LayoutParams params) { + if (!(params instanceof WindowManager.LayoutParams)) { + throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); + } + WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params; + if (windowParams.type == LayoutParams.TYPE_ACCESSIBILITY_OVERLAY + && windowParams.token == null) { + windowParams.token = mWindowToken; + } + mImpl.addView(view, params); + } + + @Override + public void updateViewLayout(View view, ViewGroup.LayoutParams params) { + if (!(params instanceof WindowManager.LayoutParams)) { + throw new IllegalArgumentException("Params must be WindowManager.LayoutParams"); + } + WindowManager.LayoutParams windowParams = (WindowManager.LayoutParams) params; + if (windowParams.type == LayoutParams.TYPE_ACCESSIBILITY_OVERLAY + && windowParams.token == null) { + windowParams.token = mWindowToken; + } + mImpl.updateViewLayout(view, params); + } + + @Override + public void removeViewImmediate(View view) { + mImpl.removeViewImmediate(view); + } + + @Override + public void removeView(View view) { + mImpl.removeView(view); + } + } } diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl index 6ce0219..8b503dd 100644 --- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl +++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl @@ -28,7 +28,7 @@ import android.view.KeyEvent; */ oneway interface IAccessibilityServiceClient { - void setConnection(in IAccessibilityServiceConnection connection, int connectionId); + void init(in IAccessibilityServiceConnection connection, int connectionId, IBinder windowToken); void onAccessibilityEvent(in AccessibilityEvent event); diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index 3720c81..da48709 100644 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -16,6 +16,8 @@ package android.animation; +import android.content.res.ConstantState; + import java.util.ArrayList; /** @@ -41,6 +43,18 @@ public abstract class Animator implements Cloneable { boolean mPaused = false; /** + * A set of flags which identify the type of configuration changes that can affect this + * Animator. Used by the Animator cache. + */ + int mChangingConfigurations = 0; + + /** + * If this animator is inflated from a constant state, keep a reference to it so that + * ConstantState will not be garbage collected until this animator is collected + */ + private AnimatorConstantState mConstantState; + + /** * Starts this animation. If the animation has a nonzero startDelay, the animation will start * running after that delay elapses. A non-delayed animation will have its initial * value(s) set immediately, followed by calls to @@ -295,25 +309,71 @@ public abstract class Animator implements Cloneable { } } + /** + * Return a mask of the configuration parameters for which this animator may change, requiring + * that it should be re-created from Resources. The default implementation returns whatever + * value was provided through setChangingConfigurations(int) or 0 by default. + * + * @return Returns a mask of the changing configuration parameters, as defined by + * {@link android.content.pm.ActivityInfo}. + * @see android.content.pm.ActivityInfo + * @hide + */ + public int getChangingConfigurations() { + return mChangingConfigurations; + } + + /** + * Set a mask of the configuration parameters for which this animator may change, requiring + * that it be re-created from resource. + * + * @param configs A mask of the changing configuration parameters, as + * defined by {@link android.content.pm.ActivityInfo}. + * + * @see android.content.pm.ActivityInfo + * @hide + */ + public void setChangingConfigurations(int configs) { + mChangingConfigurations = configs; + } + + /** + * Sets the changing configurations value to the union of the current changing configurations + * and the provided configs. + * This method is called while loading the animator. + * @hide + */ + public void appendChangingConfigurations(int configs) { + mChangingConfigurations |= configs; + } + + /** + * Return a {@link android.content.res.ConstantState} instance that holds the shared state of + * this Animator. + * <p> + * This constant state is used to create new instances of this animator when needed, instead + * of re-loading it from resources. Default implementation creates a new + * {@link AnimatorConstantState}. You can override this method to provide your custom logic or + * return null if you don't want this animator to be cached. + * + * @return The ConfigurationBoundResourceCache.BaseConstantState associated to this Animator. + * @see android.content.res.ConstantState + * @see #clone() + * @hide + */ + public ConstantState<Animator> createConstantState() { + return new AnimatorConstantState(this); + } + @Override public Animator clone() { try { final Animator anim = (Animator) super.clone(); if (mListeners != null) { - ArrayList<AnimatorListener> oldListeners = mListeners; - anim.mListeners = new ArrayList<AnimatorListener>(); - int numListeners = oldListeners.size(); - for (int i = 0; i < numListeners; ++i) { - anim.mListeners.add(oldListeners.get(i)); - } + anim.mListeners = new ArrayList<AnimatorListener>(mListeners); } if (mPauseListeners != null) { - ArrayList<AnimatorPauseListener> oldListeners = mPauseListeners; - anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(); - int numListeners = oldListeners.size(); - for (int i = 0; i < numListeners; ++i) { - anim.mPauseListeners.add(oldListeners.get(i)); - } + anim.mPauseListeners = new ArrayList<AnimatorPauseListener>(mPauseListeners); } return anim; } catch (CloneNotSupportedException e) { @@ -469,4 +529,35 @@ public abstract class Animator implements Cloneable { public void setAllowRunningAsynchronously(boolean mayRunAsync) { // It is up to subclasses to support this, if they can. } + + /** + * Creates a {@link ConstantState} which holds changing configurations information associated + * with the given Animator. + * <p> + * When {@link #newInstance()} is called, default implementation clones the Animator. + */ + private static class AnimatorConstantState extends ConstantState<Animator> { + + final Animator mAnimator; + int mChangingConf; + + public AnimatorConstantState(Animator animator) { + mAnimator = animator; + // ensure a reference back to here so that constante state is not gc'ed. + mAnimator.mConstantState = this; + mChangingConf = mAnimator.getChangingConfigurations(); + } + + @Override + public int getChangingConfigurations() { + return mChangingConf; + } + + @Override + public Animator newInstance() { + final Animator clone = mAnimator.clone(); + clone.mConstantState = this; + return clone; + } + } } diff --git a/core/java/android/animation/AnimatorInflater.java b/core/java/android/animation/AnimatorInflater.java index 25417ed..688d7e4 100644 --- a/core/java/android/animation/AnimatorInflater.java +++ b/core/java/android/animation/AnimatorInflater.java @@ -16,6 +16,8 @@ package android.animation; import android.content.Context; +import android.content.res.ConfigurationBoundResourceCache; +import android.content.res.ConstantState; import android.content.res.Resources; import android.content.res.Resources.NotFoundException; import android.content.res.Resources.Theme; @@ -30,6 +32,8 @@ import android.util.TypedValue; import android.util.Xml; import android.view.InflateException; import android.view.animation.AnimationUtils; +import android.view.animation.BaseInterpolator; +import android.view.animation.Interpolator; import com.android.internal.R; @@ -67,6 +71,9 @@ public class AnimatorInflater { private static final boolean DBG_ANIMATOR_INFLATER = false; + // used to calculate changing configs for resource references + private static final TypedValue sTmpTypedValue = new TypedValue(); + /** * Loads an {@link Animator} object from a resource * @@ -98,11 +105,34 @@ public class AnimatorInflater { /** @hide */ public static Animator loadAnimator(Resources resources, Theme theme, int id, float pathErrorScale) throws NotFoundException { - + final ConfigurationBoundResourceCache<Animator> animatorCache = resources + .getAnimatorCache(); + Animator animator = animatorCache.get(id, theme); + if (animator != null) { + if (DBG_ANIMATOR_INFLATER) { + Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id)); + } + return animator; + } else if (DBG_ANIMATOR_INFLATER) { + Log.d(TAG, "cache miss for animator " + resources.getResourceName(id)); + } XmlResourceParser parser = null; try { parser = resources.getAnimation(id); - return createAnimatorFromXml(resources, theme, parser, pathErrorScale); + animator = createAnimatorFromXml(resources, theme, parser, pathErrorScale); + if (animator != null) { + animator.appendChangingConfigurations(getChangingConfigs(resources, id)); + final ConstantState<Animator> constantState = animator.createConstantState(); + if (constantState != null) { + if (DBG_ANIMATOR_INFLATER) { + Log.d(TAG, "caching animator for res " + resources.getResourceName(id)); + } + animatorCache.put(id, theme, constantState); + // create a new animator so that cached version is never used by the user + animator = constantState.newInstance(resources, theme); + } + } + return animator; } catch (XmlPullParserException ex) { Resources.NotFoundException rnf = new Resources.NotFoundException("Can't load animation resource ID #0x" + @@ -122,10 +152,29 @@ public class AnimatorInflater { public static StateListAnimator loadStateListAnimator(Context context, int id) throws NotFoundException { + final Resources resources = context.getResources(); + final ConfigurationBoundResourceCache<StateListAnimator> cache = resources + .getStateListAnimatorCache(); + final Theme theme = context.getTheme(); + StateListAnimator animator = cache.get(id, theme); + if (animator != null) { + return animator; + } XmlResourceParser parser = null; try { - parser = context.getResources().getAnimation(id); - return createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); + parser = resources.getAnimation(id); + animator = createStateListAnimatorFromXml(context, parser, Xml.asAttributeSet(parser)); + if (animator != null) { + animator.appendChangingConfigurations(getChangingConfigs(resources, id)); + final ConstantState<StateListAnimator> constantState = animator + .createConstantState(); + if (constantState != null) { + cache.put(id, theme, constantState); + // return a clone so that the animator in constant state is never used. + animator = constantState.newInstance(resources, theme); + } + } + return animator; } catch (XmlPullParserException ex) { Resources.NotFoundException rnf = new Resources.NotFoundException( @@ -172,14 +221,13 @@ public class AnimatorInflater { for (int i = 0; i < attributeCount; i++) { int attrName = attributeSet.getAttributeNameResource(i); if (attrName == R.attr.animation) { - animator = loadAnimator(context, - attributeSet.getAttributeResourceValue(i, 0)); + final int animId = attributeSet.getAttributeResourceValue(i, 0); + animator = loadAnimator(context, animId); } else { states[stateIndex++] = attributeSet.getAttributeBooleanValue(i, false) ? attrName : -attrName; } - } if (animator == null) { animator = createAnimatorFromXml(context.getResources(), @@ -192,7 +240,6 @@ public class AnimatorInflater { } stateListAnimator .addState(StateSet.trimStateSet(states, stateIndex), animator); - } break; } @@ -508,7 +555,6 @@ public class AnimatorInflater { private static Animator createAnimatorFromXml(Resources res, Theme theme, XmlPullParser parser, AttributeSet attrs, AnimatorSet parent, int sequenceOrdering, float pixelSize) throws XmlPullParserException, IOException { - Animator anim = null; ArrayList<Animator> childAnims = null; @@ -537,8 +583,8 @@ public class AnimatorInflater { } else { a = res.obtainAttributes(attrs, R.styleable.AnimatorSet); } - int ordering = a.getInt(R.styleable.AnimatorSet_ordering, - TOGETHER); + anim.appendChangingConfigurations(a.getChangingConfigurations()); + int ordering = a.getInt(R.styleable.AnimatorSet_ordering, TOGETHER); createAnimatorFromXml(res, theme, parser, attrs, (AnimatorSet) anim, ordering, pixelSize); a.recycle(); @@ -565,7 +611,6 @@ public class AnimatorInflater { parent.playSequentially(animsArray); } } - return anim; } @@ -591,7 +636,6 @@ public class AnimatorInflater { private static ValueAnimator loadAnimator(Resources res, Theme theme, AttributeSet attrs, ValueAnimator anim, float pathErrorScale) throws NotFoundException { - TypedArray arrayAnimator = null; TypedArray arrayObjectAnimator = null; @@ -609,25 +653,37 @@ public class AnimatorInflater { } else { arrayObjectAnimator = res.obtainAttributes(attrs, R.styleable.PropertyAnimator); } + anim.appendChangingConfigurations(arrayObjectAnimator.getChangingConfigurations()); } if (anim == null) { anim = new ValueAnimator(); } + anim.appendChangingConfigurations(arrayAnimator.getChangingConfigurations()); parseAnimatorFromTypeArray(anim, arrayAnimator, arrayObjectAnimator, pathErrorScale); - final int resID = - arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); + final int resID = arrayAnimator.getResourceId(R.styleable.Animator_interpolator, 0); if (resID > 0) { - anim.setInterpolator(AnimationUtils.loadInterpolator(res, theme, resID)); + final Interpolator interpolator = AnimationUtils.loadInterpolator(res, theme, resID); + if (interpolator instanceof BaseInterpolator) { + anim.appendChangingConfigurations( + ((BaseInterpolator) interpolator).getChangingConfiguration()); + } + anim.setInterpolator(interpolator); } arrayAnimator.recycle(); if (arrayObjectAnimator != null) { arrayObjectAnimator.recycle(); } - return anim; } + + private static int getChangingConfigs(Resources resources, int id) { + synchronized (sTmpTypedValue) { + resources.getValue(id, sTmpTypedValue, true); + return sTmpTypedValue.changingConfigurations; + } + } } diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java index 0aa8fdd..92762c3 100644 --- a/core/java/android/animation/AnimatorSet.java +++ b/core/java/android/animation/AnimatorSet.java @@ -241,6 +241,19 @@ public final class AnimatorSet extends Animator { } /** + * @hide + */ + @Override + public int getChangingConfigurations() { + int conf = super.getChangingConfigurations(); + final int nodeCount = mNodes.size(); + for (int i = 0; i < nodeCount; i ++) { + conf |= mNodes.get(i).animation.getChangingConfigurations(); + } + return conf; + } + + /** * Sets the TimeInterpolator for all current {@link #getChildAnimations() child animations} * of this AnimatorSet. The default value is null, which means that no interpolator * is set on this AnimatorSet. Setting the interpolator to any non-null value @@ -628,23 +641,25 @@ public final class AnimatorSet extends Animator { * manually, as we clone each Node (and its animation). The clone will then be sorted, * and will populate any appropriate lists, when it is started. */ + final int nodeCount = mNodes.size(); anim.mNeedsSort = true; anim.mTerminated = false; anim.mStarted = false; anim.mPlayingSet = new ArrayList<Animator>(); anim.mNodeMap = new HashMap<Animator, Node>(); - anim.mNodes = new ArrayList<Node>(); - anim.mSortedNodes = new ArrayList<Node>(); + anim.mNodes = new ArrayList<Node>(nodeCount); + anim.mSortedNodes = new ArrayList<Node>(nodeCount); anim.mReversible = mReversible; anim.mSetListener = null; // Walk through the old nodes list, cloning each node and adding it to the new nodemap. // One problem is that the old node dependencies point to nodes in the old AnimatorSet. // We need to track the old/new nodes in order to reconstruct the dependencies in the clone. - HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>(); // <old, new> - for (Node node : mNodes) { + + for (int n = 0; n < nodeCount; n++) { + final Node node = mNodes.get(n); Node nodeClone = node.clone(); - nodeCloneMap.put(node, nodeClone); + node.mTmpClone = nodeClone; anim.mNodes.add(nodeClone); anim.mNodeMap.put(nodeClone.animation, nodeClone); // Clear out the dependencies in the clone; we'll set these up manually later @@ -652,40 +667,50 @@ public final class AnimatorSet extends Animator { nodeClone.tmpDependencies = null; nodeClone.nodeDependents = null; nodeClone.nodeDependencies = null; + // clear out any listeners that were set up by the AnimatorSet; these will // be set up when the clone's nodes are sorted - ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners(); + final ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners(); if (cloneListeners != null) { - ArrayList<AnimatorListener> listenersToRemove = null; - for (AnimatorListener listener : cloneListeners) { + for (int i = cloneListeners.size() - 1; i >= 0; i--) { + final AnimatorListener listener = cloneListeners.get(i); if (listener instanceof AnimatorSetListener) { - if (listenersToRemove == null) { - listenersToRemove = new ArrayList<AnimatorListener>(); - } - listenersToRemove.add(listener); - } - } - if (listenersToRemove != null) { - for (AnimatorListener listener : listenersToRemove) { - cloneListeners.remove(listener); + cloneListeners.remove(i); } } } } // Now that we've cloned all of the nodes, we're ready to walk through their // dependencies, mapping the old dependencies to the new nodes - for (Node node : mNodes) { - Node nodeClone = nodeCloneMap.get(node); + for (int n = 0; n < nodeCount; n++) { + final Node node = mNodes.get(n); + final Node clone = node.mTmpClone; if (node.dependencies != null) { - for (Dependency dependency : node.dependencies) { - Node clonedDependencyNode = nodeCloneMap.get(dependency.node); - Dependency cloneDependency = new Dependency(clonedDependencyNode, + clone.dependencies = new ArrayList<Dependency>(node.dependencies.size()); + final int depSize = node.dependencies.size(); + for (int i = 0; i < depSize; i ++) { + final Dependency dependency = node.dependencies.get(i); + Dependency cloneDependency = new Dependency(dependency.node.mTmpClone, dependency.rule); - nodeClone.addDependency(cloneDependency); + clone.dependencies.add(cloneDependency); + } + } + if (node.nodeDependents != null) { + clone.nodeDependents = new ArrayList<Node>(node.nodeDependents.size()); + for (Node dep : node.nodeDependents) { + clone.nodeDependents.add(dep.mTmpClone); + } + } + if (node.nodeDependencies != null) { + clone.nodeDependencies = new ArrayList<Node>(node.nodeDependencies.size()); + for (Node dep : node.nodeDependencies) { + clone.nodeDependencies.add(dep.mTmpClone); } } } - + for (int n = 0; n < nodeCount; n++) { + mNodes.get(n).mTmpClone = null; + } return anim; } @@ -1017,6 +1042,11 @@ public final class AnimatorSet extends Animator { public boolean done = false; /** + * Temporary field to hold the clone in AnimatorSet#clone. Cleaned after clone is complete + */ + private Node mTmpClone = null; + + /** * Constructs the Node with the animation that it encapsulates. A Node has no * dependencies by default; dependencies are added via the addDependency() * method. diff --git a/core/java/android/animation/FloatKeyframeSet.java b/core/java/android/animation/FloatKeyframeSet.java index 12e5862..abac246 100644 --- a/core/java/android/animation/FloatKeyframeSet.java +++ b/core/java/android/animation/FloatKeyframeSet.java @@ -19,6 +19,7 @@ package android.animation; import android.animation.Keyframe.FloatKeyframe; import java.util.ArrayList; +import java.util.List; /** * This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate @@ -47,8 +48,8 @@ class FloatKeyframeSet extends KeyframeSet implements Keyframes.FloatKeyframes { @Override public FloatKeyframeSet clone() { - ArrayList<Keyframe> keyframes = mKeyframes; - int numKeyframes = mKeyframes.size(); + final List<Keyframe> keyframes = mKeyframes; + final int numKeyframes = mKeyframes.size(); FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes]; for (int i = 0; i < numKeyframes; ++i) { newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone(); diff --git a/core/java/android/animation/IntKeyframeSet.java b/core/java/android/animation/IntKeyframeSet.java index 7a5b0ec..0ec5138 100644 --- a/core/java/android/animation/IntKeyframeSet.java +++ b/core/java/android/animation/IntKeyframeSet.java @@ -19,6 +19,7 @@ package android.animation; import android.animation.Keyframe.IntKeyframe; import java.util.ArrayList; +import java.util.List; /** * This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate @@ -47,7 +48,7 @@ class IntKeyframeSet extends KeyframeSet implements Keyframes.IntKeyframes { @Override public IntKeyframeSet clone() { - ArrayList<Keyframe> keyframes = mKeyframes; + List<Keyframe> keyframes = mKeyframes; int numKeyframes = mKeyframes.size(); IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes]; for (int i = 0; i < numKeyframes; ++i) { diff --git a/core/java/android/animation/KeyframeSet.java b/core/java/android/animation/KeyframeSet.java index 8d15db2..0e99bff 100644 --- a/core/java/android/animation/KeyframeSet.java +++ b/core/java/android/animation/KeyframeSet.java @@ -18,6 +18,8 @@ package android.animation; import java.util.ArrayList; import java.util.Arrays; +import java.util.List; + import android.animation.Keyframe.IntKeyframe; import android.animation.Keyframe.FloatKeyframe; import android.animation.Keyframe.ObjectKeyframe; @@ -36,16 +38,16 @@ class KeyframeSet implements Keyframes { Keyframe mFirstKeyframe; Keyframe mLastKeyframe; TimeInterpolator mInterpolator; // only used in the 2-keyframe case - ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes + List<Keyframe> mKeyframes; // only used when there are not 2 keyframes TypeEvaluator mEvaluator; public KeyframeSet(Keyframe... keyframes) { mNumKeyframes = keyframes.length; - mKeyframes = new ArrayList<Keyframe>(); - mKeyframes.addAll(Arrays.asList(keyframes)); - mFirstKeyframe = mKeyframes.get(0); - mLastKeyframe = mKeyframes.get(mNumKeyframes - 1); + // immutable list + mKeyframes = Arrays.asList(keyframes); + mFirstKeyframe = keyframes[0]; + mLastKeyframe = keyframes[mNumKeyframes - 1]; mInterpolator = mLastKeyframe.getInterpolator(); } @@ -57,7 +59,7 @@ class KeyframeSet implements Keyframes { public void invalidateCache() { } - public ArrayList<Keyframe> getKeyframes() { + public List<Keyframe> getKeyframes() { return mKeyframes; } @@ -177,9 +179,9 @@ class KeyframeSet implements Keyframes { @Override public KeyframeSet clone() { - ArrayList<Keyframe> keyframes = mKeyframes; + List<Keyframe> keyframes = mKeyframes; int numKeyframes = mKeyframes.size(); - Keyframe[] newKeyframes = new Keyframe[numKeyframes]; + final Keyframe[] newKeyframes = new Keyframe[numKeyframes]; for (int i = 0; i < numKeyframes; ++i) { newKeyframes[i] = keyframes.get(i).clone(); } diff --git a/core/java/android/animation/Keyframes.java b/core/java/android/animation/Keyframes.java index 6611c6c..c921466 100644 --- a/core/java/android/animation/Keyframes.java +++ b/core/java/android/animation/Keyframes.java @@ -16,6 +16,7 @@ package android.animation; import java.util.ArrayList; +import java.util.List; /** * This interface abstracts a collection of Keyframe objects and is called by @@ -62,7 +63,7 @@ interface Keyframes extends Cloneable { * @return A list of all Keyframes contained by this. This may return null if this is * not made up of Keyframes. */ - ArrayList<Keyframe> getKeyframes(); + List<Keyframe> getKeyframes(); Keyframes clone(); diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java index d372933..97426c3 100644 --- a/core/java/android/animation/PropertyValuesHolder.java +++ b/core/java/android/animation/PropertyValuesHolder.java @@ -27,6 +27,7 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.concurrent.locks.ReentrantReadWriteLock; /** @@ -791,7 +792,7 @@ public class PropertyValuesHolder implements Cloneable { // check to make sure that mProperty is on the class of target try { Object testValue = null; - ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes(); + List<Keyframe> keyframes = mKeyframes.getKeyframes(); int keyframeCount = keyframes == null ? 0 : keyframes.size(); for (int i = 0; i < keyframeCount; i++) { Keyframe kf = keyframes.get(i); @@ -814,7 +815,7 @@ public class PropertyValuesHolder implements Cloneable { if (mSetter == null) { setupSetter(targetClass); } - ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes(); + List<Keyframe> keyframes = mKeyframes.getKeyframes(); int keyframeCount = keyframes == null ? 0 : keyframes.size(); for (int i = 0; i < keyframeCount; i++) { Keyframe kf = keyframes.get(i); @@ -890,7 +891,7 @@ public class PropertyValuesHolder implements Cloneable { * @param target The object which holds the start values that should be set. */ void setupStartValue(Object target) { - ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes(); + List<Keyframe> keyframes = mKeyframes.getKeyframes(); if (!keyframes.isEmpty()) { setupValue(target, keyframes.get(0)); } @@ -905,7 +906,7 @@ public class PropertyValuesHolder implements Cloneable { * @param target The object which holds the start values that should be set. */ void setupEndValue(Object target) { - ArrayList<Keyframe> keyframes = mKeyframes.getKeyframes(); + List<Keyframe> keyframes = mKeyframes.getKeyframes(); if (!keyframes.isEmpty()) { setupValue(target, keyframes.get(keyframes.size() - 1)); } diff --git a/core/java/android/animation/StateListAnimator.java b/core/java/android/animation/StateListAnimator.java index 7256a06..d49e914 100644 --- a/core/java/android/animation/StateListAnimator.java +++ b/core/java/android/animation/StateListAnimator.java @@ -16,6 +16,7 @@ package android.animation; +import android.content.res.ConstantState; import android.util.StateSet; import android.view.View; @@ -44,25 +45,31 @@ import java.util.ArrayList; * @attr ref android.R.styleable#DrawableStates_state_pressed * @attr ref android.R.styleable#StateListAnimatorItem_animation */ -public class StateListAnimator { - - private final ArrayList<Tuple> mTuples = new ArrayList<Tuple>(); +public class StateListAnimator implements Cloneable { + private ArrayList<Tuple> mTuples = new ArrayList<Tuple>(); private Tuple mLastMatch = null; - private Animator mRunningAnimator = null; - private WeakReference<View> mViewRef; + private StateListAnimatorConstantState mConstantState; + private AnimatorListenerAdapter mAnimatorListener; + private int mChangingConfigurations; - private AnimatorListenerAdapter mAnimatorListener = new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - animation.setTarget(null); - if (mRunningAnimator == animation) { - mRunningAnimator = null; + public StateListAnimator() { + initAnimatorListener(); + } + + private void initAnimatorListener() { + mAnimatorListener = new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + animation.setTarget(null); + if (mRunningAnimator == animation) { + mRunningAnimator = null; + } } - } - }; + }; + } /** * Associates the given animator with the provided drawable state specs so that it will be run @@ -75,6 +82,7 @@ public class StateListAnimator { Tuple tuple = new Tuple(specs, animator); tuple.mAnimator.addListener(mAnimatorListener); mTuples.add(tuple); + mChangingConfigurations |= animator.getChangingConfigurations(); } /** @@ -118,12 +126,35 @@ public class StateListAnimator { for (int i = 0; i < size; i++) { mTuples.get(i).mAnimator.setTarget(null); } - mViewRef = null; mLastMatch = null; mRunningAnimator = null; } + @Override + public StateListAnimator clone() { + try { + StateListAnimator clone = (StateListAnimator) super.clone(); + clone.mTuples = new ArrayList<Tuple>(mTuples.size()); + clone.mLastMatch = null; + clone.mRunningAnimator = null; + clone.mViewRef = null; + clone.mAnimatorListener = null; + clone.initAnimatorListener(); + final int tupleSize = mTuples.size(); + for (int i = 0; i < tupleSize; i++) { + final Tuple tuple = mTuples.get(i); + final Animator animatorClone = tuple.mAnimator.clone(); + animatorClone.removeListener(mAnimatorListener); + clone.addState(tuple.mSpecs, animatorClone); + } + clone.setChangingConfigurations(getChangingConfigurations()); + return clone; + } catch (CloneNotSupportedException e) { + throw new AssertionError("cannot clone state list animator", e); + } + } + /** * Called by View * @hide @@ -182,6 +213,63 @@ public class StateListAnimator { } /** + * Return a mask of the configuration parameters for which this animator may change, requiring + * that it be re-created. The default implementation returns whatever was provided through + * {@link #setChangingConfigurations(int)} or 0 by default. + * + * @return Returns a mask of the changing configuration parameters, as defined by + * {@link android.content.pm.ActivityInfo}. + * + * @see android.content.pm.ActivityInfo + * @hide + */ + public int getChangingConfigurations() { + return mChangingConfigurations; + } + + /** + * Set a mask of the configuration parameters for which this animator may change, requiring + * that it should be recreated from resources instead of being cloned. + * + * @param configs A mask of the changing configuration parameters, as + * defined by {@link android.content.pm.ActivityInfo}. + * + * @see android.content.pm.ActivityInfo + * @hide + */ + public void setChangingConfigurations(int configs) { + mChangingConfigurations = configs; + } + + /** + * Sets the changing configurations value to the union of the current changing configurations + * and the provided configs. + * This method is called while loading the animator. + * @hide + */ + public void appendChangingConfigurations(int configs) { + mChangingConfigurations |= configs; + } + + /** + * Return a {@link android.content.res.ConstantState} instance that holds the shared state of + * this Animator. + * <p> + * This constant state is used to create new instances of this animator when needed. Default + * implementation creates a new {@link StateListAnimatorConstantState}. You can override this + * method to provide your custom logic or return null if you don't want this animator to be + * cached. + * + * @return The {@link android.content.res.ConstantState} associated to this Animator. + * @see android.content.res.ConstantState + * @see #clone() + * @hide + */ + public ConstantState<StateListAnimator> createConstantState() { + return new StateListAnimatorConstantState(this); + } + + /** * @hide */ public static class Tuple { @@ -209,4 +297,36 @@ public class StateListAnimator { return mAnimator; } } + + /** + * Creates a constant state which holds changing configurations information associated with the + * given Animator. + * <p> + * When new instance is called, default implementation clones the Animator. + */ + private static class StateListAnimatorConstantState + extends ConstantState<StateListAnimator> { + + final StateListAnimator mAnimator; + + int mChangingConf; + + public StateListAnimatorConstantState(StateListAnimator animator) { + mAnimator = animator; + mAnimator.mConstantState = this; + mChangingConf = mAnimator.getChangingConfigurations(); + } + + @Override + public int getChangingConfigurations() { + return mChangingConf; + } + + @Override + public StateListAnimator newInstance() { + final StateListAnimator clone = mAnimator.clone(); + clone.mConstantState = this; + return clone; + } + } } diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java index 0d17d67..07f79b8 100644 --- a/core/java/android/animation/ValueAnimator.java +++ b/core/java/android/animation/ValueAnimator.java @@ -16,6 +16,7 @@ package android.animation; +import android.content.res.ConfigurationBoundResourceCache; import android.os.Looper; import android.os.Trace; import android.util.AndroidRuntimeException; @@ -1289,12 +1290,7 @@ public class ValueAnimator extends Animator { public ValueAnimator clone() { final ValueAnimator anim = (ValueAnimator) super.clone(); if (mUpdateListeners != null) { - ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners; - anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(); - int numListeners = oldListeners.size(); - for (int i = 0; i < numListeners; ++i) { - anim.mUpdateListeners.add(oldListeners.get(i)); - } + anim.mUpdateListeners = new ArrayList<AnimatorUpdateListener>(mUpdateListeners); } anim.mSeekTime = -1; anim.mPlayingBackwards = false; diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 17a31f3..e580368 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -2513,7 +2513,12 @@ public final class ActivityThread { } public void handleInstallProvider(ProviderInfo info) { - installContentProviders(mInitialApplication, Lists.newArrayList(info)); + final StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskWrites(); + try { + installContentProviders(mInitialApplication, Lists.newArrayList(info)); + } finally { + StrictMode.setThreadPolicy(oldPolicy); + } } private void handleEnterAnimationComplete(IBinder token) { diff --git a/core/java/android/app/ActivityTransitionCoordinator.java b/core/java/android/app/ActivityTransitionCoordinator.java index 540376e..82b6e35 100644 --- a/core/java/android/app/ActivityTransitionCoordinator.java +++ b/core/java/android/app/ActivityTransitionCoordinator.java @@ -206,6 +206,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { private ArrayList<GhostViewListeners> mGhostViewListeners = new ArrayList<GhostViewListeners>(); private ArrayMap<View, Float> mOriginalAlphas = new ArrayMap<View, Float>(); + final private ArrayList<View> mRootSharedElements = new ArrayList<View>(); + private ArrayList<Matrix> mSharedElementParentMatrices; public ActivityTransitionCoordinator(Window window, ArrayList<String> allSharedElementNames, @@ -222,8 +224,7 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { if (mListener != null) { mListener.onMapSharedElements(mAllSharedElementNames, sharedElements); } - mSharedElementNames.addAll(sharedElements.keySet()); - mSharedElements.addAll(sharedElements.values()); + setSharedElements(sharedElements); if (getViewsTransition() != null && mTransitioningViews != null) { ViewGroup decorView = getDecor(); if (decorView != null) { @@ -234,6 +235,58 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { setEpicenter(); } + /** + * Iterates over the shared elements and adds them to the members in order. + * Shared elements that are nested in other shared elements are placed after the + * elements that they are nested in. This means that layout ordering can be done + * from first to last. + * + * @param sharedElements The map of transition names to shared elements to set into + * the member fields. + */ + private void setSharedElements(ArrayMap<String, View> sharedElements) { + boolean isFirstRun = true; + while (!sharedElements.isEmpty()) { + final int numSharedElements = sharedElements.size(); + for (int i = numSharedElements - 1; i >= 0; i--) { + final View view = sharedElements.valueAt(i); + final String name = sharedElements.keyAt(i); + if (isFirstRun && (view == null || !view.isAttachedToWindow() || name == null)) { + sharedElements.removeAt(i); + } else { + if (!isNested(view, sharedElements)) { + mSharedElementNames.add(name); + mSharedElements.add(view); + sharedElements.removeAt(i); + if (isFirstRun) { + // We need to keep track which shared elements are roots + // and which are nested. + mRootSharedElements.add(view); + } + } + } + } + isFirstRun = false; + } + } + + /** + * Returns true when view is nested in any of the values of sharedElements. + */ + private static boolean isNested(View view, ArrayMap<String, View> sharedElements) { + ViewParent parent = view.getParent(); + boolean isNested = false; + while (parent instanceof View) { + View parentView = (View) parent; + if (sharedElements.containsValue(parentView)) { + isNested = true; + break; + } + parent = parentView.getParent(); + } + return isNested; + } + protected void stripOffscreenViews() { if (mTransitioningViews == null) { return; @@ -449,11 +502,50 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { view.layout(x, y, x + width, y + height); } - protected void getSharedElementParentMatrix(View view, Matrix matrix) { - // Find the location in the view's parent - ViewGroup parent = (ViewGroup) view.getParent(); - matrix.reset(); - parent.transformMatrixToLocal(matrix); + private void setSharedElementMatrices() { + int numSharedElements = mSharedElements.size(); + if (numSharedElements > 0) { + mSharedElementParentMatrices = new ArrayList<Matrix>(numSharedElements); + } + for (int i = 0; i < numSharedElements; i++) { + View view = mSharedElements.get(i); + + // Find the location in the view's parent + ViewGroup parent = (ViewGroup) view.getParent(); + Matrix matrix = new Matrix(); + parent.transformMatrixToLocal(matrix); + + mSharedElementParentMatrices.add(matrix); + } + } + + private void getSharedElementParentMatrix(View view, Matrix matrix) { + final boolean isNestedInOtherSharedElement = !mRootSharedElements.contains(view); + final boolean useParentMatrix; + if (isNestedInOtherSharedElement) { + useParentMatrix = true; + } else { + final int index = mSharedElementParentMatrices == null ? -1 + : mSharedElements.indexOf(view); + if (index < 0) { + useParentMatrix = true; + } else { + // The indices of mSharedElementParentMatrices matches the + // mSharedElement matrices. + Matrix parentMatrix = mSharedElementParentMatrices.get(index); + matrix.set(parentMatrix); + useParentMatrix = false; + } + } + if (useParentMatrix) { + matrix.reset(); + ViewParent viewParent = view.getParent(); + if (viewParent instanceof ViewGroup) { + // Find the location in the view's parent + ViewGroup parent = (ViewGroup) viewParent; + parent.transformMatrixToLocal(matrix); + } + } } protected ArrayList<SharedElementOriginalState> setSharedElementState( @@ -536,10 +628,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { protected ArrayList<View> createSnapshots(Bundle state, Collection<String> names) { int numSharedElements = names.size(); + ArrayList<View> snapshots = new ArrayList<View>(numSharedElements); if (numSharedElements == 0) { - return null; + return snapshots; } - ArrayList<View> snapshots = new ArrayList<View>(numSharedElements); Context context = getWindow().getContext(); int[] decorLoc = new int[2]; ViewGroup decorView = getDecor(); @@ -607,6 +699,8 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { mResultReceiver = null; mPendingTransition = null; mListener = null; + mRootSharedElements.clear(); + mSharedElementParentMatrices = null; } protected long getFadeDuration() { @@ -704,9 +798,10 @@ abstract class ActivityTransitionCoordinator extends ResultReceiver { } protected void moveSharedElementsToOverlay() { - if (!mWindow.getSharedElementsUseOverlay()) { + if (mWindow == null || !mWindow.getSharedElementsUseOverlay()) { return; } + setSharedElementMatrices(); int numSharedElements = mSharedElements.size(); ViewGroup decor = getDecor(); if (decor != null) { diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java index 1e1a613..854719d 100644 --- a/core/java/android/app/ApplicationPackageManager.java +++ b/core/java/android/app/ApplicationPackageManager.java @@ -1664,6 +1664,17 @@ final class ApplicationPackageManager extends PackageManager { * @hide */ public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) { + Drawable dr = loadUnbadgedItemIcon(itemInfo, appInfo); + if (itemInfo.showUserIcon != UserHandle.USER_NULL) { + return dr; + } + return getUserBadgedIcon(dr, new UserHandle(mContext.getUserId())); + } + + /** + * @hide + */ + public Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) { if (itemInfo.showUserIcon != UserHandle.USER_NULL) { Bitmap bitmap = getUserManager().getUserIcon(itemInfo.showUserIcon); if (bitmap == null) { @@ -1678,7 +1689,7 @@ final class ApplicationPackageManager extends PackageManager { if (dr == null) { dr = itemInfo.loadDefaultIcon(this); } - return getUserBadgedIcon(dr, new UserHandle(mContext.getUserId())); + return dr; } private Drawable getBadgedDrawable(Drawable drawable, Drawable badgeDrawable, diff --git a/core/java/android/app/EnterTransitionCoordinator.java b/core/java/android/app/EnterTransitionCoordinator.java index add67f2..7894887 100644 --- a/core/java/android/app/EnterTransitionCoordinator.java +++ b/core/java/android/app/EnterTransitionCoordinator.java @@ -57,7 +57,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { private boolean mIsViewsTransitionStarted; private boolean mIsViewsTransitionComplete; private boolean mIsSharedElementTransitionComplete; - private ArrayList<Matrix> mSharedElementParentMatrices; private Transition mEnterViewsTransition; public EnterTransitionCoordinator(Activity activity, ResultReceiver resultReceiver, @@ -122,7 +121,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { if (mIsReturning) { sendSharedElementDestination(); } else { - setSharedElementMatrices(); moveSharedElementsToOverlay(); } if (mSharedElementsBundle != null) { @@ -194,7 +192,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } if (allReady) { Bundle state = captureSharedElementState(); - setSharedElementMatrices(); moveSharedElementsToOverlay(); mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); } else if (decorView != null) { @@ -205,7 +202,6 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { decorView.getViewTreeObserver().removeOnPreDrawListener(this); if (mResultReceiver != null) { Bundle state = captureSharedElementState(); - setSharedElementMatrices(); moveSharedElementsToOverlay(); mResultReceiver.send(MSG_SHARED_ELEMENT_DESTINATION, state); } @@ -322,6 +318,7 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { if (mListener != null) { mListener.onRejectSharedElements(rejectedSnapshots); } + removeNullViews(rejectedSnapshots); startRejectedAnimations(rejectedSnapshots); // Now start shared element transition @@ -370,6 +367,16 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { } } + private static void removeNullViews(ArrayList<View> views) { + if (views != null) { + for (int i = views.size() - 1; i >= 0; i--) { + if (views.get(i) == null) { + views.remove(i); + } + } + } + } + private void onTakeSharedElements() { if (!mIsReadyForTransition || mSharedElementsBundle == null) { return; @@ -634,30 +641,4 @@ class EnterTransitionCoordinator extends ActivityTransitionCoordinator { }); } - private void setSharedElementMatrices() { - int numSharedElements = mSharedElements.size(); - if (numSharedElements > 0) { - mSharedElementParentMatrices = new ArrayList<Matrix>(numSharedElements); - } - for (int i = 0; i < numSharedElements; i++) { - View view = mSharedElements.get(i); - - // Find the location in the view's parent - ViewGroup parent = (ViewGroup) view.getParent(); - Matrix matrix = new Matrix(); - parent.transformMatrixToLocal(matrix); - - mSharedElementParentMatrices.add(matrix); - } - } - - @Override - protected void getSharedElementParentMatrix(View view, Matrix matrix) { - int index = mSharedElementParentMatrices == null ? -1 : mSharedElements.indexOf(view); - if (index < 0) { - super.getSharedElementParentMatrix(view, matrix); - } else { - matrix.set(mSharedElementParentMatrices.get(index)); - } - } } diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java index cc9aed8..5038df9 100644 --- a/core/java/android/app/KeyguardManager.java +++ b/core/java/android/app/KeyguardManager.java @@ -16,10 +16,14 @@ package android.app; +import android.app.trust.ITrustManager; +import android.content.Context; import android.content.Intent; import android.os.Binder; import android.os.RemoteException; import android.os.IBinder; +import android.os.ServiceManager; +import android.os.UserHandle; import android.view.IWindowManager; import android.view.IOnKeyguardExitResult; import android.view.WindowManagerGlobal; @@ -33,6 +37,7 @@ import android.view.WindowManagerGlobal; */ public class KeyguardManager { private IWindowManager mWM; + private ITrustManager mTrustManager; /** * Intent used to prompt user for device credentials. @@ -151,6 +156,8 @@ public class KeyguardManager { KeyguardManager() { mWM = WindowManagerGlobal.getWindowManagerService(); + mTrustManager = ITrustManager.Stub.asInterface( + ServiceManager.getService(Context.TRUST_SERVICE)); } /** @@ -218,6 +225,34 @@ public class KeyguardManager { } /** + * Return whether unlocking the device is currently not requiring a password + * because of a trust agent. + * + * @return true if the keyguard can currently be unlocked without entering credentials + * because the device is in a trusted environment. + */ + public boolean isKeyguardInTrustedState() { + return isKeyguardInTrustedState(UserHandle.getCallingUserId()); + } + + /** + * Return whether unlocking the device is currently not requiring a password + * because of a trust agent. + * + * @param userId the user for which the trusted state should be reported. + * @return true if the keyguard can currently be unlocked without entering credentials + * because the device is in a trusted environment. + * @hide + */ + public boolean isKeyguardInTrustedState(int userId) { + try { + return mTrustManager.isTrusted(userId); + } catch (RemoteException e) { + return false; + } + } + + /** * @deprecated Use {@link android.view.WindowManager.LayoutParams#FLAG_DISMISS_KEYGUARD} * and/or {@link android.view.WindowManager.LayoutParams#FLAG_SHOW_WHEN_LOCKED} * instead; this allows you to seamlessly hide the keyguard as your application diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index fb10e17..9849c51 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -23,6 +23,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.ColorStateList; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.PorterDuff; @@ -2773,6 +2774,14 @@ public class Notification implements Parcelable contentView.setViewVisibility(R.id.progress, View.VISIBLE); contentView.setProgressBar( R.id.progress, mProgressMax, mProgress, mProgressIndeterminate); + contentView.setProgressBackgroundTintList( + R.id.progress, ColorStateList.valueOf(mContext.getResources().getColor( + R.color.notification_progress_background_color))); + if (mColor != COLOR_DEFAULT) { + ColorStateList colorStateList = ColorStateList.valueOf(mColor); + contentView.setProgressTintList(R.id.progress, colorStateList); + contentView.setProgressIndeterminateTintList(R.id.progress, colorStateList); + } showLine2 = true; } else { contentView.setViewVisibility(R.id.progress, View.GONE); diff --git a/core/java/android/app/SharedElementCallback.java b/core/java/android/app/SharedElementCallback.java index 060bbe6..6ac2401 100644 --- a/core/java/android/app/SharedElementCallback.java +++ b/core/java/android/app/SharedElementCallback.java @@ -18,13 +18,16 @@ package android.app; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; +import android.os.Bundle; import android.os.Parcelable; import android.transition.TransitionUtils; import android.view.View; +import android.widget.ImageView; +import android.widget.ImageView.ScaleType; import java.util.List; import java.util.Map; @@ -40,6 +43,9 @@ import java.util.Map; */ public abstract class SharedElementCallback { private Matrix mTempMatrix; + private static final String BUNDLE_SNAPSHOT_BITMAP = "sharedElement:snapshot:bitmap"; + private static final String BUNDLE_SNAPSHOT_IMAGE_SCALETYPE = "sharedElement:snapshot:imageScaleType"; + private static final String BUNDLE_SNAPSHOT_IMAGE_MATRIX = "sharedElement:snapshot:imageMatrix"; static final SharedElementCallback NULL_CALLBACK = new SharedElementCallback() { }; @@ -142,6 +148,27 @@ public abstract class SharedElementCallback { */ public Parcelable onCaptureSharedElementSnapshot(View sharedElement, Matrix viewToGlobalMatrix, RectF screenBounds) { + if (sharedElement instanceof ImageView) { + ImageView imageView = ((ImageView) sharedElement); + Drawable d = imageView.getDrawable(); + Drawable bg = imageView.getBackground(); + if (d != null && (bg == null || bg.getAlpha() == 0)) { + Bitmap bitmap = TransitionUtils.createDrawableBitmap(d); + if (bitmap != null) { + Bundle bundle = new Bundle(); + bundle.putParcelable(BUNDLE_SNAPSHOT_BITMAP, bitmap); + bundle.putString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE, + imageView.getScaleType().toString()); + if (imageView.getScaleType() == ScaleType.MATRIX) { + Matrix matrix = imageView.getImageMatrix(); + float[] values = new float[9]; + matrix.getValues(values); + bundle.putFloatArray(BUNDLE_SNAPSHOT_IMAGE_MATRIX, values); + } + return bundle; + } + } + } if (mTempMatrix == null) { mTempMatrix = new Matrix(viewToGlobalMatrix); } else { @@ -169,7 +196,24 @@ public abstract class SharedElementCallback { */ public View onCreateSnapshotView(Context context, Parcelable snapshot) { View view = null; - if (snapshot instanceof Bitmap) { + if (snapshot instanceof Bundle) { + Bundle bundle = (Bundle) snapshot; + Bitmap bitmap = (Bitmap) bundle.getParcelable(BUNDLE_SNAPSHOT_BITMAP); + if (bitmap == null) { + return null; + } + ImageView imageView = new ImageView(context); + view = imageView; + imageView.setImageBitmap(bitmap); + imageView.setScaleType( + ScaleType.valueOf(bundle.getString(BUNDLE_SNAPSHOT_IMAGE_SCALETYPE))); + if (imageView.getScaleType() == ScaleType.MATRIX) { + float[] values = bundle.getFloatArray(BUNDLE_SNAPSHOT_IMAGE_MATRIX); + Matrix matrix = new Matrix(); + matrix.setValues(values); + imageView.setImageMatrix(matrix); + } + } else if (snapshot instanceof Bitmap) { Bitmap bitmap = (Bitmap) snapshot; view = new View(context); Resources resources = context.getResources(); diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java index 4aec9e0..b0dd70f 100644 --- a/core/java/android/app/UiAutomation.java +++ b/core/java/android/app/UiAutomation.java @@ -25,6 +25,7 @@ import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Point; import android.hardware.display.DisplayManagerGlobal; +import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -919,7 +920,7 @@ public final class UiAutomation { public IAccessibilityServiceClientImpl(Looper looper) { super(null, looper, new Callbacks() { @Override - public void onSetConnectionId(int connectionId) { + public void init(int connectionId, IBinder windowToken) { synchronized (mLock) { mConnectionId = connectionId; mLock.notifyAll(); diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl index 6fbf87d..0193711 100644 --- a/core/java/android/app/trust/ITrustManager.aidl +++ b/core/java/android/app/trust/ITrustManager.aidl @@ -29,4 +29,5 @@ interface ITrustManager { void reportRequireCredentialEntry(int userId); void registerTrustListener(in ITrustListener trustListener); void unregisterTrustListener(in ITrustListener trustListener); + boolean isTrusted(int userId); } diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java index 5564af7..f2e03cf 100644 --- a/core/java/android/bluetooth/BluetoothAdapter.java +++ b/core/java/android/bluetooth/BluetoothAdapter.java @@ -465,7 +465,8 @@ public final class BluetoothAdapter { if (getState() != STATE_ON) { return null; } - if (!isMultipleAdvertisementSupported()) { + if (!isMultipleAdvertisementSupported() && !isPeripheralModeSupported()) { + Log.e(TAG, "bluetooth le advertising not supported"); return null; } synchronized(mLock) { @@ -918,6 +919,21 @@ public final class BluetoothAdapter { } /** + * Returns whether peripheral mode is supported. + * + * @hide + */ + public boolean isPeripheralModeSupported() { + if (getState() != STATE_ON) return false; + try { + return mService.isPeripheralModeSupported(); + } catch (RemoteException e) { + Log.e(TAG, "failed to get peripheral mode capability: ", e); + } + return false; + } + + /** * Return true if offloaded filters are supported * * @return true if chipset supports on-chip filtering diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl index cf2a343..992f601 100644 --- a/core/java/android/bluetooth/IBluetooth.aidl +++ b/core/java/android/bluetooth/IBluetooth.aidl @@ -92,6 +92,7 @@ interface IBluetooth boolean configHciSnoopLog(boolean enable); boolean isMultiAdvertisementSupported(); + boolean isPeripheralModeSupported(); boolean isOffloadedFilteringSupported(); boolean isOffloadedScanBatchingSupported(); boolean isActivityAndEnergyReportingSupported(); diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java index d468508..a019d5c 100644 --- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java +++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java @@ -111,7 +111,8 @@ public final class BluetoothLeAdvertiser { if (callback == null) { throw new IllegalArgumentException("callback cannot be null"); } - if (!mBluetoothAdapter.isMultipleAdvertisementSupported()) { + if (!mBluetoothAdapter.isMultipleAdvertisementSupported() && + !mBluetoothAdapter.isPeripheralModeSupported()) { postStartFailure(callback, AdvertiseCallback.ADVERTISE_FAILED_FEATURE_UNSUPPORTED); return; diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java index a57c3ca..93ea299 100644 --- a/core/java/android/bluetooth/le/BluetoothLeScanner.java +++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java @@ -51,6 +51,7 @@ public final class BluetoothLeScanner { private static final String TAG = "BluetoothLeScanner"; private static final boolean DBG = true; + private static final boolean VDBG = false; private final IBluetoothManager mBluetoothManager; private final Handler mHandler; @@ -317,7 +318,7 @@ public final class BluetoothLeScanner { */ @Override public void onScanResult(final ScanResult scanResult) { - if (DBG) Log.d(TAG, "onScanResult() - " + scanResult.toString()); + if (VDBG) Log.d(TAG, "onScanResult() - " + scanResult.toString()); // Check null in case the scan has been stopped synchronized (this) { @@ -346,7 +347,7 @@ public final class BluetoothLeScanner { @Override public void onFoundOrLost(final boolean onFound, final ScanResult scanResult) { - if (DBG) { + if (VDBG) { Log.d(TAG, "onFoundOrLost() - onFound = " + onFound + " " + scanResult.toString()); } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index af6f181..7676e4b 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -876,12 +876,44 @@ public class Intent implements Parcelable, Cloneable { * related methods. */ public static Intent createChooser(Intent target, CharSequence title) { + return createChooser(target, title, null); + } + + /** + * Convenience function for creating a {@link #ACTION_CHOOSER} Intent. + * + * <p>Builds a new {@link #ACTION_CHOOSER} Intent that wraps the given + * target intent, also optionally supplying a title. If the target + * intent has specified {@link #FLAG_GRANT_READ_URI_PERMISSION} or + * {@link #FLAG_GRANT_WRITE_URI_PERMISSION}, then these flags will also be + * set in the returned chooser intent, with its ClipData set appropriately: + * either a direct reflection of {@link #getClipData()} if that is non-null, + * or a new ClipData built from {@link #getData()}.</p> + * + * <p>The caller may optionally supply an {@link IntentSender} to receive a callback + * when the user makes a choice. This can be useful if the calling application wants + * to remember the last chosen target and surface it as a more prominent or one-touch + * affordance elsewhere in the UI for next time.</p> + * + * @param target The Intent that the user will be selecting an activity + * to perform. + * @param title Optional title that will be displayed in the chooser. + * @param sender Optional IntentSender to be called when a choice is made. + * @return Return a new Intent object that you can hand to + * {@link Context#startActivity(Intent) Context.startActivity()} and + * related methods. + */ + public static Intent createChooser(Intent target, CharSequence title, IntentSender sender) { Intent intent = new Intent(ACTION_CHOOSER); intent.putExtra(EXTRA_INTENT, target); if (title != null) { intent.putExtra(EXTRA_TITLE, title); } + if (sender != null) { + intent.putExtra(EXTRA_CHOSEN_COMPONENT_INTENT_SENDER, sender); + } + // Migrate any clip data and flags from target. int permFlags = target.getFlags() & (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION | FLAG_GRANT_PERSISTABLE_URI_PERMISSION @@ -3140,6 +3172,26 @@ public class Intent implements Parcelable, Cloneable { "android.intent.extra.REPLACEMENT_EXTRAS"; /** + * An {@link IntentSender} that will be notified if a user successfully chooses a target + * component to handle an action in an {@link #ACTION_CHOOSER} activity. The IntentSender + * will have the extra {@link #EXTRA_CHOSEN_COMPONENT} appended to it containing the + * {@link ComponentName} of the chosen component. + * + * <p>In some situations this callback may never come, for example if the user abandons + * the chooser, switches to another task or any number of other reasons. Apps should not + * be written assuming that this callback will always occur.</p> + */ + public static final String EXTRA_CHOSEN_COMPONENT_INTENT_SENDER = + "android.intent.extra.CHOSEN_COMPONENT_INTENT_SENDER"; + + /** + * The {@link ComponentName} chosen by the user to complete an action. + * + * @see #EXTRA_CHOSEN_COMPONENT_INTENT_SENDER + */ + public static final String EXTRA_CHOSEN_COMPONENT = "android.intent.extra.CHOSEN_COMPONENT"; + + /** * A {@link android.view.KeyEvent} object containing the event that * triggered the creation of the Intent it is in. */ diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java index cacdf8e..22a899c 100644 --- a/core/java/android/content/pm/PackageItemInfo.java +++ b/core/java/android/content/pm/PackageItemInfo.java @@ -138,7 +138,7 @@ public class PackageItemInfo { } return packageName; } - + /** * Retrieve the current graphical icon associated with this item. This * will call back on the given PackageManager to load the icon from @@ -156,6 +156,23 @@ public class PackageItemInfo { } /** + * Retrieve the current graphical icon associated with this item without + * the addition of a work badge if applicable. + * This will call back on the given PackageManager to load the icon from + * the application. + * + * @param pm A PackageManager from which the icon can be loaded; usually + * the PackageManager from which you originally retrieved this item. + * + * @return Returns a Drawable containing the item's icon. If the + * item does not have an icon, the item's default icon is returned + * such as the default activity icon. + */ + public Drawable loadUnbadgedIcon(PackageManager pm) { + return pm.loadUnbadgedItemIcon(this, getApplicationInfo()); + } + + /** * Retrieve the current graphical banner associated with this item. This * will call back on the given PackageManager to load the banner from * the application. diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index e519163..ab90b66 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -3911,6 +3911,11 @@ public abstract class PackageManager { */ public abstract Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo); + /** + * @hide + */ + public abstract Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo); + /** {@hide} */ public abstract boolean isPackageAvailable(String packageName); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index ca4ff6a..8515520 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -74,7 +74,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; @@ -380,7 +379,7 @@ public class PackageParser { */ public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, - HashSet<String> grantedPermissions, PackageUserState state) { + ArraySet<String> grantedPermissions, PackageUserState state) { return generatePackageInfo(p, gids, flags, firstInstallTime, lastUpdateTime, grantedPermissions, state, UserHandle.getCallingUserId()); @@ -401,7 +400,7 @@ public class PackageParser { public static PackageInfo generatePackageInfo(PackageParser.Package p, int gids[], int flags, long firstInstallTime, long lastUpdateTime, - HashSet<String> grantedPermissions, PackageUserState state, int userId) { + ArraySet<String> grantedPermissions, PackageUserState state, int userId) { if (!checkUseInstalledOrHidden(flags, state)) { return null; diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java index 4dcad6f..a9c7be3 100644 --- a/core/java/android/content/pm/PackageUserState.java +++ b/core/java/android/content/pm/PackageUserState.java @@ -18,7 +18,7 @@ package android.content.pm; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; -import java.util.HashSet; +import android.util.ArraySet; /** * Per-user state information about a package. @@ -34,8 +34,8 @@ public class PackageUserState { public String lastDisableAppCaller; - public HashSet<String> disabledComponents; - public HashSet<String> enabledComponents; + public ArraySet<String> disabledComponents; + public ArraySet<String> enabledComponents; public PackageUserState() { installed = true; @@ -51,9 +51,9 @@ public class PackageUserState { hidden = o.hidden; lastDisableAppCaller = o.lastDisableAppCaller; disabledComponents = o.disabledComponents != null - ? new HashSet<String>(o.disabledComponents) : null; + ? new ArraySet<String>(o.disabledComponents) : null; enabledComponents = o.enabledComponents != null - ? new HashSet<String>(o.enabledComponents) : null; + ? new ArraySet<String>(o.enabledComponents) : null; blockUninstall = o.blockUninstall; } -}
\ No newline at end of file +} diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java index 27bbb24..acdd87e 100644 --- a/core/java/android/content/res/Configuration.java +++ b/core/java/android/content/res/Configuration.java @@ -1365,9 +1365,9 @@ public final class Configuration implements Parcelable, Comparable<Configuration ArrayList<String> parts = new ArrayList<String>(); if (config.mcc != 0) { - parts.add(config.mcc + "mcc"); + parts.add("mcc" + config.mcc); if (config.mnc != 0) { - parts.add(config.mnc + "mnc"); + parts.add("mnc" + config.mnc); } } diff --git a/core/java/android/content/res/ConfigurationBoundResourceCache.java b/core/java/android/content/res/ConfigurationBoundResourceCache.java new file mode 100644 index 0000000..cde7e84 --- /dev/null +++ b/core/java/android/content/res/ConfigurationBoundResourceCache.java @@ -0,0 +1,138 @@ +/* +* 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 android.content.res; + +import android.util.ArrayMap; +import android.util.LongSparseArray; +import java.lang.ref.WeakReference; + +/** + * A Cache class which can be used to cache resource objects that are easy to clone but more + * expensive to inflate. + * @hide + */ +public class ConfigurationBoundResourceCache<T> { + + private final ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>> mCache = + new ArrayMap<String, LongSparseArray<WeakReference<ConstantState<T>>>>(); + + final Resources mResources; + + /** + * Creates a Resource cache for the given Resources instance. + * + * @param resources The Resource which can be used when creating new instances. + */ + public ConfigurationBoundResourceCache(Resources resources) { + mResources = resources; + } + + /** + * Adds a new item to the cache. + * + * @param key A custom key that uniquely identifies the resource. + * @param theme The Theme instance where this resource was loaded. + * @param constantState The constant state that can create new instances of the resource. + * + */ + public void put(long key, Resources.Theme theme, ConstantState<T> constantState) { + if (constantState == null) { + return; + } + final String themeKey = theme == null ? "" : theme.getKey(); + LongSparseArray<WeakReference<ConstantState<T>>> themedCache; + synchronized (this) { + themedCache = mCache.get(themeKey); + if (themedCache == null) { + themedCache = new LongSparseArray<WeakReference<ConstantState<T>>>(1); + mCache.put(themeKey, themedCache); + } + themedCache.put(key, new WeakReference<ConstantState<T>>(constantState)); + } + } + + /** + * If the resource is cached, creates a new instance of it and returns. + * + * @param key The long key which can be used to uniquely identify the resource. + * @param theme The The Theme instance where we want to load this resource. + * + * @return If this resources was loaded before, returns a new instance of it. Otherwise, returns + * null. + */ + public T get(long key, Resources.Theme theme) { + final String themeKey = theme != null ? theme.getKey() : ""; + final LongSparseArray<WeakReference<ConstantState<T>>> themedCache; + final WeakReference<ConstantState<T>> wr; + synchronized (this) { + themedCache = mCache.get(themeKey); + if (themedCache == null) { + return null; + } + wr = themedCache.get(key); + } + if (wr == null) { + return null; + } + final ConstantState entry = wr.get(); + if (entry != null) { + return (T) entry.newInstance(mResources, theme); + } else { // our entry has been purged + synchronized (this) { + // there is a potential race condition here where this entry may be put in + // another thread. But we prefer it to minimize lock duration + themedCache.delete(key); + } + } + return null; + } + + /** + * Users of ConfigurationBoundResourceCache must call this method whenever a configuration + * change happens. On this callback, the cache invalidates all resources that are not valid + * anymore. + * + * @param configChanges The configuration changes + */ + public void onConfigurationChange(final int configChanges) { + synchronized (this) { + final int size = mCache.size(); + for (int i = size - 1; i >= 0; i--) { + final LongSparseArray<WeakReference<ConstantState<T>>> + themeCache = mCache.valueAt(i); + onConfigurationChangeInt(themeCache, configChanges); + if (themeCache.size() == 0) { + mCache.removeAt(i); + } + } + } + } + + private void onConfigurationChangeInt( + final LongSparseArray<WeakReference<ConstantState<T>>> themeCache, + final int configChanges) { + final int size = themeCache.size(); + for (int i = size - 1; i >= 0; i--) { + final WeakReference<ConstantState<T>> wr = themeCache.valueAt(i); + final ConstantState<T> constantState = wr.get(); + if (constantState == null || Configuration.needNewResources( + configChanges, constantState.getChangingConfigurations())) { + themeCache.removeAt(i); + } + } + } + +} diff --git a/core/java/android/content/res/ConstantState.java b/core/java/android/content/res/ConstantState.java new file mode 100644 index 0000000..ee609df --- /dev/null +++ b/core/java/android/content/res/ConstantState.java @@ -0,0 +1,61 @@ +/* +* 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 android.content.res; + +/** + * A cache class that can provide new instances of a particular resource which may change + * depending on the current {@link Resources.Theme} or {@link Configuration}. + * <p> + * A constant state should be able to return a bitmask of changing configurations, which + * identifies the type of configuration changes that may invalidate this resource. These + * configuration changes can be obtained from {@link android.util.TypedValue}. Entities such as + * {@link android.animation.Animator} also provide a changing configuration method to include + * their dependencies (e.g. An AnimatorSet's changing configuration is the union of the + * changing configurations of each Animator in the set) + * @hide + */ +abstract public class ConstantState<T> { + + /** + * Return a bit mask of configuration changes that will impact + * this resource (and thus require completely reloading it). + */ + abstract public int getChangingConfigurations(); + + /** + * Create a new instance without supplying resources the caller + * is running in. + */ + public abstract T newInstance(); + + /** + * Create a new instance from its constant state. This + * must be implemented for resources that change based on the target + * density of their caller (that is depending on whether it is + * in compatibility mode). + */ + public T newInstance(Resources res) { + return newInstance(); + } + + /** + * Create a new instance from its constant state. This must be + * implemented for resources that can have a theme applied. + */ + public T newInstance(Resources res, Resources.Theme theme) { + return newInstance(res); + } +} diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 7f276c2..6e9efe1 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -16,6 +16,8 @@ package android.content.res; +import android.animation.Animator; +import android.animation.StateListAnimator; import android.util.Pools.SynchronizedPool; import android.view.ViewDebug; import com.android.internal.util.XmlUtils; @@ -115,6 +117,10 @@ public class Resources { new ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>>(); private final LongSparseArray<WeakReference<ColorStateList>> mColorStateListCache = new LongSparseArray<WeakReference<ColorStateList>>(); + private final ConfigurationBoundResourceCache<Animator> mAnimatorCache = + new ConfigurationBoundResourceCache<Animator>(this); + private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache = + new ConfigurationBoundResourceCache<StateListAnimator>(this); private TypedValue mTmpValue = new TypedValue(); private boolean mPreloading; @@ -183,6 +189,24 @@ public class Resources { } /** + * Used by AnimatorInflater. + * + * @hide + */ + public ConfigurationBoundResourceCache<Animator> getAnimatorCache() { + return mAnimatorCache; + } + + /** + * Used by AnimatorInflater. + * + * @hide + */ + public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() { + return mStateListAnimatorCache; + } + + /** * This exception is thrown by the resource APIs when a requested resource * can not be found. */ @@ -1761,23 +1785,7 @@ public class Resources { // the framework. mCompatibilityInfo.applyToDisplayMetrics(mMetrics); - int configChanges = 0xfffffff; - if (config != null) { - mTmpConfig.setTo(config); - int density = config.densityDpi; - if (density == Configuration.DENSITY_DPI_UNDEFINED) { - density = mMetrics.noncompatDensityDpi; - } - - mCompatibilityInfo.applyToConfiguration(density, mTmpConfig); - - if (mTmpConfig.locale == null) { - mTmpConfig.locale = Locale.getDefault(); - mTmpConfig.setLayoutDirection(mTmpConfig.locale); - } - configChanges = mConfiguration.updateFrom(mTmpConfig); - configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); - } + int configChanges = calcConfigChanges(config); if (mConfiguration.locale == null) { mConfiguration.locale = Locale.getDefault(); mConfiguration.setLayoutDirection(mConfiguration.locale); @@ -1825,6 +1833,8 @@ public class Resources { clearDrawableCachesLocked(mDrawableCache, configChanges); clearDrawableCachesLocked(mColorDrawableCache, configChanges); + mAnimatorCache.onConfigurationChange(configChanges); + mStateListAnimatorCache.onConfigurationChange(configChanges); mColorStateListCache.clear(); @@ -1837,6 +1847,30 @@ public class Resources { } } + /** + * Called by ConfigurationBoundResourceCacheTest via reflection. + */ + private int calcConfigChanges(Configuration config) { + int configChanges = 0xfffffff; + if (config != null) { + mTmpConfig.setTo(config); + int density = config.densityDpi; + if (density == Configuration.DENSITY_DPI_UNDEFINED) { + density = mMetrics.noncompatDensityDpi; + } + + mCompatibilityInfo.applyToConfiguration(density, mTmpConfig); + + if (mTmpConfig.locale == null) { + mTmpConfig.locale = Locale.getDefault(); + mTmpConfig.setLayoutDirection(mTmpConfig.locale); + } + configChanges = mConfiguration.updateFrom(mTmpConfig); + configChanges = ActivityInfo.activityInfoConfigToNative(configChanges); + } + return configChanges; + } + private void clearDrawableCachesLocked( ArrayMap<String, LongSparseArray<WeakReference<ConstantState>>> caches, int configChanges) { @@ -2323,7 +2357,14 @@ public class Resources { final Drawable dr; if (cs != null) { - dr = cs.newDrawable(this, theme); + final Drawable clonedDr = cs.newDrawable(this); + if (theme != null) { + dr = clonedDr.mutate(); + dr.applyTheme(theme); + dr.clearMutated(); + } else { + dr = clonedDr; + } } else if (isColorDrawable) { dr = new ColorDrawable(value.data); } else { diff --git a/core/java/android/content/res/ResourcesKey.java b/core/java/android/content/res/ResourcesKey.java index e0f1b3a..4ae3825 100644 --- a/core/java/android/content/res/ResourcesKey.java +++ b/core/java/android/content/res/ResourcesKey.java @@ -62,10 +62,15 @@ public final class ResourcesKey { return false; } ResourcesKey peer = (ResourcesKey) obj; - if (mResDir != peer.mResDir) { - if (mResDir == null || peer.mResDir == null) { - return false; - } else if (!mResDir.equals(peer.mResDir)) { + + if ((mResDir == null) && (peer.mResDir != null)) { + return false; + } + if ((mResDir != null) && (peer.mResDir == null)) { + return false; + } + if ((mResDir != null) && (peer.mResDir != null)) { + if (!mResDir.equals(peer.mResDir)) { return false; } } diff --git a/core/java/android/hardware/Sensor.java b/core/java/android/hardware/Sensor.java index f514e42..cf6a779 100644 --- a/core/java/android/hardware/Sensor.java +++ b/core/java/android/hardware/Sensor.java @@ -329,7 +329,11 @@ public final class Sensor { * A sensor of this type triggers an event each time a step is taken by the user. The only * allowed value to return is 1.0 and an event is generated for each step. Like with any other * event, the timestamp indicates when the event (here the step) occurred, this corresponds to - * when the foot hit the ground, generating a high variation in acceleration. + * when the foot hit the ground, generating a high variation in acceleration. This sensor is + * only for detecting every individual step as soon as it is taken, for example to perform dead + * reckoning. If you only need aggregate number of steps taken over a period of time, register + * for {@link #TYPE_STEP_COUNTER} instead. It is defined as a + * {@link Sensor#REPORTING_MODE_SPECIAL_TRIGGER} sensor. * <p> * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. */ @@ -349,7 +353,12 @@ public final class Sensor { * while activated. The value is returned as a float (with the fractional part set to zero) and * is reset to zero only on a system reboot. The timestamp of the event is set to the time when * the last step for that event was taken. This sensor is implemented in hardware and is - * expected to be low power. + * expected to be low power. If you want to continuously track the number of steps over a long + * period of time, do NOT unregister for this sensor, so that it keeps counting steps in the + * background even when the AP is in suspend mode and report the aggregate count when the AP + * is awake. Application needs to stay registered for this sensor because step counter does not + * count steps if it is not activated. This sensor is ideal for fitness tracking applications. + * It is defined as an {@link Sensor#REPORTING_MODE_ON_CHANGE} sensor. * <p> * See {@link android.hardware.SensorEvent#values SensorEvent.values} for more details. */ @@ -750,31 +759,41 @@ public final class Sensor { } /** - * Returns whether this sensor is a wake-up sensor. + * Returns true if the sensor is a wake-up sensor. * <p> - * Wake up sensors wake the application processor up when they have events to deliver. When a - * wake up sensor is registered to without batching enabled, each event will wake the - * application processor up. - * <p> - * When a wake up sensor is registered to with batching enabled, it - * wakes the application processor up when maxReportingLatency has elapsed or when the hardware - * FIFO storing the events from wake up sensors is getting full. - * <p> - * Non-wake up sensors never wake the application processor up. Their events are only reported - * when the application processor is awake, for example because the application holds a wake - * lock, or another source woke the application processor up. + * <b>Application Processor Power modes</b> <p> + * Application Processor(AP), is the processor on which applications run. When no wake lock is held + * and the user is not interacting with the device, this processor can enter a “Suspend” mode, + * reducing the power consumption by 10 times or more. + * </p> * <p> - * When a non-wake up sensor is registered to without batching enabled, the measurements made - * while the application processor is asleep might be lost and never returned. + * <b>Non-wake-up sensors</b> <p> + * Non-wake-up sensors are sensors that do not wake the AP out of suspend to report data. While + * the AP is in suspend mode, the sensors continue to function and generate events, which are + * put in a hardware FIFO. The events in the FIFO are delivered to the application when the AP + * wakes up. If the FIFO was too small to store all events generated while the AP was in + * suspend mode, the older events are lost: the oldest data is dropped to accommodate the newer + * data. In the extreme case where the FIFO is non-existent {@code maxFifoEventCount() == 0}, + * all events generated while the AP was in suspend mode are lost. Applications using + * non-wake-up sensors should usually: + * <ul> + * <li>Either unregister from the sensors when they do not need them, usually in the activity’s + * {@code onPause} method. This is the most common case. + * <li>Or realize that the sensors are consuming some power while the AP is in suspend mode and + * that even then, some events might be lost. + * </ul> + * </p> * <p> - * When a non-wake up sensor is registered to with batching enabled, the measurements made while - * the application processor is asleep are stored in the hardware FIFO for non-wake up sensors. - * When this FIFO gets full, new events start overwriting older events. When the application - * then wakes up, the latest events are returned, and some old events might be lost. The number - * of events actually returned depends on the hardware FIFO size, as well as on what other - * sensors are activated. If losing sensor events is not acceptable during batching, you must - * use the wake-up version of the sensor. - * @return true if this is a wake up sensor, false otherwise. + * <b>Wake-up sensors</b> <p> + * In opposition to non-wake-up sensors, wake-up sensors ensure that their data is delivered + * independently of the state of the AP. While the AP is awake, the wake-up sensors behave + * like non-wake-up-sensors. When the AP is asleep, wake-up sensors wake up the AP to deliver + * events. That is, the AP will wake up and the sensor will deliver the events before the + * maximum reporting latency is elapsed or the hardware FIFO gets full. See {@link + * SensorManager#registerListener(SensorEventListener, Sensor, int, int)} for more details. + * </p> + * + * @return <code>true</code> if this is a wake-up sensor, <code>false</code> otherwise. */ public boolean isWakeUpSensor() { return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0; diff --git a/core/java/android/hardware/SensorEventListener2.java b/core/java/android/hardware/SensorEventListener2.java index 70eff08..fd3e62b 100644 --- a/core/java/android/hardware/SensorEventListener2.java +++ b/core/java/android/hardware/SensorEventListener2.java @@ -21,15 +21,16 @@ package android.hardware; */ public interface SensorEventListener2 extends SensorEventListener { /** - * Called after flush() is completed. All the events in the batch at the point when - * the flush was called have been delivered to the applications registered for those - * sensor events. Flush Complete Events are sent ONLY to the application that has - * explicitly called flush(). If the hardware FIFO is flushed due to some other - * application calling flush(), flush complete event is not delivered to this application. + * Called after flush() is completed. All the events in the batch at the point when the flush + * was called have been delivered to the applications registered for those sensor events. In + * {@link android.os.Build.VERSION_CODES#KITKAT}, applications may receive flush complete events + * even if some other application has called flush() on the same sensor. Starting with + * {@link android.os.Build.VERSION_CODES#LOLLIPOP}, flush Complete events are sent ONLY to the + * application that has explicitly called flush(). If the hardware FIFO is flushed due to some + * other application calling flush(), flush complete event is not delivered to this application. * <p> * * @param sensor The {@link android.hardware.Sensor Sensor} on which flush was called. - * * @see android.hardware.SensorManager#flush(SensorEventListener) */ public void onFlushCompleted(Sensor sensor); diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index cccd624..e4e5a8c 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -626,73 +626,90 @@ public abstract class SensorManager { protected abstract void unregisterListenerImpl(SensorEventListener listener, Sensor sensor); /** - * Registers a {@link android.hardware.SensorEventListener - * SensorEventListener} for the given sensor. - * - * <p class="note"></p> - * Note: Don't use this method with a one shot trigger sensor such as - * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. - * Use {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. + * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given + * sensor at the given sampling frequency. + * <p> + * The events will be delivered to the provided {@code SensorEventListener} as soon as they are + * available. To reduce the power consumption, applications can use + * {@link #registerListener(SensorEventListener, Sensor, int, int)} instead and specify a + * positive non-zero maximum reporting latency. + * </p> + * <p> + * In the case of non-wake-up sensors, the events are only delivered while the Application + * Processor (AP) is not in suspend mode. See {@link Sensor#isWakeUpSensor()} for more details. + * To ensure delivery of events from non-wake-up sensors even when the screen is OFF, the + * application registering to the sensor must hold a partial wake-lock to keep the AP awake, + * otherwise some events might be lost while the AP is asleep. Note that although events might + * be lost while the AP is asleep, the sensor will still consume power if it is not explicitly + * deactivated by the application. Applications must unregister their {@code + * SensorEventListener}s in their activity's {@code onPause()} method to avoid consuming power + * while the device is inactive. See {@link #registerListener(SensorEventListener, Sensor, int, + * int)} for more details on hardware FIFO (queueing) capabilities and when some sensor events + * might be lost. + * </p> + * <p> + * In the case of wake-up sensors, each event generated by the sensor will cause the AP to + * wake-up, ensuring that each event can be delivered. Because of this, registering to a wake-up + * sensor has very significant power implications. Call {@link Sensor#isWakeUpSensor()} to check + * whether a sensor is a wake-up sensor. See + * {@link #registerListener(SensorEventListener, Sensor, int, int)} for information on how to + * reduce the power impact of registering to wake-up sensors. + * </p> + * <p class="note"> + * Note: Don't use this method with one-shot trigger sensors such as + * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use + * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. Use + * {@link Sensor#getReportingMode()} to obtain the reporting mode of a given sensor. * </p> * - * @param listener - * A {@link android.hardware.SensorEventListener SensorEventListener} - * object. - * - * @param sensor - * The {@link android.hardware.Sensor Sensor} to register to. - * - * @param rateUs - * The rate {@link android.hardware.SensorEvent sensor events} are - * delivered at. This is only a hint to the system. Events may be - * received faster or slower than the specified rate. Usually events - * are received faster. The value must be one of - * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, - * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST} - * or, the desired delay between events in microseconds. - * Specifying the delay in microseconds only works from Android - * 2.3 (API level 9) onwards. For earlier releases, you must use - * one of the {@code SENSOR_DELAY_*} constants. - * - * @return <code>true</code> if the sensor is supported and successfully - * enabled. - * + * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object. + * @param sensor The {@link android.hardware.Sensor Sensor} to register to. + * @param samplingPeriodUs The rate {@link android.hardware.SensorEvent sensor events} are + * delivered at. This is only a hint to the system. Events may be received faster or + * slower than the specified rate. Usually events are received faster. The value must + * be one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, + * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST} or, the desired delay + * between events in microseconds. Specifying the delay in microseconds only works + * from Android 2.3 (API level 9) onwards. For earlier releases, you must use one of + * the {@code SENSOR_DELAY_*} constants. + * @return <code>true</code> if the sensor is supported and successfully enabled. * @see #registerListener(SensorEventListener, Sensor, int, Handler) * @see #unregisterListener(SensorEventListener) * @see #unregisterListener(SensorEventListener, Sensor) - * */ - public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs) { - return registerListener(listener, sensor, rateUs, null); + public boolean registerListener(SensorEventListener listener, Sensor sensor, + int samplingPeriodUs) { + return registerListener(listener, sensor, samplingPeriodUs, null); } /** - * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. If the - * underlying hardware does not support batch mode, this defaults to - * {@link #registerListener(SensorEventListener, Sensor, int)} and other parameters are - * ignored. In non-batch mode, all sensor events must be reported as soon as they are detected. - * While in batch mode, sensor events do not need to be reported as soon as they are detected. - * They can be temporarily stored in batches and reported in batches, as long as no event is - * delayed by more than "maxBatchReportLatency" microseconds. That is, all events since the - * previous batch are recorded and returned all at once. This allows to reduce the amount of - * interrupts sent to the SoC, and allows the SoC to switch to a lower power state (Idle) while - * the sensor is capturing and batching data. - * <p> - * Registering to a sensor in batch mode will not prevent the SoC from going to suspend mode. In - * this case, the sensor will continue to gather events and store it in a hardware FIFO. If the - * FIFO gets full before the AP wakes up again, some events will be lost, as the older events - * get overwritten by new events in the hardware FIFO. This can be avoided by holding a wake - * lock. If the application holds a wake lock, the SoC will not go to suspend mode, so no events - * will be lost, as the events will be reported before the FIFO gets full. - * </p> + * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given + * sensor at the given sampling frequency and the given maximum reporting latency. * <p> - * Batching is always best effort. If a different application requests updates in continuous - * mode, this application will also get events in continuous mode. Batch mode updates can be - * unregistered by calling {@link #unregisterListener(SensorEventListener)}. + * This function is similar to {@link #registerListener(SensorEventListener, Sensor, int)} but + * it allows events to stay temporarily in the hardware FIFO (queue) before being delivered. The + * events can be stored in the hardware FIFO up to {@code maxReportLatencyUs} microseconds. Once + * one of the events in the FIFO needs to be reported, all of the events in the FIFO are + * reported sequentially. This means that some events will be reported before the maximum + * reporting latency has elapsed. + * </p><p> + * When {@code maxReportLatencyUs} is 0, the call is equivalent to a call to + * {@link #registerListener(SensorEventListener, Sensor, int)}, as it requires the events to be + * delivered as soon as possible. + * </p><p> + * When {@code sensor.maxFifoEventCount()} is 0, the sensor does not use a FIFO, so the call + * will also be equivalent to {@link #registerListener(SensorEventListener, Sensor, int)}. + * </p><p> + * Setting {@code maxReportLatencyUs} to a positive value allows to reduce the number of + * interrupts the AP (Application Processor) receives, hence reducing power consumption, as the + * AP can switch to a lower power state while the sensor is capturing the data. This is + * especially important when registering to wake-up sensors, for which each interrupt causes the + * AP to wake up if it was in suspend mode. See {@link Sensor#isWakeUpSensor()} for more + * information on wake-up sensors. * </p> * <p class="note"> * </p> - * Note: Don't use this method with a one shot trigger sensor such as + * Note: Don't use this method with one-shot trigger sensors such as * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p> * @@ -701,118 +718,104 @@ public abstract class SensorManager { * flush complete notifications, it should register with * {@link android.hardware.SensorEventListener SensorEventListener2} instead. * @param sensor The {@link android.hardware.Sensor Sensor} to register to. - * @param rateUs The desired delay between two consecutive events in microseconds. This is only - * a hint to the system. Events may be received faster or slower than the specified - * rate. Usually events are received faster. Can be one of + * @param samplingPeriodUs The desired delay between two consecutive events in microseconds. + * This is only a hint to the system. Events may be received faster or slower than + * the specified rate. Usually events are received faster. Can be one of * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, * {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in * microseconds. - * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most - * maxBatchReportLatency microseconds. More events can be batched if this value is - * large. If this is set to zero, batch mode is disabled and events are delivered in - * continuous mode as soon as they are available which is equivalent to calling + * @param maxReportLatencyUs Maximum time in microseconds that events can be delayed before + * being reported to the application. A large value allows reducing the power + * consumption associated with the sensor. If maxReportLatencyUs is set to zero, + * events are delivered as soon as they are available, which is equivalent to calling * {@link #registerListener(SensorEventListener, Sensor, int)}. - * @return <code>true</code> if batch mode is successfully enabled for this sensor, - * <code>false</code> otherwise. + * @return <code>true</code> if the sensor is supported and successfully enabled. * @see #registerListener(SensorEventListener, Sensor, int) * @see #unregisterListener(SensorEventListener) * @see #flush(SensorEventListener) */ - public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, - int maxBatchReportLatencyUs) { - int delay = getDelay(rateUs); - return registerListenerImpl(listener, sensor, delay, null, maxBatchReportLatencyUs, 0); + public boolean registerListener(SensorEventListener listener, Sensor sensor, + int samplingPeriodUs, int maxReportLatencyUs) { + int delay = getDelay(samplingPeriodUs); + return registerListenerImpl(listener, sensor, delay, null, maxReportLatencyUs, 0); } /** * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given * sensor. Events are delivered in continuous mode as soon as they are available. To reduce the - * battery usage, use {@link #registerListener(SensorEventListener, Sensor, int, int)} which - * enables batch mode for the sensor. - * - * <p class="note"></p> - * Note: Don't use this method with a one shot trigger sensor such as - * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. - * Use {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. + * power consumption, applications can use + * {@link #registerListener(SensorEventListener, Sensor, int, int)} instead and specify a + * positive non-zero maximum reporting latency. + * <p class="note"> * </p> + * Note: Don't use this method with a one shot trigger sensor such as + * {@link Sensor#TYPE_SIGNIFICANT_MOTION}. Use + * {@link #requestTriggerSensor(TriggerEventListener, Sensor)} instead. </p> * - * @param listener - * A {@link android.hardware.SensorEventListener SensorEventListener} - * object. - * - * @param sensor - * The {@link android.hardware.Sensor Sensor} to register to. - * - * @param rateUs - * The rate {@link android.hardware.SensorEvent sensor events} are - * delivered at. This is only a hint to the system. Events may be - * received faster or slower than the specified rate. Usually events - * are received faster. The value must be one of - * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, - * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST}. - * or, the desired delay between events in microseconds. - * Specifying the delay in microseconds only works from Android - * 2.3 (API level 9) onwards. For earlier releases, you must use - * one of the {@code SENSOR_DELAY_*} constants. - * - * @param handler - * The {@link android.os.Handler Handler} the - * {@link android.hardware.SensorEvent sensor events} will be - * delivered to. - * + * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object. + * @param sensor The {@link android.hardware.Sensor Sensor} to register to. + * @param samplingPeriodUs The rate {@link android.hardware.SensorEvent sensor events} are + * delivered at. This is only a hint to the system. Events may be received faster or + * slower than the specified rate. Usually events are received faster. The value must + * be one of {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, + * {@link #SENSOR_DELAY_GAME}, or {@link #SENSOR_DELAY_FASTEST} or, the desired + * delay between events in microseconds. Specifying the delay in microseconds only + * works from Android 2.3 (API level 9) onwards. For earlier releases, you must use + * one of the {@code SENSOR_DELAY_*} constants. + * @param handler The {@link android.os.Handler Handler} the {@link android.hardware.SensorEvent + * sensor events} will be delivered to. * @return <code>true</code> if the sensor is supported and successfully enabled. - * * @see #registerListener(SensorEventListener, Sensor, int) * @see #unregisterListener(SensorEventListener) * @see #unregisterListener(SensorEventListener, Sensor) */ - public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, - Handler handler) { - int delay = getDelay(rateUs); + public boolean registerListener(SensorEventListener listener, Sensor sensor, + int samplingPeriodUs, Handler handler) { + int delay = getDelay(samplingPeriodUs); return registerListenerImpl(listener, sensor, delay, handler, 0, 0); } /** - * Enables batch mode for a sensor with the given rate and maxBatchReportLatency. + * Registers a {@link android.hardware.SensorEventListener SensorEventListener} for the given + * sensor at the given sampling frequency and the given maximum reporting latency. + * * @param listener A {@link android.hardware.SensorEventListener SensorEventListener} object * that will receive the sensor events. If the application is interested in receiving * flush complete notifications, it should register with * {@link android.hardware.SensorEventListener SensorEventListener2} instead. * @param sensor The {@link android.hardware.Sensor Sensor} to register to. - * @param rateUs The desired delay between two consecutive events in microseconds. This is only - * a hint to the system. Events may be received faster or slower than the specified - * rate. Usually events are received faster. Can be one of + * @param samplingPeriodUs The desired delay between two consecutive events in microseconds. + * This is only a hint to the system. Events may be received faster or slower than + * the specified rate. Usually events are received faster. Can be one of * {@link #SENSOR_DELAY_NORMAL}, {@link #SENSOR_DELAY_UI}, * {@link #SENSOR_DELAY_GAME}, {@link #SENSOR_DELAY_FASTEST} or the delay in * microseconds. - * @param maxBatchReportLatencyUs An event in the batch can be delayed by at most - * maxBatchReportLatency microseconds. More events can be batched if this value is - * large. If this is set to zero, batch mode is disabled and events are delivered in - * continuous mode as soon as they are available which is equivalent to calling + * @param maxReportLatencyUs Maximum time in microseconds that events can be delayed before + * being reported to the application. A large value allows reducing the power + * consumption associated with the sensor. If maxReportLatencyUs is set to zero, + * events are delivered as soon as they are available, which is equivalent to calling * {@link #registerListener(SensorEventListener, Sensor, int)}. - * @param handler The {@link android.os.Handler Handler} the - * {@link android.hardware.SensorEvent sensor events} will be delivered to. - * - * @return <code>true</code> if batch mode is successfully enabled for this sensor, - * <code>false</code> otherwise. + * @param handler The {@link android.os.Handler Handler} the {@link android.hardware.SensorEvent + * sensor events} will be delivered to. + * @return <code>true</code> if the sensor is supported and successfully enabled. * @see #registerListener(SensorEventListener, Sensor, int, int) */ - public boolean registerListener(SensorEventListener listener, Sensor sensor, int rateUs, - int maxBatchReportLatencyUs, Handler handler) { - int delayUs = getDelay(rateUs); - return registerListenerImpl(listener, sensor, delayUs, handler, maxBatchReportLatencyUs, 0); + public boolean registerListener(SensorEventListener listener, Sensor sensor, int samplingPeriodUs, + int maxReportLatencyUs, Handler handler) { + int delayUs = getDelay(samplingPeriodUs); + return registerListenerImpl(listener, sensor, delayUs, handler, maxReportLatencyUs, 0); } /** @hide */ protected abstract boolean registerListenerImpl(SensorEventListener listener, Sensor sensor, - int delayUs, Handler handler, int maxBatchReportLatencyUs, int reservedFlags); + int delayUs, Handler handler, int maxReportLatencyUs, int reservedFlags); /** - * Flushes the batch FIFO of all the sensors registered for this listener. If there are events - * in the FIFO of the sensor, they are returned as if the batch timeout in the FIFO of the - * sensors had expired. Events are returned in the usual way through the SensorEventListener. - * This call doesn't affect the batch timeout for this sensor. This call is asynchronous and + * Flushes the FIFO of all the sensors registered for this listener. If there are events + * in the FIFO of the sensor, they are returned as if the maxReportLantecy of the FIFO has + * expired. Events are returned in the usual way through the SensorEventListener. + * This call doesn't affect the maxReportLantecy for this sensor. This call is asynchronous and * returns immediately. * {@link android.hardware.SensorEventListener2#onFlushCompleted onFlushCompleted} is called * after all the events in the batch at the time of calling this method have been delivered diff --git a/core/java/android/hardware/hdmi/HdmiClient.java b/core/java/android/hardware/hdmi/HdmiClient.java index aba90e4..45a79e1 100644 --- a/core/java/android/hardware/hdmi/HdmiClient.java +++ b/core/java/android/hardware/hdmi/HdmiClient.java @@ -3,13 +3,12 @@ package android.hardware.hdmi; import android.annotation.NonNull; import android.annotation.SystemApi; import android.hardware.hdmi.HdmiControlManager.VendorCommandListener; -import android.hardware.hdmi.IHdmiVendorCommandListener; import android.os.RemoteException; import android.util.Log; /** * Parent for classes of various HDMI-CEC device type used to access - * {@link HdmiControlService}. Contains methods and data used in common. + * the HDMI control system service. Contains methods and data used in common. * * @hide */ @@ -17,11 +16,13 @@ import android.util.Log; public abstract class HdmiClient { private static final String TAG = "HdmiClient"; - protected final IHdmiControlService mService; + /* package */ final IHdmiControlService mService; - protected abstract int getDeviceType(); + private IHdmiVendorCommandListener mIHdmiVendorCommandListener; - public HdmiClient(IHdmiControlService service) { + /* package */ abstract int getDeviceType(); + + /* package */ HdmiClient(IHdmiControlService service) { mService = service; } @@ -41,7 +42,7 @@ public abstract class HdmiClient { } /** - * Send a key event to other logical device. + * Sends a key event to other logical device. * * @param keyCode key code to send. Defined in {@link android.view.KeyEvent}. * @param isPressed true if this is key press event @@ -55,7 +56,7 @@ public abstract class HdmiClient { } /** - * Send vendor-specific command. + * Sends vendor-specific command. * * @param targetAddress address of the target device * @param params vendor-specific parameter. For <Vendor Command With ID> do not @@ -72,18 +73,23 @@ public abstract class HdmiClient { } /** - * Add a listener used to receive incoming vendor-specific command. + * Sets a listener used to receive incoming vendor-specific command. * * @param listener listener object */ - public void addVendorCommandListener(@NonNull VendorCommandListener listener) { + public void setVendorCommandListener(@NonNull VendorCommandListener listener) { if (listener == null) { throw new IllegalArgumentException("listener cannot be null"); } + if (mIHdmiVendorCommandListener != null) { + throw new IllegalStateException("listener was already set"); + } try { - mService.addVendorCommandListener(getListenerWrapper(listener), getDeviceType()); + IHdmiVendorCommandListener wrappedListener = getListenerWrapper(listener); + mService.addVendorCommandListener(wrappedListener, getDeviceType()); + mIHdmiVendorCommandListener = wrappedListener; } catch (RemoteException e) { - Log.e(TAG, "failed to add vendor command listener: ", e); + Log.e(TAG, "failed to set vendor command listener: ", e); } } @@ -91,8 +97,13 @@ public abstract class HdmiClient { final VendorCommandListener listener) { return new IHdmiVendorCommandListener.Stub() { @Override - public void onReceived(int srcAddress, byte[] params, boolean hasVendorId) { - listener.onReceived(srcAddress, params, hasVendorId); + public void onReceived(int srcAddress, int destAddress, byte[] params, + boolean hasVendorId) { + listener.onReceived(srcAddress, destAddress, params, hasVendorId); + } + @Override + public void onControlStateChanged(boolean enabled, int reason) { + listener.onControlStateChanged(enabled, reason); } }; } diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java index 30f3576..308a219 100644 --- a/core/java/android/hardware/hdmi/HdmiControlManager.java +++ b/core/java/android/hardware/hdmi/HdmiControlManager.java @@ -21,6 +21,8 @@ import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.annotation.SystemApi; import android.os.RemoteException; +import android.util.ArrayMap; +import android.util.Log; /** * The {@link HdmiControlManager} class is used to send HDMI control messages @@ -36,6 +38,8 @@ import android.os.RemoteException; */ @SystemApi public final class HdmiControlManager { + private static final String TAG = "HdmiControlManager"; + @Nullable private final IHdmiControlService mService; /** @@ -56,7 +60,7 @@ public final class HdmiControlManager { /** * Message used by TV to receive volume status from Audio Receiver. It should check volume value - * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRAM_PARAM1}. If the + * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRA_PARAM1}. If the * value is in range of [0,100], it is current volume of Audio Receiver. And there is another * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute. */ @@ -71,7 +75,7 @@ public final class HdmiControlManager { * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value * of the message. */ - public static final String EXTRA_MESSAGE_EXTRAM_PARAM1 = + public static final String EXTRA_MESSAGE_EXTRA_PARAM1 = "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1"; /** @@ -236,16 +240,24 @@ public final class HdmiControlManager { /** Clear timer error - CEC is disabled. */ public static final int CLEAR_TIMER_STATUS_CEC_DISABLE = 0xA2; + /** The HdmiControlService is started. */ + public static final int CONTROL_STATE_CHANGED_REASON_START = 0; + /** The state of HdmiControlService is changed by changing of settings. */ + public static final int CONTROL_STATE_CHANGED_REASON_SETTING = 1; + /** The HdmiControlService is enabled to wake up. */ + public static final int CONTROL_STATE_CHANGED_REASON_WAKEUP = 2; + /** The HdmiControlService will be disabled to standby. */ + public static final int CONTROL_STATE_CHANGED_REASON_STANDBY = 3; + // True if we have a logical device of type playback hosted in the system. private final boolean mHasPlaybackDevice; // True if we have a logical device of type TV hosted in the system. private final boolean mHasTvDevice; /** - * @hide - hide this constructor because it has a parameter of type - * IHdmiControlService, which is a system private class. The right way - * to create an instance of this class is using the factory - * Context.getSystemService. + * {@hide} - hide this constructor because it has a parameter of type IHdmiControlService, + * which is a system private class. The right way to create an instance of this class is + * using the factory Context.getSystemService. */ public HdmiControlManager(IHdmiControlService service) { mService = service; @@ -331,6 +343,9 @@ public final class HdmiControlManager { void onReceived(HdmiHotplugEvent event); } + private final ArrayMap<HotplugEventListener, IHdmiHotplugEventListener> + mHotplugEventListeners = new ArrayMap<>(); + /** * Listener used to get vendor-specific commands. */ @@ -339,11 +354,29 @@ public final class HdmiControlManager { * Called when a vendor command is received. * * @param srcAddress source logical address + * @param destAddress destination logical address * @param params vendor-specific parameters * @param hasVendorId {@code true} if the command is <Vendor Command * With ID>. The first 3 bytes of params is vendor id. */ - void onReceived(int srcAddress, byte[] params, boolean hasVendorId); + void onReceived(int srcAddress, int destAddress, byte[] params, boolean hasVendorId); + + /** + * The callback is called: + * <ul> + * <li> before HdmiControlService is disabled. + * <li> after HdmiControlService is enabled and the local address is assigned. + * </ul> + * The client shouldn't hold the thread too long since this is a blocking call. + * + * @param enabled {@code true} if HdmiControlService is enabled. + * @param reason the reason code why the state of HdmiControlService is changed. + * @see #CONTROL_STATE_CHANGED_REASON_START + * @see #CONTROL_STATE_CHANGED_REASON_SETTING + * @see #CONTROL_STATE_CHANGED_REASON_WAKEUP + * @see #CONTROL_STATE_CHANGED_REASON_STANDBY + */ + void onControlStateChanged(boolean enabled, int reason); } /** @@ -357,12 +390,19 @@ public final class HdmiControlManager { */ public void addHotplugEventListener(HotplugEventListener listener) { if (mService == null) { + Log.e(TAG, "HdmiControlService is not available"); + return; + } + if (mHotplugEventListeners.containsKey(listener)) { + Log.e(TAG, "listener is already registered"); return; } + IHdmiHotplugEventListener wrappedListener = getHotplugEventListenerWrapper(listener); + mHotplugEventListeners.put(listener, wrappedListener); try { - mService.addHotplugEventListener(getHotplugEventListenerWrapper(listener)); + mService.addHotplugEventListener(wrappedListener); } catch (RemoteException e) { - // Do nothing. + Log.e(TAG, "failed to add hotplug event listener: ", e); } } @@ -373,12 +413,18 @@ public final class HdmiControlManager { */ public void removeHotplugEventListener(HotplugEventListener listener) { if (mService == null) { + Log.e(TAG, "HdmiControlService is not available"); + return; + } + IHdmiHotplugEventListener wrappedListener = mHotplugEventListeners.remove(listener); + if (wrappedListener == null) { + Log.e(TAG, "tried to remove not-registered listener"); return; } try { - mService.removeHotplugEventListener(getHotplugEventListenerWrapper(listener)); + mService.removeHotplugEventListener(wrappedListener); } catch (RemoteException e) { - // Do nothing. + Log.e(TAG, "failed to remove hotplug event listener: ", e); } } diff --git a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java index 7abea36..fe414e6 100644 --- a/core/java/android/hardware/hdmi/HdmiDeviceInfo.java +++ b/core/java/android/hardware/hdmi/HdmiDeviceInfo.java @@ -237,14 +237,14 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return the id of the device. + * Returns the id of the device. */ public int getId() { return mId; } /** - * Return the id to be used for CEC device. + * Returns the id to be used for CEC device. * * @param address logical address of CEC device * @return id for CEC device @@ -255,7 +255,7 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return the id to be used for MHL device. + * Returns the id to be used for MHL device. * * @param portId port which the MHL device is connected to * @return id for MHL device @@ -266,7 +266,7 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return the id to be used for hardware port. + * Returns the id to be used for hardware port. * * @param portId port id * @return id for hardware port @@ -276,28 +276,28 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return the CEC logical address of the device. + * Returns the CEC logical address of the device. */ public int getLogicalAddress() { return mLogicalAddress; } /** - * Return the physical address of the device. + * Returns the physical address of the device. */ public int getPhysicalAddress() { return mPhysicalAddress; } /** - * Return the port ID. + * Returns the port ID. */ public int getPortId() { return mPortId; } /** - * Return CEC type of the device. For more details, refer constants between {@link #DEVICE_TV} + * Returns CEC type of the device. For more details, refer constants between {@link #DEVICE_TV} * and {@link #DEVICE_INACTIVE}. */ public int getDeviceType() { @@ -305,7 +305,7 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return device's power status. It should be one of the following values. + * Returns device's power status. It should be one of the following values. * <ul> * <li>{@link HdmiControlManager#POWER_STATUS_ON} * <li>{@link HdmiControlManager#POWER_STATUS_STANDBY} @@ -319,21 +319,21 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return MHL device id. Return -1 for non-MHL device. + * Returns MHL device id. Return -1 for non-MHL device. */ public int getDeviceId() { return mDeviceId; } /** - * Return MHL adopter id. Return -1 for non-MHL device. + * Returns MHL adopter id. Return -1 for non-MHL device. */ public int getAdopterId() { return mAdopterId; } /** - * Return {@code true} if the device is of a type that can be an input source. + * Returns {@code true} if the device is of a type that can be an input source. */ public boolean isSourceType() { return mDeviceType == DEVICE_PLAYBACK @@ -342,7 +342,7 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return {@code true} if the device represents an HDMI-CEC device. {@code false} if the device + * Returns {@code true} if the device represents an HDMI-CEC device. {@code false} if the device * is either MHL or other device. */ public boolean isCecDevice() { @@ -350,7 +350,7 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return {@code true} if the device represents an MHL device. {@code false} if the device is + * Returns {@code true} if the device represents an MHL device. {@code false} if the device is * either CEC or other device. */ public boolean isMhlDevice() { @@ -358,14 +358,14 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Return display (OSD) name of the device. + * Returns display (OSD) name of the device. */ public String getDisplayName() { return mDisplayName; } /** - * Return vendor id of the device. Vendor id is used to distinguish devices built by other + * Returns vendor id of the device. Vendor id is used to distinguish devices built by other * manufactures. This is required for vendor-specific command on CEC standard. */ public int getVendorId() { @@ -373,7 +373,7 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Describe the kinds of special objects contained in this Parcelable's marshalled + * Describes the kinds of special objects contained in this Parcelable's marshalled * representation. */ @Override @@ -382,7 +382,7 @@ public class HdmiDeviceInfo implements Parcelable { } /** - * Serialize this object into a {@link Parcel}. + * Serializes this object into a {@link Parcel}. * * @param dest The Parcel in which the object should be written. * @param flags Additional flags about how the object should be written. May be 0 or diff --git a/core/java/android/hardware/hdmi/HdmiHotplugEvent.java b/core/java/android/hardware/hdmi/HdmiHotplugEvent.java index 7be4bc5..9476742 100644 --- a/core/java/android/hardware/hdmi/HdmiHotplugEvent.java +++ b/core/java/android/hardware/hdmi/HdmiHotplugEvent.java @@ -44,7 +44,7 @@ public final class HdmiHotplugEvent implements Parcelable { } /** - * Return the port number for which the event occurred. + * Returns the port number for which the event occurred. * * @return port number */ @@ -53,7 +53,7 @@ public final class HdmiHotplugEvent implements Parcelable { } /** - * Return the connection status associated with this event + * Returns the connection status associated with this event * * @return true if the device gets connected; otherwise false */ @@ -62,7 +62,7 @@ public final class HdmiHotplugEvent implements Parcelable { } /** - * Describe the kinds of special objects contained in this Parcelable's + * Describes the kinds of special objects contained in this Parcelable's * marshalled representation. */ @Override @@ -71,7 +71,7 @@ public final class HdmiHotplugEvent implements Parcelable { } /** - * Flatten this object in to a Parcel. + * Flattens this object in to a Parcel. * * @param dest The Parcel in which the object should be written. * @param flags Additional flags about how the object should be written. @@ -86,17 +86,19 @@ public final class HdmiHotplugEvent implements Parcelable { public static final Parcelable.Creator<HdmiHotplugEvent> CREATOR = new Parcelable.Creator<HdmiHotplugEvent>() { /** - * Rebuild a {@link HdmiHotplugEvent} previously stored with + * Rebuilds a {@link HdmiHotplugEvent} previously stored with * {@link Parcelable#writeToParcel(Parcel, int)}. * * @param p {@link HdmiHotplugEvent} object to read the Rating from * @return a new {@link HdmiHotplugEvent} created from the data in the parcel */ + @Override public HdmiHotplugEvent createFromParcel(Parcel p) { int port = p.readInt(); boolean connected = p.readByte() == 1; return new HdmiHotplugEvent(port, connected); } + @Override public HdmiHotplugEvent[] newArray(int size) { return new HdmiHotplugEvent[size]; } diff --git a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java index 85ccb74..263d6b1 100644 --- a/core/java/android/hardware/hdmi/HdmiPlaybackClient.java +++ b/core/java/android/hardware/hdmi/HdmiPlaybackClient.java @@ -64,12 +64,12 @@ public final class HdmiPlaybackClient extends HdmiClient { public void onComplete(int status); } - HdmiPlaybackClient(IHdmiControlService service) { + /* package */ HdmiPlaybackClient(IHdmiControlService service) { super(service); } /** - * Perform the feature 'one touch play' from playback device to turn on display + * Performs the feature 'one touch play' from playback device to turn on display * and switch the input. * * @param callback {@link OneTouchPlayCallback} object to get informed @@ -90,7 +90,7 @@ public final class HdmiPlaybackClient extends HdmiClient { } /** - * Get the status of display device connected through HDMI bus. + * Gets the status of display device connected through HDMI bus. * * @param callback {@link DisplayStatusCallback} object to get informed * of the result diff --git a/core/java/android/hardware/hdmi/HdmiPortInfo.java b/core/java/android/hardware/hdmi/HdmiPortInfo.java index 2ec6126..e52baed 100644 --- a/core/java/android/hardware/hdmi/HdmiPortInfo.java +++ b/core/java/android/hardware/hdmi/HdmiPortInfo.java @@ -114,7 +114,7 @@ public final class HdmiPortInfo implements Parcelable { } /** - * Describe the kinds of special objects contained in this Parcelable's + * Describes the kinds of special objects contained in this Parcelable's * marshalled representation. */ @Override @@ -146,7 +146,7 @@ public final class HdmiPortInfo implements Parcelable { }; /** - * Serialize this object into a {@link Parcel}. + * Serializes this object into a {@link Parcel}. * * @param dest The Parcel in which the object should be written. * @param flags Additional flags about how the object should be written. diff --git a/core/java/android/hardware/hdmi/HdmiRecordListener.java b/core/java/android/hardware/hdmi/HdmiRecordListener.java index f6a348a..29f6cfc 100644 --- a/core/java/android/hardware/hdmi/HdmiRecordListener.java +++ b/core/java/android/hardware/hdmi/HdmiRecordListener.java @@ -25,7 +25,7 @@ import android.hardware.hdmi.HdmiRecordSources.RecordSource; */ @SystemApi public abstract class HdmiRecordListener { - protected HdmiRecordListener() {} + public HdmiRecordListener() {} /** * Called when TV received one touch record request from record device. The client of this @@ -34,7 +34,7 @@ public abstract class HdmiRecordListener { * @param recorderAddress * @return record source to be used for recording. Null if no device is available. */ - public abstract RecordSource getOneTouchRecordSource(int recorderAddress); + public abstract RecordSource onOneTouchRecordSourceRequested(int recorderAddress); /** * Called when one touch record is started or failed during initialization. diff --git a/core/java/android/hardware/hdmi/HdmiRecordSources.java b/core/java/android/hardware/hdmi/HdmiRecordSources.java index dcc41fa..922b8e7 100644 --- a/core/java/android/hardware/hdmi/HdmiRecordSources.java +++ b/core/java/android/hardware/hdmi/HdmiRecordSources.java @@ -55,23 +55,25 @@ public final class HdmiRecordSources { /** * Base class for each record source. + * @hide */ - static abstract class RecordSource { - protected final int mSourceType; - protected final int mExtraDataSize; + @SystemApi + public static abstract class RecordSource { + /* package */ final int mSourceType; + /* package */ final int mExtraDataSize; - protected RecordSource(int sourceType, int extraDataSize) { + /* package */ RecordSource(int sourceType, int extraDataSize) { mSourceType = sourceType; mExtraDataSize = extraDataSize; } - abstract int extraParamToByteArray(byte[] data, int index); + /* package */ abstract int extraParamToByteArray(byte[] data, int index); - final int getDataSize(boolean includeType) { + /* package */ final int getDataSize(boolean includeType) { return includeType ? mExtraDataSize + 1 : mExtraDataSize; } - final int toByteArray(boolean includeType, byte[] data, int index) { + /* package */ final int toByteArray(boolean includeType, byte[] data, int index) { if (includeType) { // 1 to 8 bytes (depends on source). // {[Record Source Type]} | @@ -92,7 +94,7 @@ public final class HdmiRecordSources { // ---- Own source ----------------------------------------------------------------------------- // --------------------------------------------------------------------------------------------- /** - * Create {@link OwnSource} of own source. + * Creates {@link OwnSource} of own source. */ public static OwnSource ofOwnSource() { return new OwnSource(); @@ -309,7 +311,7 @@ public final class HdmiRecordSources { */ public static final class DigitalChannelData implements DigitalServiceIdentification { /** Identifies the logical or virtual channel number of a service. */ - private ChannelIdentifier mChannelIdentifier; + private final ChannelIdentifier mChannelIdentifier; public static DigitalChannelData ofTwoNumbers(int majorNumber, int minorNumber) { return new DigitalChannelData( @@ -336,7 +338,7 @@ public final class HdmiRecordSources { } /** - * Create {@link DigitalServiceSource} with channel type. + * Creates {@link DigitalServiceSource} with channel type. * * @param broadcastSystem digital broadcast system. It should be one of * <ul> @@ -387,7 +389,7 @@ public final class HdmiRecordSources { } /** - * Create {@link DigitalServiceSource} of ARIB type. + * Creates {@link DigitalServiceSource} of ARIB type. * * @param aribType ARIB type. It should be one of * <ul> @@ -418,7 +420,7 @@ public final class HdmiRecordSources { } /** - * Create {@link DigitalServiceSource} of ATSC type. + * Creates {@link DigitalServiceSource} of ATSC type. * * @param atscType ATSC type. It should be one of * <ul> @@ -449,7 +451,7 @@ public final class HdmiRecordSources { } /** - * Create {@link DigitalServiceSource} of ATSC type. + * Creates {@link DigitalServiceSource} of ATSC type. * * @param dvbType DVB type. It should be one of * <ul> @@ -570,7 +572,7 @@ public final class HdmiRecordSources { public static final int BROADCAST_SYSTEM_PAL_OTHER_SYSTEM = 31; /** - * Create {@link AnalogueServiceSource} of analogue service. + * Creates {@link AnalogueServiceSource} of analogue service. * * @param broadcastType * @param frequency @@ -613,7 +615,7 @@ public final class HdmiRecordSources { */ @SystemApi public static final class AnalogueServiceSource extends RecordSource { - static final int EXTRA_DATA_SIZE = 4; + /* package */ static final int EXTRA_DATA_SIZE = 4; /** Indicates the Analogue broadcast type. */ private final int mBroadcastType; @@ -633,7 +635,7 @@ public final class HdmiRecordSources { } @Override - protected int extraParamToByteArray(byte[] data, int index) { + /* package */ int extraParamToByteArray(byte[] data, int index) { // [Analogue Broadcast Type] - 1 byte data[index] = (byte) mBroadcastType; // [Analogue Frequency] - 2 bytes @@ -649,7 +651,7 @@ public final class HdmiRecordSources { // ---- External plug data --------------------------------------------------------------------- // --------------------------------------------------------------------------------------------- /** - * Create {@link ExternalPlugData} of external plug type. + * Creates {@link ExternalPlugData} of external plug type. * * @param plugNumber plug number. It should be in range of [1, 255] * @hide @@ -693,7 +695,7 @@ public final class HdmiRecordSources { // ---- External physical address -------------------------------------------------------------- // --------------------------------------------------------------------------------------------- /** - * Create {@link ExternalPhysicalAddress} of external physical address. + * Creates {@link ExternalPhysicalAddress} of external physical address. * * @param physicalAddress * @hide @@ -752,7 +754,7 @@ public final class HdmiRecordSources { } /** - * Check the byte array of record source. + * Checks the byte array of record source. * @hide */ @SystemApi diff --git a/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java b/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java index 1780707..bf97375 100644 --- a/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java +++ b/core/java/android/hardware/hdmi/HdmiTimerRecordSources.java @@ -67,7 +67,7 @@ public class HdmiTimerRecordSources { private HdmiTimerRecordSources() {} /** - * Create {@link TimerRecordSource} for digital source which is used for <Set Digital + * Creates {@link TimerRecordSource} for digital source which is used for <Set Digital * Timer>. * * @param timerInfo timer info used for timer recording @@ -82,7 +82,7 @@ public class HdmiTimerRecordSources { } /** - * Create {@link TimerRecordSource} for analogue source which is used for <Set Analogue + * Creates {@link TimerRecordSource} for analogue source which is used for <Set Analogue * Timer>. * * @param timerInfo timer info used for timer recording @@ -97,7 +97,7 @@ public class HdmiTimerRecordSources { } /** - * Create {@link TimerRecordSource} for external plug which is used for <Set External + * Creates {@link TimerRecordSource} for external plug which is used for <Set External * Timer>. * * @param timerInfo timer info used for timer recording @@ -112,7 +112,7 @@ public class HdmiTimerRecordSources { } /** - * Create {@link TimerRecordSource} for external physical address which is used for <Set + * Creates {@link TimerRecordSource} for external physical address which is used for <Set * External Timer>. * * @param timerInfo timer info used for timer recording @@ -140,7 +140,7 @@ public class HdmiTimerRecordSources { } /** - * Create {@link Duration} for time value. + * Creates {@link Duration} for time value. * * @param hour hour in range of [0, 23] * @param minute minute in range of [0, 60] @@ -162,7 +162,7 @@ public class HdmiTimerRecordSources { } /** - * Create {@link Duration} for duration value. + * Creates {@link Duration} for duration value. * * @param hour hour in range of [0, 99] * @param minute minute in range of [0, 59] @@ -184,21 +184,21 @@ public class HdmiTimerRecordSources { } private static class TimeUnit { - protected final int mHour; - protected final int mMinute; + /* package */ final int mHour; + /* package */ final int mMinute; - protected TimeUnit(int hour, int minute) { + /* package */ TimeUnit(int hour, int minute) { mHour = hour; mMinute = minute; } - protected int toByteArray(byte[] data, int index) { + /* package */ int toByteArray(byte[] data, int index) { data[index] = toBcdByte(mHour); data[index + 1] = toBcdByte(mMinute); return 2; } - protected static byte toBcdByte(int value) { + /* package */ static byte toBcdByte(int value) { int digitOfTen = (value / 10) % 10; int digitOfOne = value % 10; return (byte) ((digitOfTen << 4) | digitOfOne); @@ -247,7 +247,7 @@ public class HdmiTimerRecordSources { RECORDING_SEQUENCE_REPEAT_SATUREDAY); /** - * Create {@link TimerInfo} with the given information. + * Creates {@link TimerInfo} with the given information. * * @param dayOfMonth day of month * @param monthOfYear month of year @@ -426,7 +426,7 @@ public class HdmiTimerRecordSources { } /** - * Check the byte array of timer record source. + * Checks the byte array of timer record source. * @param sourcetype * @param recordSource * @hide diff --git a/core/java/android/hardware/hdmi/HdmiTvClient.java b/core/java/android/hardware/hdmi/HdmiTvClient.java index 9d92fd9..dbfb4ef 100644 --- a/core/java/android/hardware/hdmi/HdmiTvClient.java +++ b/core/java/android/hardware/hdmi/HdmiTvClient.java @@ -24,6 +24,9 @@ import android.util.Log; import libcore.util.EmptyArray; +import java.util.Collections; +import java.util.List; + /** * HdmiTvClient represents HDMI-CEC logical device of type TV in the Android system * which acts as TV/Display. It provides with methods that manage, interact with other @@ -40,13 +43,13 @@ public final class HdmiTvClient extends HdmiClient { */ public static final int VENDOR_DATA_SIZE = 16; - HdmiTvClient(IHdmiControlService service) { + /* package */ HdmiTvClient(IHdmiControlService service) { super(service); } // Factory method for HdmiTvClient. // Declared package-private. Accessed by HdmiControlManager only. - static HdmiTvClient create(IHdmiControlService service) { + /* package */ static HdmiTvClient create(IHdmiControlService service) { return new HdmiTvClient(service); } @@ -68,7 +71,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Select a CEC logical device to be a new active source. + * Selects a CEC logical device to be a new active source. * * @param logicalAddress logical address of the device to select * @param callback callback to get the result with @@ -95,7 +98,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Select a HDMI port to be a new route path. + * Selects a HDMI port to be a new route path. * * @param portId HDMI port to select * @param callback callback to get the result with @@ -125,7 +128,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Set the listener used to get informed of the input change event. + * Sets the listener used to get informed of the input change event. * * @param listener listener object */ @@ -150,7 +153,22 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Set system audio volume + * Returns all the CEC devices connected to TV. + * + * @return list of {@link HdmiDeviceInfo} for connected CEC devices. + * Empty list is returned if there is none. + */ + public List<HdmiDeviceInfo> getDeviceList() { + try { + return mService.getDeviceList(); + } catch (RemoteException e) { + Log.e("TAG", "Failed to call getDeviceList():", e); + return Collections.<HdmiDeviceInfo>emptyList(); + } + } + + /** + * Sets system audio volume * * @param oldIndex current volume index * @param newIndex volume index to be set @@ -165,7 +183,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Set system audio mute status + * Sets system audio mute status * * @param mute {@code true} if muted; otherwise, {@code false} */ @@ -178,7 +196,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Set record listener + * Sets record listener * * @param listener */ @@ -198,7 +216,7 @@ public final class HdmiTvClient extends HdmiClient { @Override public byte[] getOneTouchRecordSource(int recorderAddress) { HdmiRecordSources.RecordSource source = - callback.getOneTouchRecordSource(recorderAddress); + callback.onOneTouchRecordSourceRequested(recorderAddress); if (source == null) { return EmptyArray.BYTE; } @@ -226,13 +244,13 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Start one touch recording with the given recorder address and recorder source. + * Starts one touch recording with the given recorder address and recorder source. * <p> * Usage * <pre> * HdmiTvClient tvClient = ....; * // for own source. - * OwnSource ownSource = ownHdmiRecordSources.ownSource(); + * OwnSource ownSource = HdmiRecordSources.ofOwnSource(); * tvClient.startOneTouchRecord(recorderAddress, ownSource); * </pre> */ @@ -251,7 +269,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Stop one touch record. + * Stops one touch record. * * @param recorderAddress recorder address where recoding will be stopped */ @@ -264,7 +282,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Start timer recording with the given recoder address and recorder source. + * Starts timer recording with the given recoder address and recorder source. * <p> * Usage * <pre> @@ -313,7 +331,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Clear timer recording with the given recorder address and recording source. + * Clears timer recording with the given recorder address and recording source. * For more details, please refer {@link #startTimerRecording(int, int, TimerRecordSource)}. */ public void clearTimerRecording(int recorderAddress, int sourceType, TimerRecordSource source) { @@ -339,7 +357,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Set {@link HdmiMhlVendorCommandListener} to get incoming MHL vendor command. + * Sets {@link HdmiMhlVendorCommandListener} to get incoming MHL vendor command. * * @param listener to receive incoming MHL vendor command */ @@ -365,7 +383,7 @@ public final class HdmiTvClient extends HdmiClient { } /** - * Send MHL vendor command to the device connected to a port of the given portId. + * Sends MHL vendor command to the device connected to a port of the given portId. * * @param portId id of port to send MHL vendor command * @param offset offset in the in given data diff --git a/core/java/android/hardware/hdmi/IHdmiControlService.aidl b/core/java/android/hardware/hdmi/IHdmiControlService.aidl index 4866a9a..c1e924e 100644 --- a/core/java/android/hardware/hdmi/IHdmiControlService.aidl +++ b/core/java/android/hardware/hdmi/IHdmiControlService.aidl @@ -59,6 +59,7 @@ interface IHdmiControlService { void setSystemAudioMute(boolean mute); void setInputChangeListener(IHdmiInputChangeListener listener); List<HdmiDeviceInfo> getInputDevices(); + List<HdmiDeviceInfo> getDeviceList(); void sendVendorCommand(int deviceType, int targetAddress, in byte[] params, boolean hasVendorId); void addVendorCommandListener(IHdmiVendorCommandListener listener, int deviceType); diff --git a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl index 55cc925..a16e878 100644 --- a/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl +++ b/core/java/android/hardware/hdmi/IHdmiVendorCommandListener.aidl @@ -23,5 +23,6 @@ package android.hardware.hdmi; * @hide */ oneway interface IHdmiVendorCommandListener { - void onReceived(int logicalAddress, in byte[] operands, boolean hasVendorId); + void onReceived(int logicalAddress, int destAddress, in byte[] operands, boolean hasVendorId); + void onControlStateChanged(boolean enabled, int reason); } diff --git a/core/java/android/net/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java index 58d0048..e4e5b1e 100644 --- a/core/java/android/net/BaseNetworkStateTracker.java +++ b/core/java/android/net/BaseNetworkStateTracker.java @@ -170,16 +170,6 @@ public abstract class BaseNetworkStateTracker implements NetworkStateTracker { } @Override - public void addStackedLink(LinkProperties link) { - mLinkProperties.addStackedLink(link); - } - - @Override - public void removeStackedLink(LinkProperties link) { - mLinkProperties.removeStackedLink(link); - } - - @Override public void supplyMessenger(Messenger messenger) { // not supported on this network } diff --git a/core/java/android/net/LinkProperties.java b/core/java/android/net/LinkProperties.java index 662c576..8b0dfc9 100644 --- a/core/java/android/net/LinkProperties.java +++ b/core/java/android/net/LinkProperties.java @@ -493,16 +493,16 @@ public final class LinkProperties implements Parcelable { /** * Removes a stacked link. * - * If there a stacked link with the same interfacename as link, it is + * If there is a stacked link with the given interface name, it is * removed. Otherwise, nothing changes. * - * @param link The link to remove. + * @param iface The interface name of the link to remove. * @return true if the link was removed, false otherwise. * @hide */ - public boolean removeStackedLink(LinkProperties link) { - if (link != null && link.getInterfaceName() != null) { - LinkProperties removed = mStackedLinks.remove(link.getInterfaceName()); + public boolean removeStackedLink(String iface) { + if (iface != null) { + LinkProperties removed = mStackedLinks.remove(iface); return removed != null; } return false; @@ -675,17 +675,38 @@ public final class LinkProperties implements Parcelable { } /** - * Returns true if this link is provisioned for global connectivity. For IPv6, this requires an - * IP address, default route, and DNS server. For IPv4, this requires only an IPv4 address, - * because WifiStateMachine accepts static configurations that only specify an address but not - * DNS servers or a default route. + * Returns true if this link is provisioned for global IPv4 connectivity. + * This requires an IP address, default route, and DNS server. + * + * @return {@code true} if the link is provisioned, {@code false} otherwise. + */ + private boolean hasIPv4() { + return (hasIPv4Address() && + hasIPv4DefaultRoute() && + hasIPv4DnsServer()); + } + + /** + * Returns true if this link is provisioned for global IPv6 connectivity. + * This requires an IP address, default route, and DNS server. + * + * @return {@code true} if the link is provisioned, {@code false} otherwise. + */ + private boolean hasIPv6() { + return (hasGlobalIPv6Address() && + hasIPv6DefaultRoute() && + hasIPv6DnsServer()); + } + + /** + * Returns true if this link is provisioned for global connectivity, + * for at least one Internet Protocol family. * * @return {@code true} if the link is provisioned, {@code false} otherwise. * @hide */ public boolean isProvisioned() { - return (hasIPv4Address() || - (hasGlobalIPv6Address() && hasIPv6DefaultRoute() && hasIPv6DnsServer())); + return (hasIPv4() || hasIPv6()); } /** diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java index d8012fe..40b7e06 100644 --- a/core/java/android/net/MobileDataStateTracker.java +++ b/core/java/android/net/MobileDataStateTracker.java @@ -661,16 +661,6 @@ public class MobileDataStateTracker extends BaseNetworkStateTracker { } @Override - public void addStackedLink(LinkProperties link) { - mLinkProperties.addStackedLink(link); - } - - @Override - public void removeStackedLink(LinkProperties link) { - mLinkProperties.removeStackedLink(link); - } - - @Override public String toString() { final CharArrayWriter writer = new CharArrayWriter(); final PrintWriter pw = new PrintWriter(writer); diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java index 58f0fc0..4fa0593 100644 --- a/core/java/android/net/Network.java +++ b/core/java/android/net/Network.java @@ -21,7 +21,9 @@ import android.os.Parcelable; import android.os.Parcel; import android.system.ErrnoException; +import java.io.FileDescriptor; import java.io.IOException; +import java.net.DatagramSocket; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.MalformedURLException; @@ -264,18 +266,40 @@ public class Network implements Parcelable { } /** + * Binds the specified {@link DatagramSocket} to this {@code Network}. All data traffic on the + * socket will be sent on this {@code Network}, irrespective of any process-wide network binding + * set by {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be + * connected. + */ + public void bindSocket(DatagramSocket socket) throws IOException { + // Apparently, the kernel doesn't update a connected UDP socket's routing upon mark changes. + if (socket.isConnected()) { + throw new SocketException("Socket is connected"); + } + // Query a property of the underlying socket to ensure that the socket's file descriptor + // exists, is available to bind to a network and is not closed. + socket.getReuseAddress(); + bindSocketFd(socket.getFileDescriptor$()); + } + + /** * Binds the specified {@link Socket} to this {@code Network}. All data traffic on the socket * will be sent on this {@code Network}, irrespective of any process-wide network binding set by * {@link ConnectivityManager#setProcessDefaultNetwork}. The socket must not be connected. */ public void bindSocket(Socket socket) throws IOException { + // Apparently, the kernel doesn't update a connected TCP socket's routing upon mark changes. if (socket.isConnected()) { throw new SocketException("Socket is connected"); } - // Query a property of the underlying socket to ensure the underlying - // socket exists so a file descriptor is available to bind to a network. + // Query a property of the underlying socket to ensure that the socket's file descriptor + // exists, is available to bind to a network and is not closed. socket.getReuseAddress(); - int err = NetworkUtils.bindSocketToNetwork(socket.getFileDescriptor$().getInt$(), netId); + bindSocketFd(socket.getFileDescriptor$()); + } + + private void bindSocketFd(FileDescriptor fd) throws IOException { + int err = NetworkUtils.bindSocketToNetwork(fd.getInt$(), netId); if (err != 0) { // bindSocketToNetwork returns negative errno. throw new ErrnoException("Binding socket to network " + netId, -err) diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java index 53f9fcd..1efe478 100644 --- a/core/java/android/net/NetworkCapabilities.java +++ b/core/java/android/net/NetworkCapabilities.java @@ -19,16 +19,7 @@ package android.net; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; -import android.util.Log; - import java.lang.IllegalArgumentException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; /** * This class represents the capabilities of a network. This is used both to specify @@ -36,15 +27,12 @@ import java.util.Set; * * Note that this replaces the old {@link ConnectivityManager#TYPE_MOBILE} method * of network selection. Rather than indicate a need for Wi-Fi because an application - * needs high bandwidth and risk obselence when a new, fast network appears (like LTE), + * needs high bandwidth and risk obsolescence when a new, fast network appears (like LTE), * the application should specify it needs high bandwidth. Similarly if an application * needs an unmetered network for a bulk transfer it can specify that rather than assuming * all cellular based connections are metered and all Wi-Fi based connections are not. */ public final class NetworkCapabilities implements Parcelable { - private static final String TAG = "NetworkCapabilities"; - private static final boolean DBG = false; - /** * @hide */ @@ -541,9 +529,11 @@ public final class NetworkCapabilities implements Parcelable { (TextUtils.isEmpty(mNetworkSpecifier) ? 0 : mNetworkSpecifier.hashCode() * 17)); } + @Override public int describeContents() { return 0; } + @Override public void writeToParcel(Parcel dest, int flags) { dest.writeLong(mNetworkCapabilities); dest.writeLong(mTransportTypes); @@ -553,6 +543,7 @@ public final class NetworkCapabilities implements Parcelable { } public static final Creator<NetworkCapabilities> CREATOR = new Creator<NetworkCapabilities>() { + @Override public NetworkCapabilities createFromParcel(Parcel in) { NetworkCapabilities netCap = new NetworkCapabilities(); @@ -563,11 +554,13 @@ public final class NetworkCapabilities implements Parcelable { netCap.mNetworkSpecifier = in.readString(); return netCap; } + @Override public NetworkCapabilities[] newArray(int size) { return new NetworkCapabilities[size]; } }; + @Override public String toString() { int[] types = getTransportTypes(); String transports = (types.length > 0 ? " Transports: " : ""); diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java index 35500cc..c80782c 100644 --- a/core/java/android/net/NetworkStateTracker.java +++ b/core/java/android/net/NetworkStateTracker.java @@ -216,16 +216,6 @@ public interface NetworkStateTracker { */ public void setDependencyMet(boolean met); - /** - * Informs the state tracker that another interface is stacked on top of it. - **/ - public void addStackedLink(LinkProperties link); - - /** - * Informs the state tracker that a stacked interface has been removed. - **/ - public void removeStackedLink(LinkProperties link); - /* * Called once to setup async channel between this and * the underlying network specific code. diff --git a/core/java/android/net/Proxy.java b/core/java/android/net/Proxy.java index c391eb8..b2c8cbd 100644 --- a/core/java/android/net/Proxy.java +++ b/core/java/android/net/Proxy.java @@ -19,7 +19,6 @@ package android.net; import android.annotation.SdkConstant; import android.annotation.SdkConstant.SdkConstantType; import android.content.Context; -import android.net.ProxyInfo; import android.text.TextUtils; import android.util.Log; diff --git a/core/java/android/net/ProxyInfo.java b/core/java/android/net/ProxyInfo.java index 1534e2c..7694420 100644 --- a/core/java/android/net/ProxyInfo.java +++ b/core/java/android/net/ProxyInfo.java @@ -36,7 +36,13 @@ import java.util.Locale; * * Other HTTP stacks will need to obtain the proxy info from * {@link Proxy#PROXY_CHANGE_ACTION} broadcast as the extra {@link Proxy#EXTRA_PROXY_INFO}. + * + * @deprecated Please use {@link java.net.URL#openConnection}, {@link java.net.Proxy} and + * friends. The Apache HTTP client is no longer maintained and may be removed in a future + * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> + * for further details. */ +@Deprecated public class ProxyInfo implements Parcelable { private String mHost; diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index b0278d3..c15e6e5 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -154,7 +154,13 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { * for none. The socket timeout is reset to 0 after the handshake. * @param cache The {@link SSLSessionCache} to use, or null for no cache. * @return a new SocketFactory with the specified parameters + * + * @deprecated Use {@link #getDefault()} along with a {@link javax.net.ssl.HttpsURLConnection} + * instead. The Apache HTTP client is no longer maintained and may be removed in a future + * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> + * for further details. */ + @Deprecated public static org.apache.http.conn.ssl.SSLSocketFactory getHttpSocketFactory( int handshakeTimeoutMillis, SSLSessionCache cache) { return new org.apache.http.conn.ssl.SSLSocketFactory( diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java index 04f3974..a262076 100644 --- a/core/java/android/net/http/AndroidHttpClient.java +++ b/core/java/android/net/http/AndroidHttpClient.java @@ -74,7 +74,13 @@ import java.util.zip.GZIPOutputStream; * To retain cookies, simply add a cookie store to the HttpContext:</p> * * <pre>context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);</pre> + * + * @deprecated Please use {@link java.net.URLConnection} and friends instead. + * The Apache HTTP client is no longer maintained and may be removed in a future + * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> + * for further details. */ +@Deprecated public final class AndroidHttpClient implements HttpClient { // Gzip of data shorter than this probably won't be worthwhile @@ -108,7 +114,13 @@ public final class AndroidHttpClient implements HttpClient { * @param userAgent to report in your HTTP requests * @param context to use for caching SSL sessions (may be null for no caching) * @return AndroidHttpClient for you to use for all your requests. + * + * @deprecated Please use {@link java.net.URLConnection} and friends instead. See + * {@link android.net.SSLCertificateSocketFactory} for SSL cache support. If you'd + * like to set a custom useragent, please use {@link java.net.URLConnection#setRequestProperty(String, String)} + * with {@code field} set to {@code User-Agent}. */ + @Deprecated public static AndroidHttpClient newInstance(String userAgent, Context context) { HttpParams params = new BasicHttpParams(); @@ -148,7 +160,13 @@ public final class AndroidHttpClient implements HttpClient { * Create a new HttpClient with reasonable defaults (which you can update). * @param userAgent to report in your HTTP requests. * @return AndroidHttpClient for you to use for all your requests. + * + * @deprecated Please use {@link java.net.URLConnection} and friends instead. See + * {@link android.net.SSLCertificateSocketFactory} for SSL cache support. If you'd + * like to set a custom useragent, please use {@link java.net.URLConnection#setRequestProperty(String, String)} + * with {@code field} set to {@code User-Agent}. */ + @Deprecated public static AndroidHttpClient newInstance(String userAgent) { return newInstance(userAgent, null /* session cache */); } diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java index d1ad313..72d61e8 100644 --- a/core/java/android/os/Build.java +++ b/core/java/android/os/Build.java @@ -589,6 +589,11 @@ public class Build { * </ul> */ public static final int LOLLIPOP = 21; + + /** + * Lollipop with an extra sugar coating on the outside! + */ + public static final int LOLLIPOP_MR1 = 22; } /** The type of build, like "user" or "eng". */ diff --git a/core/java/android/os/ConditionVariable.java b/core/java/android/os/ConditionVariable.java index 07b221c..1e820f9 100644 --- a/core/java/android/os/ConditionVariable.java +++ b/core/java/android/os/ConditionVariable.java @@ -109,7 +109,7 @@ public class ConditionVariable * <p> * If the condition is already opened, return immediately. * - * @param timeout the minimum time to wait in milliseconds. + * @param timeout the maximum time to wait in milliseconds. * * @return true if the condition was opened, false if the call returns * because of the timeout. diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java index 18730b6..084ca30 100644 --- a/core/java/android/os/Debug.java +++ b/core/java/android/os/Debug.java @@ -1093,7 +1093,15 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo /** @hide */ public static final int MEMINFO_ZRAM_TOTAL = 8; /** @hide */ - public static final int MEMINFO_COUNT = 9; + public static final int MEMINFO_MAPPED = 9; + /** @hide */ + public static final int MEMINFO_VM_ALLOC_USED = 10; + /** @hide */ + public static final int MEMINFO_PAGE_TABLES = 11; + /** @hide */ + public static final int MEMINFO_KERNEL_STACK = 12; + /** @hide */ + public static final int MEMINFO_COUNT = 13; /** * Retrieves /proc/meminfo. outSizes is filled with fields diff --git a/core/java/android/preference/ListPreference.java b/core/java/android/preference/ListPreference.java index 8081a54..9482a72 100644 --- a/core/java/android/preference/ListPreference.java +++ b/core/java/android/preference/ListPreference.java @@ -162,10 +162,10 @@ public class ListPreference extends DialogPreference { @Override public CharSequence getSummary() { final CharSequence entry = getEntry(); - if (mSummary == null || entry == null) { + if (mSummary == null) { return super.getSummary(); } else { - return String.format(mSummary, entry); + return String.format(mSummary, entry == null ? "" : entry); } } diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java index 671f722..3130b64 100644 --- a/core/java/android/preference/SeekBarVolumizer.java +++ b/core/java/android/preference/SeekBarVolumizer.java @@ -47,7 +47,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } private final Context mContext; - private final Handler mHandler; private final H mUiHandler = new H(); private final Callback mCallback; private final Uri mDefaultUri; @@ -55,8 +54,9 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba private final int mStreamType; private final int mMaxStreamVolume; private final Receiver mReceiver = new Receiver(); - private final Observer mVolumeObserver; + private Handler mHandler; + private Observer mVolumeObserver; private int mOriginalStreamVolume; private Ringtone mRingtone; private int mLastProgress = -1; @@ -75,16 +75,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); mStreamType = streamType; mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType); - HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); - thread.start(); - mHandler = new Handler(thread.getLooper(), this); mCallback = callback; mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType); - mVolumeObserver = new Observer(mHandler); - mContext.getContentResolver().registerContentObserver( - System.getUriFor(System.VOLUME_SETTINGS[mStreamType]), - false, mVolumeObserver); - mReceiver.setListening(true); if (defaultUri == null) { if (mStreamType == AudioManager.STREAM_RING) { defaultUri = Settings.System.DEFAULT_RINGTONE_URI; @@ -95,7 +87,6 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } } mDefaultUri = defaultUri; - mHandler.sendEmptyMessage(MSG_INIT_SAMPLE); } public void setSeekBar(SeekBar seekBar) { @@ -139,6 +130,7 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } private void postStartSample() { + if (mHandler == null) return; mHandler.removeMessages(MSG_START_SAMPLE); mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_START_SAMPLE), isSamplePlaying() ? CHECK_RINGTONE_PLAYBACK_DELAY_MS : 0); @@ -159,7 +151,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } } - void postStopSample() { + private void postStopSample() { + if (mHandler == null) return; // remove pending delayed start messages mHandler.removeMessages(MSG_START_SAMPLE); mHandler.removeMessages(MSG_STOP_SAMPLE); @@ -173,11 +166,27 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba } public void stop() { + if (mHandler == null) return; // already stopped postStopSample(); mContext.getContentResolver().unregisterContentObserver(mVolumeObserver); - mSeekBar.setOnSeekBarChangeListener(null); mReceiver.setListening(false); + mSeekBar.setOnSeekBarChangeListener(null); mHandler.getLooper().quitSafely(); + mHandler = null; + mVolumeObserver = null; + } + + public void start() { + if (mHandler != null) return; // already started + HandlerThread thread = new HandlerThread(TAG + ".CallbackHandler"); + thread.start(); + mHandler = new Handler(thread.getLooper(), this); + mHandler.sendEmptyMessage(MSG_INIT_SAMPLE); + mVolumeObserver = new Observer(mHandler); + mContext.getContentResolver().registerContentObserver( + System.getUriFor(System.VOLUME_SETTINGS[mStreamType]), + false, mVolumeObserver); + mReceiver.setListening(true); } public void revertVolume() { @@ -193,7 +202,8 @@ public class SeekBarVolumizer implements OnSeekBarChangeListener, Handler.Callba postSetVolume(progress); } - void postSetVolume(int progress) { + private void postSetVolume(int progress) { + if (mHandler == null) return; // Do the volume changing separately to give responsive UI mLastProgress = progress; mHandler.removeMessages(MSG_SET_STREAM_VOLUME); diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index df9e10e..0d4c0b6 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -67,6 +67,7 @@ public class VolumePreference extends SeekBarDialogPreference implements final SeekBar seekBar = (SeekBar) view.findViewById(com.android.internal.R.id.seekbar); mSeekBarVolumizer = new SeekBarVolumizer(getContext(), mStreamType, null, this); + mSeekBarVolumizer.start(); mSeekBarVolumizer.setSeekBar(seekBar); getPreferenceManager().registerOnActivityStopListener(this); @@ -116,7 +117,7 @@ public class VolumePreference extends SeekBarDialogPreference implements public void onActivityStop() { if (mSeekBarVolumizer != null) { - mSeekBarVolumizer.postStopSample(); + mSeekBarVolumizer.stopSample(); } } diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java index c8d0fd5..3e80ed0 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -24,17 +24,13 @@ import android.content.Context; import android.content.Intent; import android.content.pm.UserInfo; import android.database.Cursor; -import android.location.Country; -import android.location.CountryDetector; import android.net.Uri; import android.os.UserHandle; import android.os.UserManager; import android.provider.ContactsContract.CommonDataKinds.Callable; import android.provider.ContactsContract.CommonDataKinds.Phone; -import android.provider.ContactsContract.Data; import android.provider.ContactsContract.DataUsageFeedback; import android.telecom.PhoneAccountHandle; -import android.telephony.PhoneNumberUtils; import android.text.TextUtils; import com.android.internal.telephony.CallerInfo; @@ -387,10 +383,12 @@ public class CallLog { public static Uri addCall(CallerInfo ci, Context context, String number, int presentation, int callType, int features, PhoneAccountHandle accountHandle, long start, int duration, Long dataUsage) { + // FIXME using -1 as subId instead of SubscriptionManager.INVALID_SUB_ID return addCall(ci, context, number, presentation, callType, features, accountHandle, start, duration, dataUsage, false); } + /** * Adds a call to the call log. * @@ -406,6 +404,7 @@ public class CallLog { * @param accountHandle The accountHandle object identifying the provider of the call * @param start time stamp for the call in milliseconds * @param duration call duration in seconds + * @param subId the subscription id. * @param dataUsage data usage for the call in bytes, null if data usage was not tracked for * the call. * @param addForAllUsers If true, the call is added to the call log of all currently @@ -463,6 +462,7 @@ public class CallLog { values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString); values.put(PHONE_ACCOUNT_ID, accountId); values.put(NEW, Integer.valueOf(1)); + if (callType == MISSED_TYPE) { values.put(IS_READ, Integer.valueOf(0)); } @@ -503,13 +503,12 @@ public class CallLog { if (cursor != null) { try { if (cursor.getCount() > 0 && cursor.moveToFirst()) { - final String dataId = cursor.getString(0); - updateDataUsageStatForData(resolver, dataId); - if (duration >= MIN_DURATION_FOR_NORMALIZED_NUMBER_UPDATE_MS - && callType == Calls.OUTGOING_TYPE - && TextUtils.isEmpty(ci.normalizedNumber)) { - updateNormalizedNumber(context, resolver, dataId, number); - } + final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon() + .appendPath(cursor.getString(0)) + .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, + DataUsageFeedback.USAGE_TYPE_CALL) + .build(); + resolver.update(feedbackUri, new ContentValues(), null, null); } } finally { cursor.close(); @@ -582,53 +581,5 @@ public class CallLog { + " LIMIT -1 OFFSET 500)", null); return result; } - - private static void updateDataUsageStatForData(ContentResolver resolver, String dataId) { - final Uri feedbackUri = DataUsageFeedback.FEEDBACK_URI.buildUpon() - .appendPath(dataId) - .appendQueryParameter(DataUsageFeedback.USAGE_TYPE, - DataUsageFeedback.USAGE_TYPE_CALL) - .build(); - resolver.update(feedbackUri, new ContentValues(), null, null); - } - - /** - * Update the normalized phone number for the given dataId in the ContactsProvider, based - * on the user's current country. - */ - private static void updateNormalizedNumber(Context context, ContentResolver resolver, - String dataId, String number) { - if (TextUtils.isEmpty(number) || TextUtils.isEmpty(dataId)) { - return; - } - - final String countryIso = getCurrentCountryIso(context); - if (TextUtils.isEmpty(countryIso)) { - return; - } - - final String normalizedNumber = PhoneNumberUtils.formatNumberToE164(number, - getCurrentCountryIso(context)); - if (TextUtils.isEmpty(normalizedNumber)) { - return; - } - - final ContentValues values = new ContentValues(); - values.put(Phone.NORMALIZED_NUMBER, normalizedNumber); - resolver.update(Data.CONTENT_URI, values, Data._ID + "=?", new String[] {dataId}); - } - - private static String getCurrentCountryIso(Context context) { - String countryIso = null; - final CountryDetector detector = (CountryDetector) context.getSystemService( - Context.COUNTRY_DETECTOR); - if (detector != null) { - final Country country = detector.detectCountry(); - if (country != null) { - countryIso = country.getCountryIso(); - } - } - return countryIso; - } } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 79e84d9..a165279 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -3017,7 +3017,6 @@ public final class Settings { MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_ENABLED); MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES); MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_POLL_INTERVAL); - MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_REPORT_XT_OVER_DEV); MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_SAMPLE_ENABLED); MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE); MOVED_TO_GLOBAL.add(Settings.Global.NETSTATS_UID_BUCKET_DURATION); @@ -5013,10 +5012,19 @@ public final class Settings { default: throw new IllegalArgumentException("Invalid location mode: " + mode); } - boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser( - cr, LocationManager.GPS_PROVIDER, gps, userId); + // Note it's important that we set the NLP mode first. The Google implementation + // of NLP clears its NLP consent setting any time it receives a + // LocationManager.PROVIDERS_CHANGED_ACTION broadcast and NLP is disabled. Also, + // it shows an NLP consent dialog any time it receives the broadcast, NLP is + // enabled, and the NLP consent is not set. If 1) we were to enable GPS first, + // 2) a setup wizard has its own NLP consent UI that sets the NLP consent setting, + // and 3) the receiver happened to complete before we enabled NLP, then the Google + // NLP would detect the attempt to enable NLP and show a redundant NLP consent + // dialog. Then the people who wrote the setup wizard would be sad. boolean nlpSuccess = Settings.Secure.setLocationProviderEnabledForUser( cr, LocationManager.NETWORK_PROVIDER, network, userId); + boolean gpsSuccess = Settings.Secure.setLocationProviderEnabledForUser( + cr, LocationManager.GPS_PROVIDER, gps, userId); return gpsSuccess && nlpSuccess; } } @@ -5086,6 +5094,12 @@ public final class Settings { public static final String AIRPLANE_MODE_ON = "airplane_mode_on"; /** + * Whether Theater Mode is on. + * {@hide} + */ + public static final String THEATER_MODE_ON = "theater_mode_on"; + + /** * Constant for use in AIRPLANE_MODE_RADIOS to specify Bluetooth radio. */ public static final String RADIO_BLUETOOTH = "bluetooth"; @@ -5447,8 +5461,6 @@ public final class Settings { public static final String NETSTATS_GLOBAL_ALERT_BYTES = "netstats_global_alert_bytes"; /** {@hide} */ public static final String NETSTATS_SAMPLE_ENABLED = "netstats_sample_enabled"; - /** {@hide} */ - public static final String NETSTATS_REPORT_XT_OVER_DEV = "netstats_report_xt_over_dev"; /** {@hide} */ public static final String NETSTATS_DEV_BUCKET_DURATION = "netstats_dev_bucket_duration"; @@ -6579,6 +6591,14 @@ public final class Settings { public static final String REQUIRE_PASSWORD_TO_DECRYPT = "require_password_to_decrypt"; /** + * Whether the Volte/VT is enabled + * <p> + * Type: int (0 for false, 1 for true) + * @hide + */ + public static final String ENHANCED_4G_MODE_ENABLED = "volte_vt_enabled"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 882a3c8..9a84a1e 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -17,11 +17,13 @@ package android.service.notification; import android.content.ComponentName; +import android.content.Context; import android.content.res.Resources; import android.net.Uri; import android.os.Parcel; import android.os.Parcelable; import android.text.TextUtils; +import android.text.format.DateFormat; import android.util.Slog; import org.xmlpull.v1.XmlPullParser; @@ -32,8 +34,11 @@ import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Calendar; +import java.util.Locale; import java.util.Objects; +import com.android.internal.R; + /** * Persisted configuration for zen mode. * @@ -461,20 +466,34 @@ public class ZenModeConfig implements Parcelable { return downtime; } - public static Condition toTimeCondition(int minutesFromNow) { + public static Condition toTimeCondition(Context context, int minutesFromNow) { final long now = System.currentTimeMillis(); final long millis = minutesFromNow == 0 ? ZERO_VALUE_MS : minutesFromNow * MINUTES_MS; - return toTimeCondition(now + millis, minutesFromNow); + return toTimeCondition(context, now + millis, minutesFromNow, now); } - public static Condition toTimeCondition(long time, int minutes) { - final int num = minutes < 60 ? minutes : Math.round(minutes / 60f); - final int resId = minutes < 60 - ? com.android.internal.R.plurals.zen_mode_duration_minutes - : com.android.internal.R.plurals.zen_mode_duration_hours; - final String caption = Resources.getSystem().getQuantityString(resId, num, num); + public static Condition toTimeCondition(Context context, long time, int minutes, long now) { + final int num, summaryResId, line1ResId; + if (minutes < 60) { + // display as minutes + num = minutes; + summaryResId = R.plurals.zen_mode_duration_minutes_summary; + line1ResId = R.plurals.zen_mode_duration_minutes; + } else { + // display as hours + num = Math.round(minutes / 60f); + summaryResId = com.android.internal.R.plurals.zen_mode_duration_hours_summary; + line1ResId = com.android.internal.R.plurals.zen_mode_duration_hours; + } + final String skeleton = DateFormat.is24HourFormat(context) ? "Hm" : "hma"; + final String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), skeleton); + final CharSequence formattedTime = DateFormat.format(pattern, time); + final Resources res = context.getResources(); + final String summary = res.getQuantityString(summaryResId, num, num, formattedTime); + final String line1 = res.getQuantityString(line1ResId, num, num, formattedTime); + final String line2 = res.getString(R.string.zen_mode_until, formattedTime); final Uri id = toCountdownConditionId(time); - return new Condition(id, caption, "", "", 0, Condition.STATE_TRUE, + return new Condition(id, summary, line1, line2, 0, Condition.STATE_TRUE, Condition.FLAG_RELEVANT_NOW); } diff --git a/core/java/android/text/format/Time.java b/core/java/android/text/format/Time.java index 3c90ab6..0c66709 100644 --- a/core/java/android/text/format/Time.java +++ b/core/java/android/text/format/Time.java @@ -48,7 +48,10 @@ import libcore.util.ZoneInfoDB; * <li>Much of the formatting / parsing assumes ASCII text and is therefore not suitable for * use with non-ASCII scripts.</li> * </ul> + * + * @deprecated Use {@link java.util.GregorianCalendar} instead. */ +@Deprecated public class Time { private static final String Y_M_D_T_H_M_S_000 = "%Y-%m-%dT%H:%M:%S.000"; private static final String Y_M_D_T_H_M_S_000_Z = "%Y-%m-%dT%H:%M:%S.000Z"; diff --git a/core/java/android/transition/ChangeBounds.java b/core/java/android/transition/ChangeBounds.java index 0da5fb6..c82587b 100644 --- a/core/java/android/transition/ChangeBounds.java +++ b/core/java/android/transition/ChangeBounds.java @@ -16,7 +16,9 @@ package android.transition; +import android.animation.AnimatorSet; import android.content.Context; +import android.content.res.TypedArray; import android.graphics.PointF; import android.animation.Animator; @@ -31,11 +33,12 @@ import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.IntProperty; import android.util.Property; import android.view.View; import android.view.ViewGroup; +import com.android.internal.R; + import java.util.Map; /** @@ -43,17 +46,20 @@ import java.util.Map; * the scene change and animates those changes during the transition. * * <p>A ChangeBounds transition can be described in a resource file by using the - * tag <code>changeBounds</code>, along with the other standard + * tag <code>changeBounds</code>, using its attributes of + * {@link android.R.styleable#ChangeBounds} along with the other standard * attributes of {@link android.R.styleable#Transition}.</p> */ public class ChangeBounds extends Transition { private static final String PROPNAME_BOUNDS = "android:changeBounds:bounds"; + private static final String PROPNAME_CLIP = "android:changeBounds:clip"; private static final String PROPNAME_PARENT = "android:changeBounds:parent"; private static final String PROPNAME_WINDOW_X = "android:changeBounds:windowX"; private static final String PROPNAME_WINDOW_Y = "android:changeBounds:windowY"; private static final String[] sTransitionProperties = { PROPNAME_BOUNDS, + PROPNAME_CLIP, PROPNAME_PARENT, PROPNAME_WINDOW_X, PROPNAME_WINDOW_Y @@ -77,6 +83,83 @@ public class ChangeBounds extends Transition { } }; + private static final Property<ViewBounds, PointF> TOP_LEFT_PROPERTY = + new Property<ViewBounds, PointF>(PointF.class, "topLeft") { + @Override + public void set(ViewBounds viewBounds, PointF topLeft) { + viewBounds.setTopLeft(topLeft); + } + + @Override + public PointF get(ViewBounds viewBounds) { + return null; + } + }; + + private static final Property<ViewBounds, PointF> BOTTOM_RIGHT_PROPERTY = + new Property<ViewBounds, PointF>(PointF.class, "bottomRight") { + @Override + public void set(ViewBounds viewBounds, PointF bottomRight) { + viewBounds.setBottomRight(bottomRight); + } + + @Override + public PointF get(ViewBounds viewBounds) { + return null; + } + }; + + private static final Property<View, PointF> BOTTOM_RIGHT_ONLY_PROPERTY = + new Property<View, PointF>(PointF.class, "bottomRight") { + @Override + public void set(View view, PointF bottomRight) { + int left = view.getLeft(); + int top = view.getTop(); + int right = Math.round(bottomRight.x); + int bottom = Math.round(bottomRight.y); + view.setLeftTopRightBottom(left, top, right, bottom); + } + + @Override + public PointF get(View view) { + return null; + } + }; + + private static final Property<View, PointF> TOP_LEFT_ONLY_PROPERTY = + new Property<View, PointF>(PointF.class, "topLeft") { + @Override + public void set(View view, PointF topLeft) { + int left = Math.round(topLeft.x); + int top = Math.round(topLeft.y); + int right = view.getRight(); + int bottom = view.getBottom(); + view.setLeftTopRightBottom(left, top, right, bottom); + } + + @Override + public PointF get(View view) { + return null; + } + }; + + private static final Property<View, PointF> POSITION_PROPERTY = + new Property<View, PointF>(PointF.class, "position") { + @Override + public void set(View view, PointF topLeft) { + int left = Math.round(topLeft.x); + int top = Math.round(topLeft.y); + int right = left + view.getWidth(); + int bottom = top + view.getHeight(); + view.setLeftTopRightBottom(left, top, right, bottom); + } + + @Override + public PointF get(View view) { + return null; + } + }; + int[] tempLocation = new int[2]; boolean mResizeClip = false; boolean mReparent = false; @@ -88,6 +171,11 @@ public class ChangeBounds extends Transition { public ChangeBounds(Context context, AttributeSet attrs) { super(context, attrs); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ChangeBounds); + boolean resizeClip = a.getBoolean(R.styleable.ChangeBounds_resizeClip, false); + a.recycle(); + setResizeClip(resizeClip); } @Override @@ -95,11 +183,37 @@ public class ChangeBounds extends Transition { return sTransitionProperties; } + /** + * When <code>resizeClip</code> is true, ChangeBounds resizes the view using the clipBounds + * instead of changing the dimensions of the view during the animation. When + * <code>resizeClip</code> is false, ChangeBounds resizes the View by changing its dimensions. + * + * <p>When resizeClip is set to true, the clip bounds is modified by ChangeBounds. Therefore, + * {@link android.transition.ChangeClipBounds} is not compatible with ChangeBounds + * in this mode.</p> + * + * @param resizeClip Used to indicate whether the view bounds should be modified or the + * clip bounds should be modified by ChangeBounds. + * @see android.view.View#setClipBounds(android.graphics.Rect) + * @attr ref android.R.styleable#ChangeBounds_resizeClip + */ public void setResizeClip(boolean resizeClip) { mResizeClip = resizeClip; } /** + * Returns true when the ChangeBounds will resize by changing the clip bounds during the + * view animation or false when bounds are changed. The default value is false. + * + * @return true when the ChangeBounds will resize by changing the clip bounds during the + * view animation or false when bounds are changed. The default value is false. + * @attr ref android.R.styleable#ChangeBounds_resizeClip + */ + public boolean getResizeClip() { + return mResizeClip; + } + + /** * Setting this flag tells ChangeBounds to track the before/after parent * of every view using this transition. The flag is not enabled by * default because it requires the parent instances to be the same @@ -127,6 +241,9 @@ public class ChangeBounds extends Transition { values.values.put(PROPNAME_WINDOW_X, tempLocation[0]); values.values.put(PROPNAME_WINDOW_Y, tempLocation[1]); } + if (mResizeClip) { + values.values.put(PROPNAME_CLIP, view.getClipBounds()); + } } } @@ -170,158 +287,149 @@ public class ChangeBounds extends Transition { if (parentMatches(startParent, endParent)) { Rect startBounds = (Rect) startValues.values.get(PROPNAME_BOUNDS); Rect endBounds = (Rect) endValues.values.get(PROPNAME_BOUNDS); - int startLeft = startBounds.left; - int endLeft = endBounds.left; - int startTop = startBounds.top; - int endTop = endBounds.top; - int startRight = startBounds.right; - int endRight = endBounds.right; - int startBottom = startBounds.bottom; - int endBottom = endBounds.bottom; - int startWidth = startRight - startLeft; - int startHeight = startBottom - startTop; - int endWidth = endRight - endLeft; - int endHeight = endBottom - endTop; + final int startLeft = startBounds.left; + final int endLeft = endBounds.left; + final int startTop = startBounds.top; + final int endTop = endBounds.top; + final int startRight = startBounds.right; + final int endRight = endBounds.right; + final int startBottom = startBounds.bottom; + final int endBottom = endBounds.bottom; + final int startWidth = startRight - startLeft; + final int startHeight = startBottom - startTop; + final int endWidth = endRight - endLeft; + final int endHeight = endBottom - endTop; + Rect startClip = (Rect) startValues.values.get(PROPNAME_CLIP); + Rect endClip = (Rect) endValues.values.get(PROPNAME_CLIP); int numChanges = 0; if ((startWidth != 0 && startHeight != 0) || (endWidth != 0 && endHeight != 0)) { if (startLeft != endLeft || startTop != endTop) ++numChanges; if (startRight != endRight || startBottom != endBottom) ++numChanges; } + if ((startClip != null && !startClip.equals(endClip)) || + (startClip == null && endClip != null)) { + ++numChanges; + } if (numChanges > 0) { + Animator anim; if (!mResizeClip) { - Animator anim; - if (startWidth == endWidth && startHeight == endHeight) { - view.offsetLeftAndRight(startLeft - view.getLeft()); - view.offsetTopAndBottom(startTop - view.getTop()); - Path positionPath = getPathMotion().getPath(0, 0, endLeft - startLeft, - endTop - startTop); - anim = ObjectAnimator.ofInt(view, new HorizontalOffsetProperty(), - new VerticalOffsetProperty(), positionPath); - } else { - if (startLeft != endLeft) view.setLeft(startLeft); - if (startTop != endTop) view.setTop(startTop); - if (startRight != endRight) view.setRight(startRight); - if (startBottom != endBottom) view.setBottom(startBottom); - ObjectAnimator topLeftAnimator = null; - if (startLeft != endLeft || startTop != endTop) { + view.setLeftTopRightBottom(startLeft, startTop, startRight, startBottom); + if (numChanges == 2) { + if (startWidth == endWidth && startHeight == endHeight) { + Path topLeftPath = getPathMotion().getPath(startLeft, startTop, endLeft, + endTop); + anim = ObjectAnimator.ofObject(view, POSITION_PROPERTY, null, + topLeftPath); + } else { + final ViewBounds viewBounds = new ViewBounds(view); Path topLeftPath = getPathMotion().getPath(startLeft, startTop, endLeft, endTop); - topLeftAnimator = ObjectAnimator - .ofInt(view, "left", "top", topLeftPath); - } - ObjectAnimator bottomRightAnimator = null; - if (startRight != endRight || startBottom != endBottom) { + ObjectAnimator topLeftAnimator = ObjectAnimator + .ofObject(viewBounds, TOP_LEFT_PROPERTY, null, topLeftPath); + Path bottomRightPath = getPathMotion().getPath(startRight, startBottom, endRight, endBottom); - bottomRightAnimator = ObjectAnimator.ofInt(view, "right", "bottom", - bottomRightPath); + ObjectAnimator bottomRightAnimator = ObjectAnimator.ofObject(viewBounds, + BOTTOM_RIGHT_PROPERTY, null, bottomRightPath); + AnimatorSet set = new AnimatorSet(); + set.playTogether(topLeftAnimator, bottomRightAnimator); + anim = set; + set.addListener(new AnimatorListenerAdapter() { + // We need a strong reference to viewBounds until the + // animator ends. + private ViewBounds mViewBounds = viewBounds; + }); } - anim = TransitionUtils.mergeAnimators(topLeftAnimator, - bottomRightAnimator); - } - if (view.getParent() instanceof ViewGroup) { - final ViewGroup parent = (ViewGroup) view.getParent(); - parent.suppressLayout(true); - TransitionListener transitionListener = new TransitionListenerAdapter() { - boolean mCanceled = false; - - @Override - public void onTransitionCancel(Transition transition) { - parent.suppressLayout(false); - mCanceled = true; - } - - @Override - public void onTransitionEnd(Transition transition) { - if (!mCanceled) { - parent.suppressLayout(false); - } - } - - @Override - public void onTransitionPause(Transition transition) { - parent.suppressLayout(false); - } - - @Override - public void onTransitionResume(Transition transition) { - parent.suppressLayout(true); - } - }; - addListener(transitionListener); + } else if (startLeft != endLeft || startTop != endTop) { + Path topLeftPath = getPathMotion().getPath(startLeft, startTop, + endLeft, endTop); + anim = ObjectAnimator.ofObject(view, TOP_LEFT_ONLY_PROPERTY, null, + topLeftPath); + } else { + Path bottomRight = getPathMotion().getPath(startRight, startBottom, + endRight, endBottom); + anim = ObjectAnimator.ofObject(view, BOTTOM_RIGHT_ONLY_PROPERTY, null, + bottomRight); } - return anim; } else { - if (startWidth != endWidth) view.setRight(endLeft + - Math.max(startWidth, endWidth)); - if (startHeight != endHeight) view.setBottom(endTop + - Math.max(startHeight, endHeight)); - // TODO: don't clobber TX/TY - if (startLeft != endLeft) view.setTranslationX(startLeft - endLeft); - if (startTop != endTop) view.setTranslationY(startTop - endTop); - // Animate location with translationX/Y and size with clip bounds - float transXDelta = endLeft - startLeft; - float transYDelta = endTop - startTop; - int widthDelta = endWidth - startWidth; - int heightDelta = endHeight - startHeight; - numChanges = 0; - if (transXDelta != 0) numChanges++; - if (transYDelta != 0) numChanges++; - if (widthDelta != 0 || heightDelta != 0) numChanges++; - ObjectAnimator translationAnimator = null; - if (transXDelta != 0 || transYDelta != 0) { - Path topLeftPath = getPathMotion().getPath(0, 0, transXDelta, transYDelta); - translationAnimator = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, - View.TRANSLATION_Y, topLeftPath); + int maxWidth = Math.max(startWidth, endWidth); + int maxHeight = Math.max(startHeight, endHeight); + + view.setLeftTopRightBottom(startLeft, startTop, startLeft + maxWidth, + startTop + maxHeight); + + ObjectAnimator positionAnimator = null; + if (startLeft != endLeft || startTop != endTop) { + Path topLeftPath = getPathMotion().getPath(startLeft, startTop, endLeft, + endTop); + positionAnimator = ObjectAnimator.ofObject(view, POSITION_PROPERTY, null, + topLeftPath); + } + final Rect finalClip = endClip; + if (startClip == null) { + startClip = new Rect(0, 0, startWidth, startHeight); + } + if (endClip == null) { + endClip = new Rect(0, 0, endWidth, endHeight); } ObjectAnimator clipAnimator = null; - if (widthDelta != 0 || heightDelta != 0) { - Rect tempStartBounds = new Rect(0, 0, startWidth, startHeight); - Rect tempEndBounds = new Rect(0, 0, endWidth, endHeight); + if (!startClip.equals(endClip)) { + view.setClipBounds(startClip); clipAnimator = ObjectAnimator.ofObject(view, "clipBounds", sRectEvaluator, - tempStartBounds, tempEndBounds); - } - Animator anim = TransitionUtils.mergeAnimators(translationAnimator, - clipAnimator); - if (view.getParent() instanceof ViewGroup) { - final ViewGroup parent = (ViewGroup) view.getParent(); - parent.suppressLayout(true); - TransitionListener transitionListener = new TransitionListenerAdapter() { - boolean mCanceled = false; + startClip, endClip); + clipAnimator.addListener(new AnimatorListenerAdapter() { + private boolean mIsCanceled; @Override - public void onTransitionCancel(Transition transition) { - parent.suppressLayout(false); - mCanceled = true; + public void onAnimationCancel(Animator animation) { + mIsCanceled = true; } @Override - public void onTransitionEnd(Transition transition) { - if (!mCanceled) { - parent.suppressLayout(false); + public void onAnimationEnd(Animator animation) { + if (!mIsCanceled) { + view.setClipBounds(finalClip); + view.setLeftTopRightBottom(endLeft, endTop, endRight, + endBottom); } } + }); + } + anim = TransitionUtils.mergeAnimators(positionAnimator, + clipAnimator); + } + if (view.getParent() instanceof ViewGroup) { + final ViewGroup parent = (ViewGroup) view.getParent(); + parent.suppressLayout(true); + TransitionListener transitionListener = new TransitionListenerAdapter() { + boolean mCanceled = false; - @Override - public void onTransitionPause(Transition transition) { + @Override + public void onTransitionCancel(Transition transition) { + parent.suppressLayout(false); + mCanceled = true; + } + + @Override + public void onTransitionEnd(Transition transition) { + if (!mCanceled) { parent.suppressLayout(false); } + } + + @Override + public void onTransitionPause(Transition transition) { + parent.suppressLayout(false); + } - @Override - public void onTransitionResume(Transition transition) { - parent.suppressLayout(true); - } - }; - addListener(transitionListener); - } - anim.addListener(new AnimatorListenerAdapter() { @Override - public void onAnimationEnd(Animator animation) { - view.setClipBounds(null); + public void onTransitionResume(Transition transition) { + parent.suppressLayout(true); } - }); - return anim; + }; + addListener(transitionListener); } + return anim; } } else { int startX = (Integer) startValues.values.get(PROPNAME_WINDOW_X); @@ -357,47 +465,41 @@ public class ChangeBounds extends Transition { return null; } - private abstract static class OffsetProperty extends IntProperty<View> { - int mPreviousValue; - - public OffsetProperty(String name) { - super(name); - } - - @Override - public void setValue(View view, int value) { - int offset = value - mPreviousValue; - offsetBy(view, offset); - mPreviousValue = value; - } - - @Override - public Integer get(View object) { - return null; - } - - protected abstract void offsetBy(View view, int by); - } - - private static class HorizontalOffsetProperty extends OffsetProperty { - public HorizontalOffsetProperty() { - super("offsetLeftAndRight"); + private static class ViewBounds { + private int mLeft; + private int mTop; + private int mRight; + private int mBottom; + private boolean mIsTopLeftSet; + private boolean mIsBottomRightSet; + private View mView; + + public ViewBounds(View view) { + mView = view; } - @Override - protected void offsetBy(View view, int by) { - view.offsetLeftAndRight(by); + public void setTopLeft(PointF topLeft) { + mLeft = Math.round(topLeft.x); + mTop = Math.round(topLeft.y); + mIsTopLeftSet = true; + if (mIsBottomRightSet) { + setLeftTopRightBottom(); + } } - } - private static class VerticalOffsetProperty extends OffsetProperty { - public VerticalOffsetProperty() { - super("offsetTopAndBottom"); + public void setBottomRight(PointF bottomRight) { + mRight = Math.round(bottomRight.x); + mBottom = Math.round(bottomRight.y); + mIsBottomRightSet = true; + if (mIsTopLeftSet) { + setLeftTopRightBottom(); + } } - @Override - protected void offsetBy(View view, int by) { - view.offsetTopAndBottom(by); + private void setLeftTopRightBottom() { + mView.setLeftTopRightBottom(mLeft, mTop, mRight, mBottom); + mIsTopLeftSet = false; + mIsBottomRightSet = false; } } } diff --git a/core/java/android/transition/Transition.java b/core/java/android/transition/Transition.java index 6dede46..e99c2cf 100644 --- a/core/java/android/transition/Transition.java +++ b/core/java/android/transition/Transition.java @@ -1790,6 +1790,10 @@ public abstract class Transition implements Cloneable { private static boolean isValueChanged(TransitionValues oldValues, TransitionValues newValues, String key) { + if (oldValues.values.containsKey(key) != newValues.values.containsKey(key)) { + // The transition didn't care about this particular value, so we don't care, either. + return false; + } Object oldValue = oldValues.values.get(key); Object newValue = newValues.values.get(key); boolean changed; diff --git a/core/java/android/transition/TransitionUtils.java b/core/java/android/transition/TransitionUtils.java index 03423ff..49ceb3b 100644 --- a/core/java/android/transition/TransitionUtils.java +++ b/core/java/android/transition/TransitionUtils.java @@ -22,8 +22,10 @@ import android.animation.TypeEvaluator; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Matrix; +import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; @@ -109,6 +111,35 @@ public class TransitionUtils { } /** + * Get a copy of bitmap of given drawable, return null if intrinsic size is zero + */ + public static Bitmap createDrawableBitmap(Drawable drawable) { + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + if (width <= 0 || height <= 0) { + return null; + } + float scale = Math.min(1f, ((float)MAX_IMAGE_SIZE) / (width * height)); + if (drawable instanceof BitmapDrawable && scale == 1f) { + // return same bitmap if scale down not needed + return ((BitmapDrawable) drawable).getBitmap(); + } + int bitmapWidth = (int) (width * scale); + int bitmapHeight = (int) (height * scale); + Bitmap bitmap = Bitmap.createBitmap(bitmapWidth, bitmapHeight, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + Rect existingBounds = drawable.getBounds(); + int left = existingBounds.left; + int top = existingBounds.top; + int right = existingBounds.right; + int bottom = existingBounds.bottom; + drawable.setBounds(0, 0, bitmapWidth, bitmapHeight); + drawable.draw(canvas); + drawable.setBounds(left, top, right, bottom); + return bitmap; + } + + /** * Creates a Bitmap of the given view, using the Matrix matrix to transform to the local * coordinates. <code>matrix</code> will be modified during the bitmap creation. * diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java index f58291f..36bac31 100644 --- a/core/java/android/transition/Visibility.java +++ b/core/java/android/transition/Visibility.java @@ -484,12 +484,19 @@ public abstract class Visibility extends Transition { @Override boolean areValuesChanged(TransitionValues oldValues, TransitionValues newValues) { - VisibilityInfo changeInfo = getVisibilityChangeInfo(oldValues, newValues); if (oldValues == null && newValues == null) { return false; } + if (oldValues != null && newValues != null && + newValues.values.containsKey(PROPNAME_VISIBILITY) != + oldValues.values.containsKey(PROPNAME_VISIBILITY)) { + // The transition wasn't targeted in either the start or end, so it couldn't + // have changed. + return false; + } + VisibilityInfo changeInfo = getVisibilityChangeInfo(oldValues, newValues); return changeInfo.visibilityChange && (changeInfo.startVisibility == View.VISIBLE || - changeInfo.endVisibility == View.VISIBLE); + changeInfo.endVisibility == View.VISIBLE); } /** diff --git a/core/java/android/util/ArraySet.java b/core/java/android/util/ArraySet.java index 423e48b..68f725e 100644 --- a/core/java/android/util/ArraySet.java +++ b/core/java/android/util/ArraySet.java @@ -245,13 +245,20 @@ public final class ArraySet<E> implements Collection<E>, Set<E> { /** * Create a new ArraySet with the mappings from the given ArraySet. */ - public ArraySet(ArraySet set) { + public ArraySet(ArraySet<E> set) { this(); if (set != null) { addAll(set); } } + /** {@hide} */ + public ArraySet(Collection<E> set) { + this(); + if (set != null) { + addAll(set); + } + } /** * Make the array map empty. All storage is released. diff --git a/core/java/android/util/FloatMath.java b/core/java/android/util/FloatMath.java index 90e0636..8f488af 100644 --- a/core/java/android/util/FloatMath.java +++ b/core/java/android/util/FloatMath.java @@ -24,7 +24,10 @@ package android.util; * became slower and have since been re-implemented to wrap calls to * {@link java.lang.Math}. {@link java.lang.Math} should be used in * preference. + * + * @deprecated Use {@link java.lang.Math} instead. */ +@Deprecated public class FloatMath { /** Prevents instantiation. */ diff --git a/core/java/android/util/IntArray.java b/core/java/android/util/IntArray.java new file mode 100644 index 0000000..e8d3947 --- /dev/null +++ b/core/java/android/util/IntArray.java @@ -0,0 +1,162 @@ +/* + * 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 android.util; + +import com.android.internal.util.ArrayUtils; + +import libcore.util.EmptyArray; + +/** + * Implements a growing array of int primitives. + * + * @hide + */ +public class IntArray implements Cloneable { + private static final int MIN_CAPACITY_INCREMENT = 12; + + private int[] mValues; + private int mSize; + + /** + * Creates an empty IntArray with the default initial capacity. + */ + public IntArray() { + this(10); + } + + /** + * Creates an empty IntArray with the specified initial capacity. + */ + public IntArray(int initialCapacity) { + if (initialCapacity == 0) { + mValues = EmptyArray.INT; + } else { + mValues = ArrayUtils.newUnpaddedIntArray(initialCapacity); + } + mSize = 0; + } + + /** + * Appends the specified value to the end of this array. + */ + public void add(int value) { + add(mSize, value); + } + + /** + * Inserts a value at the specified position in this array. + * + * @throws IndexOutOfBoundsException when index < 0 || index > size() + */ + public void add(int index, int value) { + if (index < 0 || index > mSize) { + throw new IndexOutOfBoundsException(); + } + + ensureCapacity(1); + + if (mSize - index != 0) { + System.arraycopy(mValues, index, mValues, index + 1, mSize - index); + } + + mValues[index] = value; + mSize++; + } + + /** + * Adds the values in the specified array to this array. + */ + public void addAll(IntArray values) { + final int count = values.mSize; + ensureCapacity(count); + + System.arraycopy(values.mValues, 0, mValues, mSize, count); + mSize += count; + } + + /** + * Ensures capacity to append at least <code>count</code> values. + */ + private void ensureCapacity(int count) { + final int currentSize = mSize; + final int minCapacity = currentSize + count; + if (minCapacity >= mValues.length) { + final int targetCap = currentSize + (currentSize < (MIN_CAPACITY_INCREMENT / 2) ? + MIN_CAPACITY_INCREMENT : currentSize >> 1); + final int newCapacity = targetCap > minCapacity ? targetCap : minCapacity; + final int[] newValues = ArrayUtils.newUnpaddedIntArray(newCapacity); + System.arraycopy(mValues, 0, newValues, 0, currentSize); + mValues = newValues; + } + } + + /** + * Removes all values from this array. + */ + public void clear() { + mSize = 0; + } + + @Override + public IntArray clone() throws CloneNotSupportedException { + final IntArray clone = (IntArray) super.clone(); + clone.mValues = mValues.clone(); + return clone; + } + + /** + * Returns the value at the specified position in this array. + */ + public int get(int index) { + if (index >= mSize) { + throw new ArrayIndexOutOfBoundsException(mSize, index); + } + return mValues[index]; + } + + /** + * Returns the index of the first occurrence of the specified value in this + * array, or -1 if this array does not contain the value. + */ + public int indexOf(int value) { + final int n = mSize; + for (int i = 0; i < n; i++) { + if (mValues[i] == value) { + return i; + } + } + return -1; + } + + /** + * Removes the value at the specified index from this array. + */ + public void remove(int index) { + if (index >= mSize) { + throw new ArrayIndexOutOfBoundsException(mSize, index); + } + System.arraycopy(mValues, index + 1, mValues, index, mSize - index - 1); + mSize--; + } + + /** + * Returns the number of values in this array. + */ + public int size() { + return mSize; + } +} diff --git a/core/java/android/util/PathParser.java b/core/java/android/util/PathParser.java index 6820f77..e5f3b2c 100644 --- a/core/java/android/util/PathParser.java +++ b/core/java/android/util/PathParser.java @@ -34,7 +34,11 @@ public class PathParser { Path path = new Path(); PathDataNode[] nodes = createNodesFromPathData(pathData); if (nodes != null) { - PathDataNode.nodesToPath(nodes, path); + try { + PathDataNode.nodesToPath(nodes, path); + } catch (RuntimeException e) { + throw new RuntimeException("Error in parsing " + pathData, e); + } return path; } return null; @@ -128,7 +132,12 @@ public class PathParser { while (end < s.length()) { c = s.charAt(end); - if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) { + // Note that 'e' or 'E' are not valid path commands, but could be + // used for floating point numbers' scientific notation. + // Therefore, when searching for next command, we should ignore 'e' + // and 'E'. + if ((((c - 'A') * (c - 'Z') <= 0) || ((c - 'a') * (c - 'z') <= 0)) + && c != 'e' && c != 'E') { return end; } end++; @@ -142,9 +151,9 @@ public class PathParser { private static class ExtractFloatResult { // We need to return the position of the next separator and whether the - // next float starts with a '-'. + // next float starts with a '-' or a '.'. int mEndPosition; - boolean mEndWithNegSign; + boolean mEndWithNegOrDot; } /** @@ -179,8 +188,8 @@ public class PathParser { s.substring(startPosition, endPosition)); } - if (result.mEndWithNegSign) { - // Keep the '-' sign with next number. + if (result.mEndWithNegOrDot) { + // Keep the '-' or '.' sign with next number. startPosition = endPosition; } else { startPosition = endPosition + 1; @@ -188,8 +197,7 @@ public class PathParser { } return Arrays.copyOf(results, count); } catch (NumberFormatException e) { - Log.e(LOGTAG, "error in parsing \"" + s + "\""); - throw e; + throw new RuntimeException("error in parsing \"" + s + "\"", e); } } @@ -201,11 +209,15 @@ public class PathParser { * the starting position of next number, whether it is ending with a '-'. */ private static void extract(String s, int start, ExtractFloatResult result) { - // Now looking for ' ', ',' or '-' from the start. + // Now looking for ' ', ',', '.' or '-' from the start. int currentIndex = start; boolean foundSeparator = false; - result.mEndWithNegSign = false; + result.mEndWithNegOrDot = false; + boolean secondDot = false; + boolean isExponential = false; for (; currentIndex < s.length(); currentIndex++) { + boolean isPrevExponential = isExponential; + isExponential = false; char currentChar = s.charAt(currentIndex); switch (currentChar) { case ' ': @@ -213,11 +225,25 @@ public class PathParser { foundSeparator = true; break; case '-': - if (currentIndex != start) { + // The negative sign following a 'e' or 'E' is not a separator. + if (currentIndex != start && !isPrevExponential) { foundSeparator = true; - result.mEndWithNegSign = true; + result.mEndWithNegOrDot = true; } break; + case '.': + if (!secondDot) { + secondDot = true; + } else { + // This is the second dot, and it is considered as a separator. + foundSeparator = true; + result.mEndWithNegOrDot = true; + } + break; + case 'e': + case 'E': + isExponential = true; + break; } if (foundSeparator) { break; diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java index 3770b8a..562d138 100644 --- a/core/java/android/view/Surface.java +++ b/core/java/android/view/Surface.java @@ -87,6 +87,8 @@ public class Surface implements Parcelable { // non compatibility mode. private Matrix mCompatibleMatrix; + private HwuiContext mHwuiContext; + /** @hide */ @IntDef({ROTATION_0, ROTATION_90, ROTATION_180, ROTATION_270}) @Retention(RetentionPolicy.SOURCE) @@ -171,6 +173,10 @@ public class Surface implements Parcelable { nativeRelease(mNativeObject); setNativeObjectLocked(0); } + if (mHwuiContext != null) { + mHwuiContext.destroy(); + mHwuiContext = null; + } } } @@ -264,27 +270,63 @@ public class Surface implements Parcelable { * @param canvas The canvas previously obtained from {@link #lockCanvas}. */ public void unlockCanvasAndPost(Canvas canvas) { + synchronized (mLock) { + checkNotReleasedLocked(); + + if (mHwuiContext != null) { + mHwuiContext.unlockAndPost(canvas); + } else { + unlockSwCanvasAndPost(canvas); + } + } + } + + private void unlockSwCanvasAndPost(Canvas canvas) { if (canvas != mCanvas) { throw new IllegalArgumentException("canvas object must be the same instance that " + "was previously returned by lockCanvas"); } + if (mNativeObject != mLockedObject) { + Log.w(TAG, "WARNING: Surface's mNativeObject (0x" + + Long.toHexString(mNativeObject) + ") != mLockedObject (0x" + + Long.toHexString(mLockedObject) +")"); + } + if (mLockedObject == 0) { + throw new IllegalStateException("Surface was not locked"); + } + try { + nativeUnlockCanvasAndPost(mLockedObject, canvas); + } finally { + nativeRelease(mLockedObject); + mLockedObject = 0; + } + } + /** + * Gets a {@link Canvas} for drawing into this surface. + * + * After drawing into the provided {@link Canvas}, the caller must + * invoke {@link #unlockCanvasAndPost} to post the new contents to the surface. + * + * Unlike {@link #lockCanvas(Rect)} this will return a hardware-accelerated + * canvas. See the <a href="{@docRoot}guide/topics/graphics/hardware-accel.html#unsupported"> + * unsupported drawing operations</a> for a list of what is and isn't + * supported in a hardware-accelerated canvas. It is also required to + * fully cover the surface every time {@link #lockHardwareCanvas()} is + * called as the buffer is not preserved between frames. Partial updates + * are not supported. + * + * @return A canvas for drawing into the surface. + * + * @throws IllegalStateException If the canvas cannot be locked. + */ + public Canvas lockHardwareCanvas() { synchronized (mLock) { checkNotReleasedLocked(); - if (mNativeObject != mLockedObject) { - Log.w(TAG, "WARNING: Surface's mNativeObject (0x" + - Long.toHexString(mNativeObject) + ") != mLockedObject (0x" + - Long.toHexString(mLockedObject) +")"); - } - if (mLockedObject == 0) { - throw new IllegalStateException("Surface was not locked"); - } - try { - nativeUnlockCanvasAndPost(mLockedObject, canvas); - } finally { - nativeRelease(mLockedObject); - mLockedObject = 0; + if (mHwuiContext == null) { + mHwuiContext = new HwuiContext(); } + return mHwuiContext.lockCanvas(); } } @@ -415,6 +457,9 @@ public class Surface implements Parcelable { } mNativeObject = ptr; mGenerationId += 1; + if (mHwuiContext != null) { + mHwuiContext.updateSurface(); + } } } @@ -518,4 +563,59 @@ public class Surface implements Parcelable { mOrigMatrix.set(m); } } + + private final class HwuiContext { + private final RenderNode mRenderNode; + private long mHwuiRenderer; + private HardwareCanvas mCanvas; + + HwuiContext() { + mRenderNode = RenderNode.create("HwuiCanvas", null); + mRenderNode.setClipToBounds(false); + mHwuiRenderer = nHwuiCreate(mRenderNode.mNativeRenderNode, mNativeObject); + } + + Canvas lockCanvas() { + if (mCanvas != null) { + throw new IllegalStateException("Surface was already locked!"); + } + mCanvas = mRenderNode.start(0, 0); + return mCanvas; + } + + void unlockAndPost(Canvas canvas) { + if (canvas != mCanvas) { + throw new IllegalArgumentException("canvas object must be the same instance that " + + "was previously returned by lockCanvas"); + } + mRenderNode.end(mCanvas); + mCanvas = null; + nHwuiDraw(mHwuiRenderer); + } + + void updateSurface() { + nHwuiSetSurface(mHwuiRenderer, mNativeObject); + } + + void destroy() { + if (mHwuiRenderer != 0) { + nHwuiDestroy(mHwuiRenderer); + mHwuiRenderer = 0; + } + } + + @Override + protected void finalize() throws Throwable { + try { + destroy(); + } finally { + super.finalize(); + } + } + } + + private static native long nHwuiCreate(long rootNode, long surface); + private static native void nHwuiSetSurface(long renderer, long surface); + private static native void nHwuiDraw(long renderer); + private static native void nHwuiDestroy(long renderer); } diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java index 1e46517..0711aed 100644 --- a/core/java/android/view/ThreadedRenderer.java +++ b/core/java/android/view/ThreadedRenderer.java @@ -255,6 +255,9 @@ public class ThreadedRenderer extends HardwareRenderer { mProfilingEnabled = wantProfiling; changed = true; } + if (changed) { + invalidateRoot(); + } return changed; } diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 1ecc8d9..e7b98ca 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -5877,6 +5877,21 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return true; } + /** + * Adds the clickable rectangles withing the bounds of this view. They + * may overlap. This method is intended for use only by the accessibility + * layer. + * + * @param outRects List to which to add clickable areas. + */ + void addClickableRectsForAccessibility(List<RectF> outRects) { + if (isClickable() || isLongClickable()) { + RectF bounds = new RectF(); + bounds.set(0, 0, getWidth(), getHeight()); + outRects.add(bounds); + } + } + static void offsetRects(List<RectF> rects, float offsetX, float offsetY) { final int rectCount = rects.size(); for (int i = 0; i < rectCount; i++) { @@ -15676,7 +15691,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, sizeChange(newWidth, newHeight, oldWidth, oldHeight); } - if ((mViewFlags & VISIBILITY_MASK) == VISIBLE) { + if ((mViewFlags & VISIBILITY_MASK) == VISIBLE || mGhostView != null) { // If we are visible, force the DRAWN bit to on so that // this invalidate will go through (at least to our parent). // This is because someone may have invalidated this view @@ -15699,6 +15714,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return changed; } + /** + * Same as setFrame, but public and hidden. For use in {@link android.transition.ChangeBounds}. + * @hide + */ + public void setLeftTopRightBottom(int left, int top, int right, int bottom) { + setFrame(left, top, right, bottom); + } + private void sizeChange(int newWidth, int newHeight, int oldWidth, int oldHeight) { onSizeChanged(newWidth, newHeight, oldWidth, oldHeight); if (mOverlay != null) { @@ -16617,8 +16640,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback, invalidate(true); refreshDrawableState(); dispatchSetSelected(selected); - notifyViewAccessibilityStateChangedIfNeeded( - AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); + if (selected) { + sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + } else { + notifyViewAccessibilityStateChangedIfNeeded( + AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED); + } } } @@ -17414,17 +17441,22 @@ public class View implements Drawable.Callback, KeyEvent.Callback, long key = (long) widthMeasureSpec << 32 | (long) heightMeasureSpec & 0xffffffffL; if (mMeasureCache == null) mMeasureCache = new LongSparseLongArray(2); - if ((mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT || - widthMeasureSpec != mOldWidthMeasureSpec || - heightMeasureSpec != mOldHeightMeasureSpec) { + final boolean forceLayout = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT; + final boolean isExactly = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY && + MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY; + final boolean matchingSize = isExactly && + getMeasuredWidth() == MeasureSpec.getSize(widthMeasureSpec) && + getMeasuredHeight() == MeasureSpec.getSize(heightMeasureSpec); + if (forceLayout || !matchingSize && + (widthMeasureSpec != mOldWidthMeasureSpec || + heightMeasureSpec != mOldHeightMeasureSpec)) { // first clears the measured dimension flag mPrivateFlags &= ~PFLAG_MEASURED_DIMENSION_SET; resolveRtlPropertiesIfNeeded(); - int cacheIndex = (mPrivateFlags & PFLAG_FORCE_LAYOUT) == PFLAG_FORCE_LAYOUT ? -1 : - mMeasureCache.indexOfKey(key); + int cacheIndex = forceLayout ? -1 : mMeasureCache.indexOfKey(key); if (cacheIndex < 0 || sIgnoreMeasureCache) { // measure ourselves, this should set the measured dimension flag back onMeasure(widthMeasureSpec, heightMeasureSpec); diff --git a/core/java/android/view/ViewDebug.java b/core/java/android/view/ViewDebug.java index 12a49d5..50e64c6 100644 --- a/core/java/android/view/ViewDebug.java +++ b/core/java/android/view/ViewDebug.java @@ -1005,12 +1005,21 @@ public class ViewDebug { return fields; } - final ArrayList<Field> foundFields = new ArrayList<Field>(); - fields = klass.getDeclaredFields(); + final ArrayList<Field> declaredFields = new ArrayList(); + klass.getDeclaredFieldsUnchecked(false, declaredFields); - int count = fields.length; + final ArrayList<Field> foundFields = new ArrayList<Field>(); + final int count = declaredFields.size(); for (int i = 0; i < count; i++) { - final Field field = fields[i]; + final Field field = declaredFields.get(i); + + // Ensure the field type can be resolved. + try { + field.getType(); + } catch (NoClassDefFoundError e) { + continue; + } + if (field.isAnnotationPresent(ExportedProperty.class)) { field.setAccessible(true); foundFields.add(field); @@ -1039,12 +1048,22 @@ public class ViewDebug { return methods; } - final ArrayList<Method> foundMethods = new ArrayList<Method>(); - methods = klass.getDeclaredMethods(); + final ArrayList<Method> declaredMethods = new ArrayList(); + klass.getDeclaredMethodsUnchecked(false, declaredMethods); - int count = methods.length; + final ArrayList<Method> foundMethods = new ArrayList<Method>(); + final int count = declaredMethods.size(); for (int i = 0; i < count; i++) { - final Method method = methods[i]; + final Method method = declaredMethods.get(i); + + // Ensure the method return and parameter types can be resolved. + try { + method.getReturnType(); + method.getParameterTypes(); + } catch (NoClassDefFoundError e) { + continue; + } + if (method.getParameterTypes().length == 0 && method.isAnnotationPresent(ExportedProperty.class) && method.getReturnType() != Void.class) { diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 32d1a88..c967eb4 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -51,8 +51,10 @@ import com.android.internal.util.Predicate; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.NoSuchElementException; import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; @@ -468,6 +470,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager @ViewDebug.ExportedProperty(category = "layout") private int mChildCountWithTransientState = 0; + // Iterator over the children in decreasing Z order (top children first). + private OrderedChildIterator mOrderedChildIterator; + /** * Currently registered axes for nested scrolling. Flag set consisting of * {@link #SCROLL_AXIS_HORIZONTAL} {@link #SCROLL_AXIS_VERTICAL} or {@link #SCROLL_AXIS_NONE} @@ -817,19 +822,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return false; } - // Check whether any clickable siblings cover the child - // view and if so keep track of the intersections. Also - // respect Z ordering when iterating over children. - ArrayList<View> orderedList = buildOrderedChildList(); - final boolean useCustomOrder = orderedList == null - && isChildrenDrawingOrderEnabled(); - - final int childCount = mChildrenCount; - for (int i = childCount - 1; i >= 0; i--) { - final int childIndex = useCustomOrder - ? getChildDrawingOrder(childCount, i) : i; - final View sibling = (orderedList == null) - ? mChildren[childIndex] : orderedList.get(childIndex); + Iterator<View> iterator = obtainOrderedChildIterator(); + while (iterator.hasNext()) { + View sibling = iterator.next(); // We care only about siblings over the child. if (sibling == child) { @@ -837,12 +832,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } // Ignore invisible views as they are not interactive. - if (sibling.getVisibility() != View.VISIBLE) { - continue; - } - - // If sibling is not interactive we do not care. - if (!sibling.isClickable() && !sibling.isLongClickable()) { + if (!isVisible(sibling)) { continue; } @@ -850,28 +840,37 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager RectF siblingBounds = mAttachInfo.mTmpTransformRect1; siblingBounds.set(0, 0, sibling.getWidth(), sibling.getHeight()); - // Take into account the sibling transformation matrix. - if (!sibling.hasIdentityMatrix()) { - sibling.getMatrix().mapRect(siblingBounds); - } - - // Offset the sibling to our coordinates. - final int siblingDx = sibling.mLeft - mScrollX; - final int siblingDy = sibling.mTop - mScrollY; - siblingBounds.offset(siblingDx, siblingDy); + // Translate the sibling bounds to our coordinates. + offsetChildRectToMyCoords(siblingBounds, sibling); // Compute the intersection between the child and the sibling. if (siblingBounds.intersect(bounds)) { - // If an interactive sibling completely covers the child, done. - if (siblingBounds.equals(bounds)) { - return false; + List<RectF> clickableRects = new ArrayList<>(); + sibling.addClickableRectsForAccessibility(clickableRects); + + final int clickableRectCount = clickableRects.size(); + for (int j = 0; j < clickableRectCount; j++) { + RectF clickableRect = clickableRects.get(j); + + // Translate the clickable rect to our coordinates. + offsetChildRectToMyCoords(clickableRect, sibling); + + // Compute the intersection between the child and the clickable rects. + if (clickableRect.intersect(bounds)) { + // If a clickable rect completely covers the child, done. + if (clickableRect.equals(bounds)) { + releaseOrderedChildIterator(); + return false; + } + // Keep track of the intersection rectangle. + intersections.add(clickableRect); + } } - // Keep track of the intersection rectangle. - RectF intersection = new RectF(siblingBounds); - intersections.add(intersection); } } + releaseOrderedChildIterator(); + if (mParent instanceof ViewGroup) { ViewGroup parentGroup = (ViewGroup) mParent; return parentGroup.translateBoundsAndIntersectionsInWindowCoordinates( @@ -881,6 +880,94 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager return true; } + @Override + void addClickableRectsForAccessibility(List<RectF> outRects) { + int sizeBefore = outRects.size(); + + super.addClickableRectsForAccessibility(outRects); + + // If we added ourselves, then no need to visit children. + if (outRects.size() > sizeBefore) { + return; + } + + Iterator<View> iterator = obtainOrderedChildIterator(); + while (iterator.hasNext()) { + View child = iterator.next(); + + // Cannot click on an invisible view. + if (!isVisible(child)) { + continue; + } + + sizeBefore = outRects.size(); + + // Add clickable rects in the child bounds. + child.addClickableRectsForAccessibility(outRects); + + // Offset the clickable rects for out children to our coordinates. + final int sizeAfter = outRects.size(); + for (int j = sizeBefore; j < sizeAfter; j++) { + RectF rect = outRects.get(j); + + // Translate the clickable rect to our coordinates. + offsetChildRectToMyCoords(rect, child); + + // If a clickable rect fills the parent, done. + if ((int) rect.left == 0 && (int) rect.top == 0 + && (int) rect.right == mRight && (int) rect.bottom == mBottom) { + releaseOrderedChildIterator(); + return; + } + } + } + + releaseOrderedChildIterator(); + } + + private void offsetChildRectToMyCoords(RectF rect, View child) { + if (!child.hasIdentityMatrix()) { + child.getMatrix().mapRect(rect); + } + final int childDx = child.mLeft - mScrollX; + final int childDy = child.mTop - mScrollY; + rect.offset(childDx, childDy); + } + + private static boolean isVisible(View view) { + return (view.getAlpha() > 0 && view.getTransitionAlpha() > 0 && + view.getVisibility() == VISIBLE); + } + + /** + * Obtains the iterator to traverse the children in a descending Z order. + * Only one party can use the iterator at any given time and you cannot + * modify the children while using this iterator. Acquisition if already + * obtained is an error. + * + * @return The child iterator. + */ + OrderedChildIterator obtainOrderedChildIterator() { + if (mOrderedChildIterator == null) { + mOrderedChildIterator = new OrderedChildIterator(); + } else if (mOrderedChildIterator.isInitialized()) { + throw new IllegalStateException("Already obtained"); + } + mOrderedChildIterator.initialize(); + return mOrderedChildIterator; + } + + /** + * Releases the iterator to traverse the children in a descending Z order. + * Release if not obtained is an error. + */ + void releaseOrderedChildIterator() { + if (mOrderedChildIterator == null || !mOrderedChildIterator.isInitialized()) { + throw new IllegalStateException("Not obtained"); + } + mOrderedChildIterator.release(); + } + /** * Called when a child view has changed whether or not it is tracking transient state. */ @@ -3293,7 +3380,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager /** * Populates (and returns) mPreSortedChildren with a pre-ordered list of the View's children, - * sorted first by Z, then by child drawing order (if applicable). + * sorted first by Z, then by child drawing order (if applicable). This list must be cleared + * after use to avoid leaking child Views. * * Uses a stable, insertion sort which is commonly O(n) for ViewGroups with very few elevated * children. @@ -3668,6 +3756,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * @see #generateDefaultLayoutParams() */ public void addView(View child, int index) { + if (child == null) { + throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); + } LayoutParams params = child.getLayoutParams(); if (params == null) { params = generateDefaultLayoutParams(); @@ -3725,6 +3816,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager System.out.println(this + " addView"); } + if (child == null) { + throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); + } + // addViewInner() will call child.requestLayout() when setting the new LayoutParams // therefore, we call requestLayout() on ourselves before, so that the child's request // will be blocked at our level @@ -3852,6 +3947,9 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ protected boolean addViewInLayout(View child, int index, LayoutParams params, boolean preventRequestLayout) { + if (child == null) { + throw new IllegalArgumentException("Cannot add a null child view to a ViewGroup"); + } child.mParent = null; addViewInner(child, index, params, preventRequestLayout); child.mPrivateFlags = (child.mPrivateFlags & ~PFLAG_DIRTY_MASK) | PFLAG_DRAWN; @@ -4065,9 +4163,10 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * {@link #dispatchDraw(android.graphics.Canvas)} or any related method.</p> */ public void removeView(View view) { - removeViewInternal(view); - requestLayout(); - invalidate(true); + if (removeViewInternal(view)) { + requestLayout(); + invalidate(true); + } } /** @@ -4130,11 +4229,13 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager invalidate(true); } - private void removeViewInternal(View view) { + private boolean removeViewInternal(View view) { final int index = indexOfChild(view); if (index >= 0) { removeViewInternal(index, view); + return true; } + return false; } private void removeViewInternal(int index, View view) { @@ -6488,7 +6589,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager */ public static class MarginLayoutParams extends ViewGroup.LayoutParams { /** - * The left margin in pixels of the child. + * The left margin in pixels of the child. Margin values should be positive. * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value * to this field. */ @@ -6496,7 +6597,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public int leftMargin; /** - * The top margin in pixels of the child. + * The top margin in pixels of the child. Margin values should be positive. * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value * to this field. */ @@ -6504,7 +6605,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public int topMargin; /** - * The right margin in pixels of the child. + * The right margin in pixels of the child. Margin values should be positive. * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value * to this field. */ @@ -6512,7 +6613,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public int rightMargin; /** - * The bottom margin in pixels of the child. + * The bottom margin in pixels of the child. Margin values should be positive. * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value * to this field. */ @@ -6520,7 +6621,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager public int bottomMargin; /** - * The start margin in pixels of the child. + * The start margin in pixels of the child. Margin values should be positive. * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value * to this field. */ @@ -6528,7 +6629,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager private int startMargin = DEFAULT_MARGIN_RELATIVE; /** - * The end margin in pixels of the child. + * The end margin in pixels of the child. Margin values should be positive. * Call {@link ViewGroup#setLayoutParams(LayoutParams)} after reassigning a new value * to this field. */ @@ -6709,6 +6810,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * Sets the margins, in pixels. A call to {@link android.view.View#requestLayout()} needs * to be done so that the new margins are taken into account. Left and right margins may be * overriden by {@link android.view.View#requestLayout()} depending on layout direction. + * Margin values should be positive. * * @param left the left margin size * @param top the top margin size @@ -6738,7 +6840,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager * Sets the relative margins, in pixels. A call to {@link android.view.View#requestLayout()} * needs to be done so that the new relative margins are taken into account. Left and right * margins may be overriden by {@link android.view.View#requestLayout()} depending on layout - * direction. + * direction. Margin values should be positive. * * @param start the start margin size * @param top the top margin size @@ -6761,7 +6863,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Sets the relative start margin. + * Sets the relative start margin. Margin values should be positive. * * @param start the start margin size * @@ -6794,7 +6896,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } /** - * Sets the relative end margin. + * Sets the relative end margin. Margin values should be positive. * * @param end the end margin size * @@ -7281,4 +7383,57 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager canvas.drawLines(sDebugLines, paint); } + + private final class OrderedChildIterator implements Iterator<View> { + private List<View> mOrderedChildList; + private boolean mUseCustomOrder; + private int mCurrentIndex; + private boolean mInitialized; + + public void initialize() { + mOrderedChildList = buildOrderedChildList(); + mUseCustomOrder = (mOrderedChildList == null) + && isChildrenDrawingOrderEnabled(); + mCurrentIndex = mChildrenCount - 1; + mInitialized = true; + } + + public void release() { + if (mOrderedChildList != null) { + mOrderedChildList.clear(); + } + mUseCustomOrder = false; + mCurrentIndex = 0; + mInitialized = false; + } + + public boolean isInitialized() { + return mInitialized; + } + + @Override + public boolean hasNext() { + return (mCurrentIndex >= 0); + } + + @Override + public View next() { + if (!hasNext()) { + throw new NoSuchElementException("No such element"); + } + return getChild(mCurrentIndex--); + } + + private View getChild(int index) { + final int childIndex = mUseCustomOrder + ? getChildDrawingOrder(mChildrenCount, index) : index; + return (mOrderedChildList == null) + ? mChildren[childIndex] : mOrderedChildList.get(childIndex); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } + } } diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java index 63ab7d2..20edeb8 100644 --- a/core/java/android/view/Window.java +++ b/core/java/android/view/Window.java @@ -24,7 +24,6 @@ import android.content.res.TypedArray; import android.graphics.PixelFormat; import android.graphics.drawable.Drawable; import android.media.session.MediaController; -import android.media.session.MediaSession; import android.net.Uri; import android.os.Bundle; import android.os.IBinder; @@ -801,9 +800,6 @@ public abstract class Window { public void setFlags(int flags, int mask) { final WindowManager.LayoutParams attrs = getAttributes(); attrs.flags = (attrs.flags&~mask) | (flags&mask); - if ((mask&WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0) { - attrs.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY; - } mForcedWindowFlags |= mask; dispatchWindowAttributesChanged(attrs); } @@ -817,6 +813,15 @@ public abstract class Window { /** * {@hide} */ + protected void setNeedsMenuKey(int value) { + final WindowManager.LayoutParams attrs = getAttributes(); + attrs.needsMenuKey = value; + dispatchWindowAttributesChanged(attrs); + } + + /** + * {@hide} + */ protected void dispatchWindowAttributesChanged(WindowManager.LayoutParams attrs) { if (mCallback != null) { mCallback.onWindowAttributesChanged(attrs); @@ -1125,31 +1130,31 @@ public abstract class Window { * Set an explicit Drawable value for feature of this window. You must * have called requestFeature(featureId) before calling this function. * - * @param featureId The desired drawable feature to change. - * Features are constants defined by Window. + * @param featureId The desired drawable feature to change. Features are + * constants defined by Window. * @param drawable A Drawable object to display. */ public abstract void setFeatureDrawable(int featureId, Drawable drawable); /** - * Set a custom alpha value for the given drawale feature, controlling how + * Set a custom alpha value for the given drawable feature, controlling how * much the background is visible through it. * - * @param featureId The desired drawable feature to change. - * Features are constants defined by Window. + * @param featureId The desired drawable feature to change. Features are + * constants defined by Window. * @param alpha The alpha amount, 0 is completely transparent and 255 is * completely opaque. */ public abstract void setFeatureDrawableAlpha(int featureId, int alpha); /** - * Set the integer value for a feature. The range of the value depends on - * the feature being set. For FEATURE_PROGRESSS, it should go from 0 to - * 10000. At 10000 the progress is complete and the indicator hidden. + * Set the integer value for a feature. The range of the value depends on + * the feature being set. For {@link #FEATURE_PROGRESS}, it should go from + * 0 to 10000. At 10000 the progress is complete and the indicator hidden. * - * @param featureId The desired feature to change. - * Features are constants defined by Window. - * @param value The value for the feature. The interpretation of this + * @param featureId The desired feature to change. Features are constants + * defined by Window. + * @param value The value for the feature. The interpretation of this * value is feature-specific. */ public abstract void setFeatureInt(int featureId, int value); diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 47ee52e..5b48c0d 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -523,15 +523,6 @@ public interface WindowManager extends ViewManager { public static final int TYPE_MAGNIFICATION_OVERLAY = FIRST_SYSTEM_WINDOW+27; /** - * Window type: Recents. Same layer as {@link #TYPE_SYSTEM_DIALOG} but only appears on - * one user's screen. - * In multiuser systems shows on all users' windows. - * @hide - */ - public static final int TYPE_RECENTS_OVERLAY = FIRST_SYSTEM_WINDOW+28; - - - /** * Window type: keyguard scrim window. Shows if keyguard needs to be restarted. * In multiuser systems shows on all users' windows. * @hide @@ -551,6 +542,19 @@ public interface WindowManager extends ViewManager { public static final int TYPE_VOICE_INTERACTION = FIRST_SYSTEM_WINDOW+31; /** + * Window type: Windows that are overlaid <em>only</em> by an {@link + * android.accessibilityservice.AccessibilityService} for interception of + * user interactions without changing the windows an accessibility service + * can introspect. In particular, an accessibility service can introspect + * only windows that a sighted user can interact with which is they can touch + * these windows or can type into these windows. For example, if there + * is a full screen accessibility overlay that is touchable, the windows + * below it will be introspectable by an accessibility service regardless + * they are covered by a touchable window. + */ + public static final int TYPE_ACCESSIBILITY_OVERLAY = FIRST_SYSTEM_WINDOW+32; + + /** * End of types of system windows. */ public static final int LAST_SYSTEM_WINDOW = 2999; @@ -887,9 +891,6 @@ public interface WindowManager extends ViewManager { */ public static final int FLAG_TRANSLUCENT_NAVIGATION = 0x08000000; - // ----- HIDDEN FLAGS. - // These start at the high bit and go down. - /** * Flag for a window in local focus mode. * Window in local focus mode can control focus independent of window manager using @@ -912,17 +913,12 @@ public interface WindowManager extends ViewManager { public static final int FLAG_SLIPPERY = 0x20000000; /** - * Flag for a window belonging to an activity that responds to {@link KeyEvent#KEYCODE_MENU} - * and therefore needs a Menu key. For devices where Menu is a physical button this flag is - * ignored, but on devices where the Menu key is drawn in software it may be hidden unless - * this flag is set. - * - * (Note that Action Bars, when available, are the preferred way to offer additional - * functions otherwise accessed via an options menu.) - * - * {@hide} + * Window flag: When requesting layout with an attached window, the attached window may + * overlap with the screen decorations of the parent window such as the navigation bar. By + * including this flag, the window manager will layout the attached window within the decor + * frame of the parent window such that it doesn't overlap with screen decorations. */ - public static final int FLAG_NEEDS_MENU_KEY = 0x40000000; + public static final int FLAG_LAYOUT_ATTACHED_IN_DECOR = 0x40000000; /** * Flag indicating that this Window is responsible for drawing the background for the @@ -1065,16 +1061,6 @@ public interface WindowManager extends ViewManager { */ public static final int PRIVATE_FLAG_WANTS_OFFSET_NOTIFICATIONS = 0x00000004; - /** - * This is set for a window that has explicitly specified its - * FLAG_NEEDS_MENU_KEY, so we know the value on this window is the - * appropriate one to use. If this is not set, we should look at - * windows behind it to determine the appropriate value. - * - * @hide - */ - public static final int PRIVATE_FLAG_SET_NEEDS_MENU_KEY = 0x00000008; - /** In a multiuser system if this flag is set and the owner is a system process then this * window will appear on all user screens. This overrides the default behavior of window * types that normally only appear on the owning user's screen. Refer to each window type @@ -1122,6 +1108,45 @@ public interface WindowManager extends ViewManager { public int privateFlags; /** + * Value for {@link #needsMenuKey} for a window that has not explicitly specified if it + * needs {@link #NEEDS_MENU_SET_TRUE} or doesn't need {@link #NEEDS_MENU_SET_FALSE} a menu + * key. For this case, we should look at windows behind it to determine the appropriate + * value. + * + * @hide + */ + public static final int NEEDS_MENU_UNSET = 0; + + /** + * Value for {@link #needsMenuKey} for a window that has explicitly specified it needs a + * menu key. + * + * @hide + */ + public static final int NEEDS_MENU_SET_TRUE = 1; + + /** + * Value for {@link #needsMenuKey} for a window that has explicitly specified it doesn't + * needs a menu key. + * + * @hide + */ + public static final int NEEDS_MENU_SET_FALSE = 2; + + /** + * State variable for a window belonging to an activity that responds to + * {@link KeyEvent#KEYCODE_MENU} and therefore needs a Menu key. For devices where Menu is a + * physical button this variable is ignored, but on devices where the Menu key is drawn in + * software it may be hidden unless this variable is set to {@link #NEEDS_MENU_SET_TRUE}. + * + * (Note that Action Bars, when available, are the preferred way to offer additional + * functions otherwise accessed via an options menu.) + * + * {@hide} + */ + public int needsMenuKey = NEEDS_MENU_UNSET; + + /** * Given a particular set of window manager flags, determine whether * such a window may be a target for an input method when it has * focus. In particular, this checks the @@ -1129,9 +1154,9 @@ public interface WindowManager extends ViewManager { * flags and returns true if the combination of the two corresponds * to a window that needs to be behind the input method so that the * user can type into it. - * + * * @param flags The current window manager flags. - * + * * @return Returns true if such a window should be behind/interact * with an input method, false if not. */ @@ -1596,14 +1621,15 @@ public interface WindowManager extends ViewManager { out.writeInt(surfaceInsets.top); out.writeInt(surfaceInsets.right); out.writeInt(surfaceInsets.bottom); + out.writeInt(needsMenuKey); } - + public static final Parcelable.Creator<LayoutParams> CREATOR = new Parcelable.Creator<LayoutParams>() { public LayoutParams createFromParcel(Parcel in) { return new LayoutParams(in); } - + public LayoutParams[] newArray(int size) { return new LayoutParams[size]; } @@ -1643,8 +1669,9 @@ public interface WindowManager extends ViewManager { surfaceInsets.top = in.readInt(); surfaceInsets.right = in.readInt(); surfaceInsets.bottom = in.readInt(); + needsMenuKey = in.readInt(); } - + @SuppressWarnings({"PointlessBitwiseExpression"}) public static final int LAYOUT_CHANGED = 1<<0; public static final int TYPE_CHANGED = 1<<1; @@ -1678,14 +1705,16 @@ public interface WindowManager extends ViewManager { /** {@hide} */ public static final int PREFERRED_REFRESH_RATE_CHANGED = 1 << 21; /** {@hide} */ + public static final int NEEDS_MENU_KEY_CHANGED = 1 << 22; + /** {@hide} */ public static final int EVERYTHING_CHANGED = 0xffffffff; // internal buffer to backup/restore parameters under compatibility mode. private int[] mCompatibilityParamsBackup = null; - + public final int copyFrom(LayoutParams o) { int changes = 0; - + if (width != o.width) { width = o.width; changes |= LAYOUT_CHANGED; @@ -1822,9 +1851,14 @@ public interface WindowManager extends ViewManager { changes |= SURFACE_INSETS_CHANGED; } + if (needsMenuKey != o.needsMenuKey) { + needsMenuKey = o.needsMenuKey; + changes |= NEEDS_MENU_KEY_CHANGED; + } + return changes; } - + @Override public String debug(String output) { output += "Contents of " + this + ":"; @@ -1928,6 +1962,10 @@ public interface WindowManager extends ViewManager { if (!surfaceInsets.equals(Insets.NONE)) { sb.append(" surfaceInsets=").append(surfaceInsets); } + if (needsMenuKey != NEEDS_MENU_UNSET) { + sb.append(" needsMenuKey="); + sb.append(needsMenuKey); + } sb.append('}'); return sb.toString(); } diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java index 38e3723..f557b97 100644 --- a/core/java/android/view/WindowManagerInternal.java +++ b/core/java/android/view/WindowManagerInternal.java @@ -173,4 +173,20 @@ public abstract class WindowManagerInternal { * redrawn. */ public abstract void waitForAllWindowsDrawn(Runnable callback, long timeout); + + /** + * Adds a window token for a given window type. + * + * @param token The token to add. + * @param type The window type. + */ + public abstract void addWindowToken(android.os.IBinder token, int type); + + /** + * Removes a window token. + * + * @param token The toke to remove. + * @param removeWindows Whether to also remove the windows associated with the token. + */ + public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows); } diff --git a/core/java/android/view/accessibility/AccessibilityWindowInfo.java b/core/java/android/view/accessibility/AccessibilityWindowInfo.java index ad55f5f..e1942be 100644 --- a/core/java/android/view/accessibility/AccessibilityWindowInfo.java +++ b/core/java/android/view/accessibility/AccessibilityWindowInfo.java @@ -51,11 +51,24 @@ public final class AccessibilityWindowInfo implements Parcelable { */ public static final int TYPE_SYSTEM = 3; + /** + * Window type: Windows that are overlaid <em>only</em> by an {@link + * android.accessibilityservice.AccessibilityService} for interception of + * user interactions without changing the windows an accessibility service + * can introspect. In particular, an accessibility service can introspect + * only windows that a sighted user can interact with which they can touch + * these windows or can type into these windows. For example, if there + * is a full screen accessibility overlay that is touchable, the windows + * below it will be introspectable by an accessibility service regardless + * they are covered by a touchable window. + */ + public static final int TYPE_ACCESSIBILITY_OVERLAY = 4; + private static final int UNDEFINED = -1; private static final int BOOLEAN_PROPERTY_ACTIVE = 1 << 0; private static final int BOOLEAN_PROPERTY_FOCUSED = 1 << 1; - private static final int BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED = 1 << 2; + private static final int BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED = 1 << 2; // Housekeeping. private static final int MAX_POOL_SIZE = 10; @@ -85,6 +98,7 @@ public final class AccessibilityWindowInfo implements Parcelable { * @see #TYPE_APPLICATION * @see #TYPE_INPUT_METHOD * @see #TYPE_SYSTEM + * @see #TYPE_ACCESSIBILITY_OVERLAY */ public int getType() { return mType; @@ -93,7 +107,7 @@ public final class AccessibilityWindowInfo implements Parcelable { /** * Sets the type of the window. * - * @param The type + * @param type The type * * @hide */ @@ -115,7 +129,7 @@ public final class AccessibilityWindowInfo implements Parcelable { * Sets the layer which determines the Z-order of the window. Windows * with greater layer appear on top of windows with lesser layer. * - * @param The window layer. + * @param layer The window layer. * * @hide */ @@ -174,7 +188,7 @@ public final class AccessibilityWindowInfo implements Parcelable { /** * Sets the unique window id. * - * @param windowId The window id. + * @param id The window id. * * @hide */ @@ -230,7 +244,7 @@ public final class AccessibilityWindowInfo implements Parcelable { * the user is currently touching or the window has input focus * and the user is not touching any window. * - * @param Whether this is the active window. + * @param active Whether this is the active window. * * @hide */ @@ -250,7 +264,7 @@ public final class AccessibilityWindowInfo implements Parcelable { /** * Sets if this window has input focus. * - * @param Whether has input focus. + * @param focused Whether has input focus. * * @hide */ @@ -264,18 +278,18 @@ public final class AccessibilityWindowInfo implements Parcelable { * @return Whether has accessibility focus. */ public boolean isAccessibilityFocused() { - return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED); + return getBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED); } /** * Sets if this window has accessibility focus. * - * @param Whether has accessibility focus. + * @param focused Whether has accessibility focus. * * @hide */ public void setAccessibilityFocused(boolean focused) { - setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBLITY_FOCUSED, focused); + setBooleanProperty(BOOLEAN_PROPERTY_ACCESSIBILITY_FOCUSED, focused); } /** @@ -534,6 +548,9 @@ public final class AccessibilityWindowInfo implements Parcelable { case TYPE_SYSTEM: { return "TYPE_SYSTEM"; } + case TYPE_ACCESSIBILITY_OVERLAY: { + return "TYPE_ACCESSIBILITY_OVERLAY"; + } default: return "<UNKNOWN>"; } diff --git a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java index ed6949a..21d5a5b 100644 --- a/core/java/android/view/animation/AccelerateDecelerateInterpolator.java +++ b/core/java/android/view/animation/AccelerateDecelerateInterpolator.java @@ -26,17 +26,17 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; /** * An interpolator where the rate of change starts and ends slowly but * accelerates through the middle. - * */ @HasNativeInterpolator -public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory { +public class AccelerateDecelerateInterpolator extends BaseInterpolator + implements NativeInterpolatorFactory { public AccelerateDecelerateInterpolator() { } - + @SuppressWarnings({"UnusedDeclaration"}) public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) { } - + public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } diff --git a/core/java/android/view/animation/AccelerateInterpolator.java b/core/java/android/view/animation/AccelerateInterpolator.java index 1c75f16..6c8d7b1 100644 --- a/core/java/android/view/animation/AccelerateInterpolator.java +++ b/core/java/android/view/animation/AccelerateInterpolator.java @@ -33,7 +33,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; * */ @HasNativeInterpolator -public class AccelerateInterpolator implements Interpolator, NativeInterpolatorFactory { +public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { private final float mFactor; private final double mDoubleFactor; @@ -70,7 +70,7 @@ public class AccelerateInterpolator implements Interpolator, NativeInterpolatorF mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f); mDoubleFactor = 2 * mFactor; - + setChangingConfiguration(a.getChangingConfigurations()); a.recycle(); } diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index af4e04f..606c83e 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -321,7 +321,7 @@ public class AnimationUtils { private static Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser) throws XmlPullParserException, IOException { - Interpolator interpolator = null; + BaseInterpolator interpolator = null; // Make sure we are on a start tag. int type; @@ -361,10 +361,7 @@ public class AnimationUtils { } else { throw new RuntimeException("Unknown interpolator name: " + parser.getName()); } - } - return interpolator; - } } diff --git a/core/java/android/view/animation/AnticipateInterpolator.java b/core/java/android/view/animation/AnticipateInterpolator.java index fe756bd..fb66c31 100644 --- a/core/java/android/view/animation/AnticipateInterpolator.java +++ b/core/java/android/view/animation/AnticipateInterpolator.java @@ -31,7 +31,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; * An interpolator where the change starts backward then flings forward. */ @HasNativeInterpolator -public class AnticipateInterpolator implements Interpolator, NativeInterpolatorFactory { +public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { private final float mTension; public AnticipateInterpolator() { @@ -60,9 +60,8 @@ public class AnticipateInterpolator implements Interpolator, NativeInterpolatorF a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator); } - mTension = - a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f); - + mTension = a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f); + setChangingConfiguration(a.getChangingConfigurations()); a.recycle(); } diff --git a/core/java/android/view/animation/AnticipateOvershootInterpolator.java b/core/java/android/view/animation/AnticipateOvershootInterpolator.java index 78e5acf..1af72da 100644 --- a/core/java/android/view/animation/AnticipateOvershootInterpolator.java +++ b/core/java/android/view/animation/AnticipateOvershootInterpolator.java @@ -35,7 +35,8 @@ import static com.android.internal.R.styleable.AnticipateOvershootInterpolator; * the target value and finally goes back to the final value. */ @HasNativeInterpolator -public class AnticipateOvershootInterpolator implements Interpolator, NativeInterpolatorFactory { +public class AnticipateOvershootInterpolator extends BaseInterpolator + implements NativeInterpolatorFactory { private final float mTension; public AnticipateOvershootInterpolator() { @@ -78,7 +79,7 @@ public class AnticipateOvershootInterpolator implements Interpolator, NativeInte mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) * a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f); - + setChangingConfiguration(a.getChangingConfigurations()); a.recycle(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java b/core/java/android/view/animation/BaseInterpolator.java index f339401..9c0014c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Prefs.java +++ b/core/java/android/view/animation/BaseInterpolator.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 The Android Open Source Project + * 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. @@ -14,19 +14,24 @@ * limitations under the License. */ -package com.android.systemui.statusbar.policy; +package android.view.animation; -import android.content.Context; -import android.content.SharedPreferences; - -public class Prefs { - private static final String SHARED_PREFS_NAME = "status_bar"; - - public static SharedPreferences read(Context context) { - return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE); +/** + * An abstract class which is extended by default interpolators. + */ +abstract public class BaseInterpolator implements Interpolator { + private int mChangingConfiguration; + /** + * @hide + */ + public int getChangingConfiguration() { + return mChangingConfiguration; } - public static SharedPreferences.Editor edit(Context context) { - return context.getSharedPreferences(Prefs.SHARED_PREFS_NAME, Context.MODE_PRIVATE).edit(); + /** + * @hide + */ + void setChangingConfiguration(int changingConfiguration) { + mChangingConfiguration = changingConfiguration; } } diff --git a/core/java/android/view/animation/BounceInterpolator.java b/core/java/android/view/animation/BounceInterpolator.java index 9d8ca90..909eaa4 100644 --- a/core/java/android/view/animation/BounceInterpolator.java +++ b/core/java/android/view/animation/BounceInterpolator.java @@ -27,7 +27,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; * An interpolator where the change bounces at the end. */ @HasNativeInterpolator -public class BounceInterpolator implements Interpolator, NativeInterpolatorFactory { +public class BounceInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public BounceInterpolator() { } diff --git a/core/java/android/view/animation/CycleInterpolator.java b/core/java/android/view/animation/CycleInterpolator.java index 3114aa3..663c109 100644 --- a/core/java/android/view/animation/CycleInterpolator.java +++ b/core/java/android/view/animation/CycleInterpolator.java @@ -33,7 +33,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; * */ @HasNativeInterpolator -public class CycleInterpolator implements Interpolator, NativeInterpolatorFactory { +public class CycleInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public CycleInterpolator(float cycles) { mCycles = cycles; } @@ -52,7 +52,7 @@ public class CycleInterpolator implements Interpolator, NativeInterpolatorFactor } mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f); - + setChangingConfiguration(a.getChangingConfigurations()); a.recycle(); } diff --git a/core/java/android/view/animation/DecelerateInterpolator.java b/core/java/android/view/animation/DecelerateInterpolator.java index 674207c..f426f60 100644 --- a/core/java/android/view/animation/DecelerateInterpolator.java +++ b/core/java/android/view/animation/DecelerateInterpolator.java @@ -33,7 +33,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; * */ @HasNativeInterpolator -public class DecelerateInterpolator implements Interpolator, NativeInterpolatorFactory { +public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public DecelerateInterpolator() { } @@ -62,7 +62,7 @@ public class DecelerateInterpolator implements Interpolator, NativeInterpolatorF } mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f); - + setChangingConfiguration(a.getChangingConfigurations()); a.recycle(); } diff --git a/core/java/android/view/animation/LinearInterpolator.java b/core/java/android/view/animation/LinearInterpolator.java index 552c611..2a047b4 100644 --- a/core/java/android/view/animation/LinearInterpolator.java +++ b/core/java/android/view/animation/LinearInterpolator.java @@ -25,17 +25,16 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; /** * An interpolator where the rate of change is constant - * */ @HasNativeInterpolator -public class LinearInterpolator implements Interpolator, NativeInterpolatorFactory { +public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { public LinearInterpolator() { } - + public LinearInterpolator(Context context, AttributeSet attrs) { } - + public float getInterpolation(float input) { return input; } diff --git a/core/java/android/view/animation/OvershootInterpolator.java b/core/java/android/view/animation/OvershootInterpolator.java index d6c2808..306688a 100644 --- a/core/java/android/view/animation/OvershootInterpolator.java +++ b/core/java/android/view/animation/OvershootInterpolator.java @@ -32,7 +32,7 @@ import com.android.internal.view.animation.NativeInterpolatorFactoryHelper; * then comes back. */ @HasNativeInterpolator -public class OvershootInterpolator implements Interpolator, NativeInterpolatorFactory { +public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { private final float mTension; public OvershootInterpolator() { @@ -61,9 +61,8 @@ public class OvershootInterpolator implements Interpolator, NativeInterpolatorFa a = res.obtainAttributes(attrs, R.styleable.OvershootInterpolator); } - mTension = - a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f); - + mTension = a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f); + setChangingConfiguration(a.getChangingConfigurations()); a.recycle(); } diff --git a/core/java/android/view/animation/PathInterpolator.java b/core/java/android/view/animation/PathInterpolator.java index 945ecf0..eec5555 100644 --- a/core/java/android/view/animation/PathInterpolator.java +++ b/core/java/android/view/animation/PathInterpolator.java @@ -42,7 +42,7 @@ import com.android.internal.R; * path.lineTo(1f, 1f); * </pre></blockquote></p> */ -public class PathInterpolator implements Interpolator { +public class PathInterpolator extends BaseInterpolator { // This governs how accurate the approximation of the Path is. private static final float PRECISION = 0.002f; @@ -98,7 +98,7 @@ public class PathInterpolator implements Interpolator { a = res.obtainAttributes(attrs, R.styleable.PathInterpolator); } parseInterpolatorFromTypeArray(a); - + setChangingConfiguration(a.getChangingConfigurations()); a.recycle(); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 6a34c80..ef953de 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -4655,7 +4655,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te if (mPositionScroller == null) { mPositionScroller = createPositionScroller(); } - mPositionScroller.startWithOffset(position, offset, offset); + mPositionScroller.startWithOffset(position, offset); } /** diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java index b9f891c..5e2394c 100644 --- a/core/java/android/widget/AdapterView.java +++ b/core/java/android/widget/AdapterView.java @@ -215,7 +215,12 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { private boolean mDesiredFocusableState; private boolean mDesiredFocusableInTouchModeState; + /** Lazily-constructed runnable for dispatching selection events. */ private SelectionNotifier mSelectionNotifier; + + /** Selection notifier that's waiting for the next layout pass. */ + private SelectionNotifier mPendingSelectionNotifier; + /** * When set to true, calls to requestLayout() will not propagate up the parent hierarchy. * This is used to layout the children during a layout pass. @@ -854,39 +859,51 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { private class SelectionNotifier implements Runnable { public void run() { - if (mDataChanged) { - // Data has changed between when this SelectionNotifier - // was posted and now. We need to wait until the AdapterView - // has been synched to the new data. + mPendingSelectionNotifier = null; + + if (mDataChanged && getViewRootImpl() != null + && getViewRootImpl().isLayoutRequested()) { + // Data has changed between when this SelectionNotifier was + // posted and now. Postpone the notification until the next + // layout is complete and we run checkSelectionChanged(). if (getAdapter() != null) { - post(this); + mPendingSelectionNotifier = this; } } else { - fireOnSelected(); - performAccessibilityActionsOnSelected(); + dispatchOnItemSelected(); } } } void selectionChanged() { + // We're about to post or run the selection notifier, so we don't need + // a pending notifier. + mPendingSelectionNotifier = null; + if (mOnItemSelectedListener != null || AccessibilityManager.getInstance(mContext).isEnabled()) { if (mInLayout || mBlockLayoutRequests) { // If we are in a layout traversal, defer notification // by posting. This ensures that the view tree is - // in a consistent state and is able to accomodate + // in a consistent state and is able to accommodate // new layout or invalidate requests. if (mSelectionNotifier == null) { mSelectionNotifier = new SelectionNotifier(); + } else { + removeCallbacks(mSelectionNotifier); } post(mSelectionNotifier); } else { - fireOnSelected(); - performAccessibilityActionsOnSelected(); + dispatchOnItemSelected(); } } } + private void dispatchOnItemSelected() { + fireOnSelected(); + performAccessibilityActionsOnSelected(); + } + private void fireOnSelected() { if (mOnItemSelectedListener == null) { return; @@ -1042,12 +1059,22 @@ public abstract class AdapterView<T extends Adapter> extends ViewGroup { notifySubtreeAccessibilityStateChangedIfNeeded(); } + /** + * Called after layout to determine whether the selection position needs to + * be updated. Also used to fire any pending selection events. + */ void checkSelectionChanged() { if ((mSelectedPosition != mOldSelectedPosition) || (mSelectedRowId != mOldSelectedRowId)) { selectionChanged(); mOldSelectedPosition = mSelectedPosition; mOldSelectedRowId = mSelectedRowId; } + + // If we have a pending selection notification -- and we won't if we + // just fired one in selectionChanged() -- run it now. + if (mPendingSelectionNotifier != null) { + mPendingSelectionNotifier.run(); + } } /** diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java index 10e56c7..5c05b5a 100644 --- a/core/java/android/widget/AppSecurityPermissions.java +++ b/core/java/android/widget/AppSecurityPermissions.java @@ -99,12 +99,12 @@ public class AppSecurityPermissions { public Drawable loadGroupIcon(PackageManager pm) { if (icon != 0) { - return loadIcon(pm); + return loadUnbadgedIcon(pm); } else { ApplicationInfo appInfo; try { appInfo = pm.getApplicationInfo(packageName, 0); - return appInfo.loadIcon(pm); + return appInfo.loadUnbadgedIcon(pm); } catch (NameNotFoundException e) { } } diff --git a/core/java/android/widget/CalendarView.java b/core/java/android/widget/CalendarView.java index ea60abb..f380d68 100644 --- a/core/java/android/widget/CalendarView.java +++ b/core/java/android/widget/CalendarView.java @@ -775,9 +775,14 @@ public class CalendarView extends FrameLayout { private ViewGroup mDayNamesHeader; /** - * Cached labels for the week names header. + * Cached abbreviations for day of week names. */ - private String[] mDayLabels; + private String[] mDayNamesShort; + + /** + * Cached full-length day of week names. + */ + private String[] mDayNamesLong; /** * The first day of the week. @@ -1306,11 +1311,14 @@ public class CalendarView extends FrameLayout { * Sets up the strings to be used by the header. */ private void setUpHeader() { - mDayLabels = new String[mDaysPerWeek]; + mDayNamesShort = new String[mDaysPerWeek]; + mDayNamesLong = new String[mDaysPerWeek]; for (int i = mFirstDayOfWeek, count = mFirstDayOfWeek + mDaysPerWeek; i < count; i++) { int calendarDay = (i > Calendar.SATURDAY) ? i - Calendar.SATURDAY : i; - mDayLabels[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay, + mDayNamesShort[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay, DateUtils.LENGTH_SHORTEST); + mDayNamesLong[i - mFirstDayOfWeek] = DateUtils.getDayOfWeekString(calendarDay, + DateUtils.LENGTH_LONG); } TextView label = (TextView) mDayNamesHeader.getChildAt(0); @@ -1325,7 +1333,8 @@ public class CalendarView extends FrameLayout { label.setTextAppearance(mContext, mWeekDayTextAppearanceResId); } if (i < mDaysPerWeek + 1) { - label.setText(mDayLabels[i - 1]); + label.setText(mDayNamesShort[i - 1]); + label.setContentDescription(mDayNamesLong[i - 1]); label.setVisibility(View.VISIBLE); } else { label.setVisibility(View.GONE); diff --git a/core/java/android/widget/CompoundButton.java b/core/java/android/widget/CompoundButton.java index 7d9d305..092e31c 100644 --- a/core/java/android/widget/CompoundButton.java +++ b/core/java/android/widget/CompoundButton.java @@ -29,6 +29,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.AttributeSet; import android.view.Gravity; +import android.view.SoundEffectConstants; import android.view.ViewDebug; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; @@ -114,15 +115,16 @@ public abstract class CompoundButton extends Button implements Checkable { @Override public boolean performClick() { - /* - * XXX: These are tiny, need some surrounding 'expanded touch area', - * which will need to be implemented in Button if we only override - * performClick() - */ - - /* When clicked, toggle the state */ toggle(); - return super.performClick(); + + final boolean handled = super.performClick(); + if (!handled) { + // View only makes a sound effect if the onClickListener was + // called, so we'll need to make one here instead. + playSoundEffect(SoundEffectConstants.CLICK); + } + + return handled; } @ViewDebug.ExportedProperty diff --git a/core/java/android/widget/DatePickerCalendarDelegate.java b/core/java/android/widget/DatePickerCalendarDelegate.java index e71b383..64c81e0 100644 --- a/core/java/android/widget/DatePickerCalendarDelegate.java +++ b/core/java/android/widget/DatePickerCalendarDelegate.java @@ -21,13 +21,11 @@ import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.drawable.Drawable; import android.os.Parcel; import android.os.Parcelable; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.AttributeSet; -import android.util.SparseArray; import android.view.HapticFeedbackConstants; import android.view.LayoutInflater; import android.view.View; @@ -186,6 +184,8 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i headerSelectedTextColor)); mDayPickerView = new DayPickerView(mContext, this); + mDayPickerView.setRange(mMinDate, mMaxDate); + mYearPickerView = new YearPickerView(mContext); mYearPickerView.init(this); @@ -411,7 +411,8 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i updateDisplay(false); } mMinDate.setTimeInMillis(minDate); - mDayPickerView.goTo(getSelectedDay(), false, true, true); + mDayPickerView.setRange(mMinDate, mMaxDate); + mYearPickerView.setRange(mMinDate, mMaxDate); } @Override @@ -432,7 +433,8 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i updateDisplay(false); } mMaxDate.setTimeInMillis(maxDate); - mDayPickerView.goTo(getSelectedDay(), false, true, true); + mDayPickerView.setRange(mMinDate, mMaxDate); + mYearPickerView.setRange(mMinDate, mMaxDate); } @Override @@ -454,36 +456,6 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate i } @Override - public int getMinYear() { - return mMinDate.get(Calendar.YEAR); - } - - @Override - public int getMaxYear() { - return mMaxDate.get(Calendar.YEAR); - } - - @Override - public int getMinMonth() { - return mMinDate.get(Calendar.MONTH); - } - - @Override - public int getMaxMonth() { - return mMaxDate.get(Calendar.MONTH); - } - - @Override - public int getMinDay() { - return mMinDate.get(Calendar.DAY_OF_MONTH); - } - - @Override - public int getMaxDay() { - return mMaxDate.get(Calendar.DAY_OF_MONTH); - } - - @Override public void setEnabled(boolean enabled) { mMonthAndDayLayout.setEnabled(enabled); mHeaderYearTextView.setEnabled(enabled); diff --git a/core/java/android/widget/DatePickerController.java b/core/java/android/widget/DatePickerController.java index 059709d..ea6ec61 100644 --- a/core/java/android/widget/DatePickerController.java +++ b/core/java/android/widget/DatePickerController.java @@ -38,20 +38,5 @@ interface DatePickerController { void setFirstDayOfWeek(int firstDayOfWeek); int getFirstDayOfWeek(); - int getMinYear(); - int getMaxYear(); - - int getMinMonth(); - int getMaxMonth(); - - int getMinDay(); - int getMaxDay(); - - void setMinDate(long minDate); - Calendar getMinDate(); - - void setMaxDate(long maxDate); - Calendar getMaxDate(); - void tryVibrate(); } diff --git a/core/java/android/widget/DayPickerView.java b/core/java/android/widget/DayPickerView.java index ca4095e..fcf66f6 100644 --- a/core/java/android/widget/DayPickerView.java +++ b/core/java/android/widget/DayPickerView.java @@ -25,6 +25,7 @@ import android.os.Bundle; import android.os.Handler; import android.util.AttributeSet; import android.util.Log; +import android.util.MathUtils; import android.view.View; import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; @@ -57,9 +58,11 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener, // highlighted time private Calendar mSelectedDay = Calendar.getInstance(); - private SimpleMonthAdapter mAdapter; - private Calendar mTempDay = Calendar.getInstance(); + private Calendar mMinDate = Calendar.getInstance(); + private Calendar mMaxDate = Calendar.getInstance(); + + private SimpleMonthAdapter mAdapter; // which month should be displayed/highlighted [0-11] private int mCurrentMonthDisplayed; @@ -75,6 +78,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener, public DayPickerView(Context context, DatePickerController controller) { super(context); + init(); setController(controller); } @@ -97,6 +101,41 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener, setUpListView(); } + public void setRange(Calendar minDate, Calendar maxDate) { + mMinDate.setTimeInMillis(minDate.getTimeInMillis()); + mMaxDate.setTimeInMillis(maxDate.getTimeInMillis()); + + mAdapter.setRange(mMinDate, mMaxDate); + + if (constrainCalendar(mSelectedDay, mMinDate, mMaxDate)) { + goTo(mSelectedDay, false, true, true); + } + } + + /** + * Constrains the supplied calendar to stay within the min and max + * calendars, returning <code>true</code> if the supplied calendar + * was modified. + * + * @param value The calendar to constrain + * @param min The minimum calendar + * @param max The maximum calendar + * @return True if <code>value</code> was modified + */ + private boolean constrainCalendar(Calendar value, Calendar min, Calendar max) { + if (value.compareTo(min) < 0) { + value.setTimeInMillis(min.getTimeInMillis()); + return true; + } + + if (value.compareTo(max) > 0) { + value.setTimeInMillis(max.getTimeInMillis()); + return true; + } + + return false; + } + public void onChange() { setUpAdapter(); setAdapter(mAdapter); @@ -137,23 +176,16 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener, setFriction(ViewConfiguration.getScrollFriction() * mFriction); } - private int getDiffMonths(Calendar start, Calendar end){ + private int getDiffMonths(Calendar start, Calendar end) { final int diffYears = end.get(Calendar.YEAR) - start.get(Calendar.YEAR); final int diffMonths = end.get(Calendar.MONTH) - start.get(Calendar.MONTH) + 12 * diffYears; return diffMonths; } private int getPositionFromDay(Calendar day) { - final int diffMonthMax = getDiffMonths(mController.getMinDate(), mController.getMaxDate()); - int diffMonth = getDiffMonths(mController.getMinDate(), day); - - if (diffMonth < 0 ) { - diffMonth = 0; - } else if (diffMonth > diffMonthMax) { - diffMonth = diffMonthMax; - } - - return diffMonth; + final int diffMonthMax = getDiffMonths(mMinDate, mMaxDate); + final int diffMonth = getDiffMonths(mMinDate, day); + return MathUtils.constrain(diffMonth, 0, diffMonthMax); } /** @@ -171,8 +203,7 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener, * visible * @return Whether or not the view animated to the new location */ - public boolean goTo(Calendar day, boolean animate, boolean setSelected, - boolean forceScroll) { + public boolean goTo(Calendar day, boolean animate, boolean setSelected, boolean forceScroll) { // Set the selected day if (setSelected) { @@ -464,10 +495,10 @@ class DayPickerView extends ListView implements AbsListView.OnScrollListener, } // Figure out what month is showing. - int firstVisiblePosition = getFirstVisiblePosition(); - int month = firstVisiblePosition % 12; - int year = firstVisiblePosition / 12 + mController.getMinYear(); - Calendar day = Calendar.getInstance(); + final int firstVisiblePosition = getFirstVisiblePosition(); + final int month = firstVisiblePosition % 12; + final int year = firstVisiblePosition / 12 + mMinDate.get(Calendar.YEAR); + final Calendar day = Calendar.getInstance(); day.set(year, month, 1); // Scroll either forward or backward one month. diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index f90a9fe..75dfcca 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -1120,6 +1120,9 @@ public class ImageView extends View { /** @hide */ public void animateTransform(Matrix matrix) { + if (mDrawable == null) { + return; + } if (matrix == null) { mDrawable.setBounds(0, 0, getWidth(), getHeight()); } else { diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java index 3c186e3..9f540c0 100644 --- a/core/java/android/widget/ListPopupWindow.java +++ b/core/java/android/widget/ListPopupWindow.java @@ -1639,6 +1639,11 @@ public class ListPopupWindow { setPressed(false); updateSelectorState(); + final View motionView = getChildAt(mMotionPosition - mFirstPosition); + if (motionView != null) { + motionView.setPressed(false); + } + if (mClickAnimation != null) { mClickAnimation.cancel(); mClickAnimation = null; @@ -1653,6 +1658,15 @@ public class ListPopupWindow { setPressed(true); layoutChildren(); + // Manage the pressed view based on motion position. This allows us to + // play nicely with actual touch and scroll events. + final View motionView = getChildAt(mMotionPosition - mFirstPosition); + if (motionView != null) { + motionView.setPressed(false); + } + mMotionPosition = position; + child.setPressed(true); + // Ensure that keyboard focus starts from the last touched position. setSelectedPositionInt(position); positionSelectorLikeTouch(position, child, x, y); diff --git a/core/java/android/widget/PopupMenu.java b/core/java/android/widget/PopupMenu.java index 111dadc..2708398 100644 --- a/core/java/android/widget/PopupMenu.java +++ b/core/java/android/widget/PopupMenu.java @@ -16,6 +16,7 @@ package android.widget; +import com.android.internal.R; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.MenuPresenter; @@ -37,10 +38,11 @@ import android.widget.ListPopupWindow.ForwardingListener; * of the popup will dismiss it. */ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback { - private Context mContext; - private MenuBuilder mMenu; - private View mAnchor; - private MenuPopupHelper mPopup; + private final Context mContext; + private final MenuBuilder mMenu; + private final View mAnchor; + private final MenuPopupHelper mPopup; + private OnMenuItemClickListener mMenuItemClickListener; private OnDismissListener mDismissListener; private OnTouchListener mDragListener; @@ -58,31 +60,56 @@ public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback { } /** - * Construct a new PopupMenu. + * Constructor to create a new popup menu with an anchor view. * - * @param context Context for the PopupMenu. - * @param anchor Anchor view for this popup. The popup will appear below the anchor if there - * is room, or above it if there is not. + * @param context Context the popup menu is running in, through which it + * can access the current theme, resources, etc. + * @param anchor Anchor view for this popup. The popup will appear below + * the anchor if there is room, or above it if there is not. */ public PopupMenu(Context context, View anchor) { this(context, anchor, Gravity.NO_GRAVITY); } /** - * Construct a new PopupMenu. + * Constructor to create a new popup menu with an anchor view and alignment + * gravity. * - * @param context Context for the PopupMenu. - * @param anchor Anchor view for this popup. The popup will appear below the anchor if there - * is room, or above it if there is not. - * @param gravity The {@link Gravity} value for aligning the popup with its anchor + * @param context Context the popup menu is running in, through which it + * can access the current theme, resources, etc. + * @param anchor Anchor view for this popup. The popup will appear below + * the anchor if there is room, or above it if there is not. + * @param gravity The {@link Gravity} value for aligning the popup with its + * anchor. */ public PopupMenu(Context context, View anchor, int gravity) { - // TODO Theme? + this(context, anchor, gravity, R.attr.popupMenuStyle, 0); + } + + /** + * Constructor a create a new popup menu with a specific style. + * + * @param context Context the popup menu is running in, through which it + * can access the current theme, resources, etc. + * @param anchor Anchor view for this popup. The popup will appear below + * the anchor if there is room, or above it if there is not. + * @param gravity The {@link Gravity} value for aligning the popup with its + * anchor. + * @param popupStyleAttr An attribute in the current theme that contains a + * reference to a style resource that supplies default values for + * the popup window. Can be 0 to not look for defaults. + * @param popupStyleRes A resource identifier of a style resource that + * supplies default values for the popup window, used only if + * popupStyleAttr is 0 or can not be found in the theme. Can be 0 + * to not look for defaults. + */ + public PopupMenu(Context context, View anchor, int gravity, int popupStyleAttr, + int popupStyleRes) { mContext = context; mMenu = new MenuBuilder(context); mMenu.setCallback(this); mAnchor = anchor; - mPopup = new MenuPopupHelper(context, mMenu, anchor); + mPopup = new MenuPopupHelper(context, mMenu, anchor, false, popupStyleAttr, popupStyleRes); mPopup.setGravity(gravity); mPopup.setCallback(this); } diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 41d3e320..54a7940 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -97,9 +97,11 @@ public class PopupWindow { private boolean mAllowScrollingAnchorParent = true; private boolean mLayoutInsetDecor = false; private boolean mNotTouchModal; + private boolean mAttachedInDecor = true; + private boolean mAttachedInDecorSet = false; private OnTouchListener mTouchInterceptor; - + private int mWidthMode; private int mWidth; private int mLastWidth; @@ -316,6 +318,7 @@ public class PopupWindow { mContext = contentView.getContext(); mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); } + setContentView(contentView); setWidth(width); setHeight(height); @@ -373,16 +376,16 @@ public class PopupWindow { public int getAnimationStyle() { return mAnimationStyle; } - + /** - * Set the flag on popup to ignore cheek press eventt; by default this flag + * Set the flag on popup to ignore cheek press event; by default this flag * is set to false * which means the pop wont ignore cheek press dispatch events. - * + * * <p>If the popup is showing, calling this method will take effect only * the next time the popup is shown or through a manual call to one of * the {@link #update()} methods.</p> - * + * * @see #update() */ public void setIgnoreCheekPress() { @@ -443,6 +446,19 @@ public class PopupWindow { if (mWindowManager == null && mContentView != null) { mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); } + + // Setting the default for attachedInDecor based on SDK version here + // instead of in the constructor since we might not have the context + // object in the constructor. We only want to set default here if the + // app hasn't already set the attachedInDecor. + if (mContext != null && !mAttachedInDecorSet) { + // Attach popup window in decor frame of parent window by default for + // {@link Build.VERSION_CODES.LOLLIPOP_MR1} or greater. Keep current + // behavior of not attaching to decor frame for older SDKs. + setAttachedInDecor(mContext.getApplicationInfo().targetSdkVersion + >= Build.VERSION_CODES.LOLLIPOP_MR1); + } + } /** @@ -452,7 +468,7 @@ public class PopupWindow { public void setTouchInterceptor(OnTouchListener l) { mTouchInterceptor = l; } - + /** * <p>Indicate whether the popup window can grab the focus.</p> * @@ -702,6 +718,36 @@ public class PopupWindow { } /** + * <p>Indicates whether the popup window will be attached in the decor frame of its parent + * window. + * + * @return true if the window will be attached to the decor frame of its parent window. + * + * @see #setAttachedInDecor(boolean) + * @see WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR + */ + public boolean isAttachedInDecor() { + return mAttachedInDecor; + } + + /** + * <p>This will attach the popup window to the decor frame of the parent window to avoid + * overlaping with screen decorations like the navigation bar. Overrides the default behavior of + * the flag {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR}. + * + * <p>By default the flag is set on SDK version {@link Build.VERSION_CODES#LOLLIPOP_MR1} or + * greater and cleared on lesser SDK versions. + * + * @param enabled true if the popup should be attached to the decor frame of its parent window. + * + * @see WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR + */ + public void setAttachedInDecor(boolean enabled) { + mAttachedInDecor = enabled; + mAttachedInDecorSet = true; + } + + /** * Allows the popup window to force the flag * {@link WindowManager.LayoutParams#FLAG_LAYOUT_INSET_DECOR}, overriding default behavior. * This will cause the popup to inset its content to account for system windows overlaying @@ -1140,9 +1186,12 @@ public class PopupWindow { if (mNotTouchModal) { curFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; } + if (mAttachedInDecor) { + curFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_ATTACHED_IN_DECOR; + } return curFlags; } - + private int computeAnimationResource() { if (mAnimationStyle == -1) { if (mIsDropdown) { diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index e9298c2..1c190c3 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -604,6 +604,7 @@ public class ProgressBar extends View { * @see #getIndeterminateTintList() * @see Drawable#setTintList(ColorStateList) */ + @RemotableViewMethod public void setIndeterminateTintList(@Nullable ColorStateList tint) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); @@ -842,6 +843,7 @@ public class ProgressBar extends View { * @see #getProgressTintList() * @see Drawable#setTintList(ColorStateList) */ + @RemotableViewMethod public void setProgressTintList(@Nullable ColorStateList tint) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); @@ -923,6 +925,7 @@ public class ProgressBar extends View { * @see #getProgressBackgroundTintList() * @see Drawable#setTintList(ColorStateList) */ + @RemotableViewMethod public void setProgressBackgroundTintList(@Nullable ColorStateList tint) { if (mProgressTintInfo == null) { mProgressTintInfo = new ProgressTintInfo(); diff --git a/core/java/android/widget/RadialTimePickerView.java b/core/java/android/widget/RadialTimePickerView.java index 56f126c..24fc2bb 100644 --- a/core/java/android/widget/RadialTimePickerView.java +++ b/core/java/android/widget/RadialTimePickerView.java @@ -22,21 +22,19 @@ import android.animation.Keyframe; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.ValueAnimator; -import android.annotation.SuppressLint; import android.content.Context; -import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; +import android.graphics.Rect; import android.graphics.Typeface; -import android.graphics.RectF; import android.os.Bundle; -import android.text.format.DateUtils; -import android.text.format.Time; import android.util.AttributeSet; +import android.util.IntArray; import android.util.Log; +import android.util.MathUtils; import android.util.TypedValue; import android.view.HapticFeedbackConstants; import android.view.MotionEvent; @@ -44,10 +42,11 @@ import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import com.android.internal.R; +import com.android.internal.widget.ExploreByTouchHelper; -import java.text.DateFormatSymbols; import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; @@ -69,7 +68,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private static final int HOURS = 0; private static final int MINUTES = 1; private static final int HOURS_INNER = 2; - private static final int AMPM = 3; private static final int SELECTOR_CIRCLE = 0; private static final int SELECTOR_DOT = 1; @@ -87,12 +85,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { // Alpha level of color for selector. private static final int ALPHA_SELECTOR = 60; // was 51 - // Alpha level of color for selected circle. - private static final int ALPHA_AMPM_SELECTED = ALPHA_SELECTOR; - - // Alpha level of color for pressed circle. - private static final int ALPHA_AMPM_PRESSED = 255; // was 175 - private static final float COSINE_30_DEGREES = ((float) Math.sqrt(3)) * 0.5f; private static final float SINE_30_DEGREES = 0.5f; @@ -105,17 +97,16 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private static final int CENTER_RADIUS = 2; - private static final int[] STATE_SET_SELECTED = new int[] {R.attr.state_selected}; - private static int[] sSnapPrefer30sMap = new int[361]; + private final InvalidateUpdateListener mInvalidateUpdateListener = + new InvalidateUpdateListener(); + private final String[] mHours12Texts = new String[12]; private final String[] mOuterHours24Texts = new String[12]; private final String[] mInnerHours24Texts = new String[12]; private final String[] mMinutesTexts = new String[12]; - private final String[] mAmPmText = new String[2]; - private final Paint[] mPaint = new Paint[2]; private final int[] mColor = new int[2]; private final IntHolder[] mAlpha = new IntHolder[2]; @@ -126,14 +117,42 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private final int[][] mColorSelector = new int[2][3]; private final IntHolder[][] mAlphaSelector = new IntHolder[2][3]; - private final Paint mPaintAmPmText = new Paint(); - private final Paint[] mPaintAmPmCircle = new Paint[2]; - private final Paint mPaintBackground = new Paint(); - private final Paint mPaintDisabled = new Paint(); private final Paint mPaintDebug = new Paint(); - private Typeface mTypeface; + private final Typeface mTypeface; + + private final float[] mCircleRadius = new float[3]; + + private final float[] mTextSize = new float[2]; + + private final float[][] mTextGridHeights = new float[2][7]; + private final float[][] mTextGridWidths = new float[2][7]; + + private final float[] mInnerTextGridHeights = new float[7]; + private final float[] mInnerTextGridWidths = new float[7]; + + private final float[] mCircleRadiusMultiplier = new float[2]; + private final float[] mNumbersRadiusMultiplier = new float[3]; + + private final float[] mTextSizeMultiplier = new float[3]; + + private final float[] mAnimationRadiusMultiplier = new float[3]; + + private final float mTransitionMidRadiusMultiplier; + private final float mTransitionEndRadiusMultiplier; + + private final int[] mLineLength = new int[3]; + private final int[] mSelectionRadius = new int[3]; + private final float mSelectionRadiusMultiplier; + private final int[] mSelectionDegrees = new int[3]; + + private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<Animator>(); + private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<Animator>(); + + private final RadialPickerTouchHelper mTouchHelper; + + private float mInnerTextSize; private boolean mIs24HourMode; private boolean mShowHours; @@ -147,66 +166,21 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { private int mXCenter; private int mYCenter; - private float[] mCircleRadius = new float[3]; - private int mMinHypotenuseForInnerNumber; private int mMaxHypotenuseForOuterNumber; private int mHalfwayHypotenusePoint; - private float[] mTextSize = new float[2]; - private float mInnerTextSize; - - private float[][] mTextGridHeights = new float[2][7]; - private float[][] mTextGridWidths = new float[2][7]; - - private float[] mInnerTextGridHeights = new float[7]; - private float[] mInnerTextGridWidths = new float[7]; - private String[] mOuterTextHours; private String[] mInnerTextHours; private String[] mOuterTextMinutes; - - private float[] mCircleRadiusMultiplier = new float[2]; - private float[] mNumbersRadiusMultiplier = new float[3]; - - private float[] mTextSizeMultiplier = new float[3]; - - private float[] mAnimationRadiusMultiplier = new float[3]; - - private float mTransitionMidRadiusMultiplier; - private float mTransitionEndRadiusMultiplier; - private AnimatorSet mTransition; - private InvalidateUpdateListener mInvalidateUpdateListener = new InvalidateUpdateListener(); - - private int[] mLineLength = new int[3]; - private int[] mSelectionRadius = new int[3]; - private float mSelectionRadiusMultiplier; - private int[] mSelectionDegrees = new int[3]; - - private int mAmPmCircleRadius; - private float mAmPmYCenter; - - private float mAmPmCircleRadiusMultiplier; - private int mAmPmTextColor; - - private float mLeftIndicatorXCenter; - private float mRightIndicatorXCenter; - - private int mAmPmUnselectedColor; - private int mAmPmSelectedColor; private int mAmOrPm; - private int mAmOrPmPressed; - private int mDisabledAlpha; - private RectF mRectF = new RectF(); - private boolean mInputEnabled = true; private OnValueSelectedListener mListener; - private final ArrayList<Animator> mHoursToMinutesAnims = new ArrayList<Animator>(); - private final ArrayList<Animator> mMinuteToHoursAnims = new ArrayList<Animator>(); + private boolean mInputEnabled = true; public interface OnValueSelectedListener { void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance); @@ -314,11 +288,21 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { return degrees; } + @SuppressWarnings("unused") + public RadialTimePickerView(Context context) { + this(context, null); + } + public RadialTimePickerView(Context context, AttributeSet attrs) { this(context, attrs, R.attr.timePickerStyle); } - public RadialTimePickerView(Context context, AttributeSet attrs, int defStyle) { + public RadialTimePickerView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } + + public RadialTimePickerView( + Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs); // Pull disabled alpha from theme. @@ -329,28 +313,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { // process style attributes final Resources res = getResources(); final TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TimePicker, - defStyle, 0); - - ColorStateList amPmBackgroundColor = a.getColorStateList( - R.styleable.TimePicker_amPmBackgroundColor); - if (amPmBackgroundColor == null) { - amPmBackgroundColor = res.getColorStateList( - R.color.timepicker_default_ampm_unselected_background_color_material); - } - - // Obtain the backup selected color. If the background color state - // list doesn't have a state for selected, we'll use this color. - final int amPmSelectedColor = a.getColor(R.styleable.TimePicker_amPmSelectedBackgroundColor, - res.getColor(R.color.timepicker_default_ampm_selected_background_color_material)); - amPmBackgroundColor = ColorStateList.addFirstIfMissing( - amPmBackgroundColor, R.attr.state_selected, amPmSelectedColor); - - mAmPmSelectedColor = amPmBackgroundColor.getColorForState( - STATE_SET_SELECTED, amPmSelectedColor); - mAmPmUnselectedColor = amPmBackgroundColor.getDefaultColor(); - - mAmPmTextColor = a.getColor(R.styleable.TimePicker_amPmTextColor, - res.getColor(R.color.timepicker_default_text_color_material)); + defStyleAttr, defStyleRes); mTypeface = Typeface.create("sans-serif", Typeface.NORMAL); @@ -419,16 +382,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { R.styleable.TimePicker_numbersSelectorColor, R.color.timepicker_default_selector_color_material); - mPaintAmPmText.setColor(mAmPmTextColor); - mPaintAmPmText.setTypeface(mTypeface); - mPaintAmPmText.setAntiAlias(true); - mPaintAmPmText.setTextAlign(Paint.Align.CENTER); - - mPaintAmPmCircle[AM] = new Paint(); - mPaintAmPmCircle[AM].setAntiAlias(true); - mPaintAmPmCircle[PM] = new Paint(); - mPaintAmPmCircle[PM].setAntiAlias(true); - mPaintBackground.setColor(a.getColor(R.styleable.TimePicker_numbersBackgroundColor, res.getColor(R.color.timepicker_default_numbers_background_color_material))); mPaintBackground.setAntiAlias(true); @@ -444,7 +397,14 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mShowHours = true; mIs24HourMode = false; mAmOrPm = AM; - mAmOrPmPressed = -1; + + // Set up accessibility components. + mTouchHelper = new RadialPickerTouchHelper(); + setAccessibilityDelegate(mTouchHelper); + + if (getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + } initHoursAndMinutesText(); initData(); @@ -470,8 +430,8 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { final int currentHour = calendar.get(Calendar.HOUR_OF_DAY); final int currentMinute = calendar.get(Calendar.MINUTE); - setCurrentHour(currentHour); - setCurrentMinute(currentMinute); + setCurrentHourInternal(currentHour, false, false); + setCurrentMinuteInternal(currentMinute, false); setHapticFeedbackEnabled(true); } @@ -493,8 +453,9 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { public void initialize(int hour, int minute, boolean is24HourMode) { mIs24HourMode = is24HourMode; - setCurrentHour(hour); - setCurrentMinute(minute); + + setCurrentHourInternal(hour, false, false); + setCurrentMinuteInternal(minute, false); } public void setCurrentItemShowing(int item, boolean animate) { @@ -524,23 +485,39 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { * @param hour the current hour between 0 and 23 (inclusive) */ public void setCurrentHour(int hour) { + setCurrentHourInternal(hour, true, false); + } + + /** + * Sets the current hour. + * + * @param hour The current hour + * @param callback Whether the value listener should be invoked + * @param autoAdvance Whether the listener should auto-advance to the next + * selection mode, e.g. hour to minutes + */ + private void setCurrentHourInternal(int hour, boolean callback, boolean autoAdvance) { final int degrees = (hour % 12) * DEGREES_FOR_ONE_HOUR; mSelectionDegrees[HOURS] = degrees; mSelectionDegrees[HOURS_INNER] = degrees; // 0 is 12 AM (midnight) and 12 is 12 PM (noon). - mAmOrPm = (hour == 0 || (hour % 24) < 12) ? AM : PM; - - if (mIs24HourMode) { - // Inner circle is 1 through 12. - mIsOnInnerCircle = hour >= 1 && hour <= 12; - } else { - mIsOnInnerCircle = false; + final int amOrPm = (hour == 0 || (hour % 24) < 12) ? AM : PM; + final boolean isOnInnerCircle = mIs24HourMode && hour >= 1 && hour <= 12; + if (mAmOrPm != amOrPm || mIsOnInnerCircle != isOnInnerCircle) { + mAmOrPm = amOrPm; + mIsOnInnerCircle = isOnInnerCircle; + + initData(); + updateLayoutData(); + mTouchHelper.invalidateRoot(); } - initData(); - updateLayoutData(); invalidate(); + + if (callback && mListener != null) { + mListener.onValueSelected(HOURS, hour, autoAdvance); + } } /** @@ -549,15 +526,19 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { * @return the current hour between 0 and 23 (inclusive) */ public int getCurrentHour() { - int hour = (mSelectionDegrees[mIsOnInnerCircle ? - HOURS_INNER : HOURS] / DEGREES_FOR_ONE_HOUR) % 12; + return getHourForDegrees( + mSelectionDegrees[mIsOnInnerCircle ? HOURS_INNER : HOURS], mIsOnInnerCircle); + } + + private int getHourForDegrees(int degrees, boolean innerCircle) { + int hour = (degrees / DEGREES_FOR_ONE_HOUR) % 12; if (mIs24HourMode) { // Convert the 12-hour value into 24-hour time based on where the // selector is positioned. - if (mIsOnInnerCircle && hour == 0) { + if (innerCircle && hour == 0) { // Inner circle is 1 through 12. hour = 12; - } else if (!mIsOnInnerCircle && hour != 0) { + } else if (!innerCircle && hour != 0) { // Outer circle is 13 through 23 and 0. hour += 12; } @@ -567,30 +548,55 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { return hour; } + private int getDegreesForHour(int hour) { + // Convert to be 0-11. + if (mIs24HourMode) { + if (hour >= 12) { + hour -= 12; + } + } else if (hour == 12) { + hour = 0; + } + return hour * DEGREES_FOR_ONE_HOUR; + } + public void setCurrentMinute(int minute) { + setCurrentMinuteInternal(minute, true); + } + + private void setCurrentMinuteInternal(int minute, boolean callback) { mSelectionDegrees[MINUTES] = (minute % 60) * DEGREES_FOR_ONE_MINUTE; + invalidate(); + + if (callback && mListener != null) { + mListener.onValueSelected(MINUTES, minute, false); + } } // Returns minutes in 0-59 range public int getCurrentMinute() { - return (mSelectionDegrees[MINUTES] / DEGREES_FOR_ONE_MINUTE); + return getMinuteForDegrees(mSelectionDegrees[MINUTES]); + } + + private int getMinuteForDegrees(int degrees) { + return degrees / DEGREES_FOR_ONE_MINUTE; + } + + private int getDegreesForMinute(int minute) { + return minute * DEGREES_FOR_ONE_MINUTE; } public void setAmOrPm(int val) { mAmOrPm = (val % 2); invalidate(); + mTouchHelper.invalidateRoot(); } public int getAmOrPm() { return mAmOrPm; } - public void swapAmPm() { - mAmOrPm = (mAmOrPm == AM) ? PM : AM; - invalidate(); - } - public void showHours(boolean animate) { if (mShowHours) return; mShowHours = true; @@ -621,10 +627,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mInnerHours24Texts[i] = String.format("%d", HOURS_NUMBERS[i]); mMinutesTexts[i] = String.format("%02d", MINUTES_NUMBERS[i]); } - - String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(mContext); - mAmPmText[AM] = amPmStrings[0]; - mAmPmText[PM] = amPmStrings[1]; } private void initData() { @@ -674,9 +676,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mAnimationRadiusMultiplier[HOURS_INNER] = 1; mAnimationRadiusMultiplier[MINUTES] = 1; - mAmPmCircleRadiusMultiplier = Float.parseFloat( - res.getString(R.string.timepicker_ampm_circle_radius_multiplier)); - mAlpha[HOURS].setValue(mShowHours ? ALPHA_OPAQUE : ALPHA_TRANSPARENT); mAlpha[MINUTES].setValue(mShowHours ? ALPHA_TRANSPARENT : ALPHA_OPAQUE); @@ -710,14 +709,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mCircleRadius[HOURS_INNER] = min * mCircleRadiusMultiplier[HOURS]; mCircleRadius[MINUTES] = min * mCircleRadiusMultiplier[MINUTES]; - if (!mIs24HourMode) { - // We'll need to draw the AM/PM circles, so the main circle will need to have - // a slightly higher center. To keep the entire view centered vertically, we'll - // have to push it up by half the radius of the AM/PM circles. - int amPmCircleRadius = (int) (mCircleRadius[HOURS] * mAmPmCircleRadiusMultiplier); - mYCenter -= amPmCircleRadius / 2; - } - mMinHypotenuseForInnerNumber = (int) (mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS_INNER]) - mSelectionRadius[HOURS]; mMaxHypotenuseForOuterNumber = (int) (mCircleRadius[HOURS] @@ -739,16 +730,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mSelectionRadius[HOURS_INNER] = mSelectionRadius[HOURS]; mSelectionRadius[MINUTES] = (int) (mCircleRadius[MINUTES] * mSelectionRadiusMultiplier); - mAmPmCircleRadius = (int) (mCircleRadius[HOURS] * mAmPmCircleRadiusMultiplier); - mPaintAmPmText.setTextSize(mAmPmCircleRadius * 3 / 4); - - // Line up the vertical center of the AM/PM circles with the bottom of the main circle. - mAmPmYCenter = mYCenter + mCircleRadius[HOURS]; - - // Line up the horizontal edges of the AM/PM circles with the horizontal edges - // of the main circle - mLeftIndicatorXCenter = mXCenter - mCircleRadius[HOURS] + mAmPmCircleRadius; - mRightIndicatorXCenter = mXCenter + mCircleRadius[HOURS] - mAmPmCircleRadius; + mTouchHelper.invalidateRoot(); } @Override @@ -780,9 +762,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { mColor[MINUTES], mAlpha[MINUTES].getValue()); drawCenter(canvas); - if (!mIs24HourMode) { - drawAmPm(canvas); - } if (DEBUG) { drawDebug(canvas); @@ -804,50 +783,6 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { drawSelector(canvas, MINUTES); } - private void drawAmPm(Canvas canvas) { - final boolean isLayoutRtl = isLayoutRtl(); - - int amColor = mAmPmUnselectedColor; - int amAlpha = ALPHA_OPAQUE; - int pmColor = mAmPmUnselectedColor; - int pmAlpha = ALPHA_OPAQUE; - if (mAmOrPm == AM) { - amColor = mAmPmSelectedColor; - amAlpha = ALPHA_AMPM_SELECTED; - } else if (mAmOrPm == PM) { - pmColor = mAmPmSelectedColor; - pmAlpha = ALPHA_AMPM_SELECTED; - } - if (mAmOrPmPressed == AM) { - amColor = mAmPmSelectedColor; - amAlpha = ALPHA_AMPM_PRESSED; - } else if (mAmOrPmPressed == PM) { - pmColor = mAmPmSelectedColor; - pmAlpha = ALPHA_AMPM_PRESSED; - } - - // Draw the two circles - mPaintAmPmCircle[AM].setColor(amColor); - mPaintAmPmCircle[AM].setAlpha(getMultipliedAlpha(amColor, amAlpha)); - canvas.drawCircle(isLayoutRtl ? mRightIndicatorXCenter : mLeftIndicatorXCenter, - mAmPmYCenter, mAmPmCircleRadius, mPaintAmPmCircle[AM]); - - mPaintAmPmCircle[PM].setColor(pmColor); - mPaintAmPmCircle[PM].setAlpha(getMultipliedAlpha(pmColor, pmAlpha)); - canvas.drawCircle(isLayoutRtl ? mLeftIndicatorXCenter : mRightIndicatorXCenter, - mAmPmYCenter, mAmPmCircleRadius, mPaintAmPmCircle[PM]); - - // Draw the AM/PM texts on top - mPaintAmPmText.setColor(mAmPmTextColor); - float textYCenter = mAmPmYCenter - - (int) (mPaintAmPmText.descent() + mPaintAmPmText.ascent()) / 2; - - canvas.drawText(isLayoutRtl ? mAmPmText[PM] : mAmPmText[AM], mLeftIndicatorXCenter, - textYCenter, mPaintAmPmText); - canvas.drawText(isLayoutRtl ? mAmPmText[AM] : mAmPmText[PM], mRightIndicatorXCenter, - textYCenter, mPaintAmPmText); - } - private int getMultipliedAlpha(int argb, int alpha) { return (int) (Color.alpha(argb) * (alpha / 255.0) + 0.5); } @@ -917,20 +852,17 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { float top = mYCenter - outerRadius; float right = mXCenter + outerRadius; float bottom = mYCenter + outerRadius; - mRectF = new RectF(left, top, right, bottom); - canvas.drawRect(mRectF, mPaintDebug); + canvas.drawRect(left, top, right, bottom, mPaintDebug); // Draw outer rectangle for background left = mXCenter - mCircleRadius[HOURS]; top = mYCenter - mCircleRadius[HOURS]; right = mXCenter + mCircleRadius[HOURS]; bottom = mYCenter + mCircleRadius[HOURS]; - mRectF.set(left, top, right, bottom); - canvas.drawRect(mRectF, mPaintDebug); + canvas.drawRect(left, top, right, bottom, mPaintDebug); // Draw outer view rectangle - mRectF.set(0, 0, getWidth(), getHeight()); - canvas.drawRect(mRectF, mPaintDebug); + canvas.drawRect(0, 0, getWidth(), getHeight(), mPaintDebug); // Draw selected time final String selected = String.format("%02d:%02d", getCurrentHour(), getCurrentMinute()); @@ -950,7 +882,7 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { float x = mXCenter - width / 2; float y = mYCenter + 1.5f * height; - canvas.drawText(selected.toString(), x, y, paint); + canvas.drawText(selected, x, y, paint); } private void calculateGridSizesHours() { @@ -1044,12 +976,14 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { } // Used for animating the hours by changing their radius + @SuppressWarnings("unused") private void setAnimationRadiusMultiplierHours(float animationRadiusMultiplier) { mAnimationRadiusMultiplier[HOURS] = animationRadiusMultiplier; mAnimationRadiusMultiplier[HOURS_INNER] = animationRadiusMultiplier; } // Used for animating the minutes by changing their radius + @SuppressWarnings("unused") private void setAnimationRadiusMultiplierMinutes(float animationRadiusMultiplier) { mAnimationRadiusMultiplier[MINUTES] = animationRadiusMultiplier; } @@ -1242,41 +1176,25 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { } final float opposite = Math.abs(y - mYCenter); - double degrees = Math.toDegrees(Math.asin(opposite / hypotenuse)); + int degrees = (int) (Math.toDegrees(Math.asin(opposite / hypotenuse)) + 0.5); // Now we have to translate to the correct quadrant. - boolean rightSide = (x > mXCenter); - boolean topSide = (y < mYCenter); - if (rightSide && topSide) { - degrees = 90 - degrees; - } else if (rightSide && !topSide) { - degrees = 90 + degrees; - } else if (!rightSide && !topSide) { - degrees = 270 - degrees; - } else if (!rightSide && topSide) { - degrees = 270 + degrees; - } - return (int) degrees; - } - - private int getIsTouchingAmOrPm(float x, float y) { - final boolean isLayoutRtl = isLayoutRtl(); - int squaredYDistance = (int) ((y - mAmPmYCenter) * (y - mAmPmYCenter)); - - int distanceToAmCenter = (int) Math.sqrt( - (x - mLeftIndicatorXCenter) * (x - mLeftIndicatorXCenter) + squaredYDistance); - if (distanceToAmCenter <= mAmPmCircleRadius) { - return (isLayoutRtl ? PM : AM); - } - - int distanceToPmCenter = (int) Math.sqrt( - (x - mRightIndicatorXCenter) * (x - mRightIndicatorXCenter) + squaredYDistance); - if (distanceToPmCenter <= mAmPmCircleRadius) { - return (isLayoutRtl ? AM : PM); + final boolean rightSide = (x > mXCenter); + final boolean topSide = (y < mYCenter); + if (rightSide) { + if (topSide) { + degrees = 90 - degrees; + } else { + degrees = 90 + degrees; + } + } else { + if (topSide) { + degrees = 270 + degrees; + } else { + degrees = 270 - degrees; + } } - - // Neither was close enough. - return -1; + return degrees; } @Override @@ -1295,181 +1213,326 @@ public class RadialTimePickerView extends View implements View.OnTouchListener { switch(event.getAction()) { case MotionEvent.ACTION_DOWN: case MotionEvent.ACTION_MOVE: - mAmOrPmPressed = getIsTouchingAmOrPm(eventX, eventY); - if (mAmOrPmPressed != -1) { - result = true; - } else { - degrees = getDegreesFromXY(eventX, eventY); - if (degrees != -1) { - snapDegrees = (mShowHours ? - snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; + degrees = getDegreesFromXY(eventX, eventY); + if (degrees != -1) { + snapDegrees = (mShowHours ? + snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; + if (mShowHours) { + mSelectionDegrees[HOURS] = snapDegrees; + mSelectionDegrees[HOURS_INNER] = snapDegrees; + } else { + mSelectionDegrees[MINUTES] = snapDegrees; + } + performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); + if (mListener != null) { if (mShowHours) { - mSelectionDegrees[HOURS] = snapDegrees; - mSelectionDegrees[HOURS_INNER] = snapDegrees; - } else { - mSelectionDegrees[MINUTES] = snapDegrees; - } - performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); - if (mListener != null) { - if (mShowHours) { - mListener.onValueSelected(HOURS, getCurrentHour(), false); - } else { - mListener.onValueSelected(MINUTES, getCurrentMinute(), false); - } + mListener.onValueSelected(HOURS, getCurrentHour(), false); + } else { + mListener.onValueSelected(MINUTES, getCurrentMinute(), false); } - result = true; } + result = true; + invalidate(); } - invalidate(); - return result; + break; case MotionEvent.ACTION_UP: - mAmOrPmPressed = getIsTouchingAmOrPm(eventX, eventY); - if (mAmOrPmPressed != -1) { - if (mAmOrPm != mAmOrPmPressed) { - swapAmPm(); + degrees = getDegreesFromXY(eventX, eventY); + if (degrees != -1) { + snapDegrees = (mShowHours ? + snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; + if (mShowHours) { + mSelectionDegrees[HOURS] = snapDegrees; + mSelectionDegrees[HOURS_INNER] = snapDegrees; + } else { + mSelectionDegrees[MINUTES] = snapDegrees; } - mAmOrPmPressed = -1; if (mListener != null) { - mListener.onValueSelected(AMPM, getCurrentHour(), true); - } - result = true; - } else { - degrees = getDegreesFromXY(eventX, eventY); - if (degrees != -1) { - snapDegrees = (mShowHours ? - snapOnly30s(degrees, 0) : snapPrefer30s(degrees)) % 360; if (mShowHours) { - mSelectionDegrees[HOURS] = snapDegrees; - mSelectionDegrees[HOURS_INNER] = snapDegrees; - } else { - mSelectionDegrees[MINUTES] = snapDegrees; + mListener.onValueSelected(HOURS, getCurrentHour(), true); + } else { + mListener.onValueSelected(MINUTES, getCurrentMinute(), true); } - if (mListener != null) { - if (mShowHours) { - mListener.onValueSelected(HOURS, getCurrentHour(), true); - } else { - mListener.onValueSelected(MINUTES, getCurrentMinute(), true); - } - } - result = true; } - } - if (result) { invalidate(); + result = true; } - return result; - - default: break; } - return false; + return result; } - /** - * Necessary for accessibility, to ensure we support "scrolling" forward and backward - * in the circle. - */ - @Override - public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(info); - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); - } - - /** - * Announce the currently-selected time when launched. - */ @Override - public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) { - if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) { - // Clear the event's current text so that only the current time will be spoken. - event.getText().clear(); - Time time = new Time(); - time.hour = getCurrentHour(); - time.minute = getCurrentMinute(); - long millis = time.normalize(true); - int flags = DateUtils.FORMAT_SHOW_TIME; - if (mIs24HourMode) { - flags |= DateUtils.FORMAT_24HOUR; - } - String timeString = DateUtils.formatDateTime(getContext(), millis, flags); - event.getText().add(timeString); + public boolean dispatchHoverEvent(MotionEvent event) { + // First right-of-refusal goes the touch exploration helper. + if (mTouchHelper.dispatchHoverEvent(event)) { return true; } - return super.dispatchPopulateAccessibilityEvent(event); + return super.dispatchHoverEvent(event); } - /** - * When scroll forward/backward events are received, jump the time to the higher/lower - * discrete, visible value on the circle. - */ - @SuppressLint("NewApi") - @Override - public boolean performAccessibilityAction(int action, Bundle arguments) { - if (super.performAccessibilityAction(action, arguments)) { - return true; + public void setInputEnabled(boolean inputEnabled) { + mInputEnabled = inputEnabled; + invalidate(); + } + + private class RadialPickerTouchHelper extends ExploreByTouchHelper { + private final Rect mTempRect = new Rect(); + + private final int TYPE_HOUR = 1; + private final int TYPE_MINUTE = 2; + + private final int SHIFT_TYPE = 0; + private final int MASK_TYPE = 0xF; + + private final int SHIFT_VALUE = 8; + private final int MASK_VALUE = 0xFF; + + /** Increment in which virtual views are exposed for minutes. */ + private final int MINUTE_INCREMENT = 5; + + public RadialPickerTouchHelper() { + super(RadialTimePickerView.this); } - int changeMultiplier = 0; - if (action == AccessibilityNodeInfo.ACTION_SCROLL_FORWARD) { - changeMultiplier = 1; - } else if (action == AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD) { - changeMultiplier = -1; + @Override + public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(host, info); + + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); + info.addAction(AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); } - if (changeMultiplier != 0) { - int value = 0; - int stepSize = 0; - if (mShowHours) { - stepSize = DEGREES_FOR_ONE_HOUR; - value = getCurrentHour() % 12; - } else { - stepSize = DEGREES_FOR_ONE_MINUTE; - value = getCurrentMinute(); + + @Override + public boolean performAccessibilityAction(View host, int action, Bundle arguments) { + if (super.performAccessibilityAction(host, action, arguments)) { + return true; + } + + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: + adjustPicker(1); + return true; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: + adjustPicker(-1); + return true; } - int degrees = value * stepSize; - degrees = snapOnly30s(degrees, changeMultiplier); - value = degrees / stepSize; - int maxValue = 0; - int minValue = 0; + return false; + } + + private void adjustPicker(int step) { + final int stepSize; + final int initialValue; + final int maxValue; + final int minValue; if (mShowHours) { + stepSize = DEGREES_FOR_ONE_HOUR; + initialValue = getCurrentHour() % 12; + if (mIs24HourMode) { maxValue = 23; + minValue = 0; } else { maxValue = 12; minValue = 1; } } else { + stepSize = DEGREES_FOR_ONE_MINUTE; + initialValue = getCurrentMinute(); + maxValue = 55; + minValue = 0; } - if (value > maxValue) { - // If we scrolled forward past the highest number, wrap around to the lowest. - value = minValue; - } else if (value < minValue) { - // If we scrolled backward past the lowest number, wrap around to the highest. - value = maxValue; + + final int steppedValue = snapOnly30s(initialValue * stepSize, step) / stepSize; + final int clampedValue = MathUtils.constrain(steppedValue, minValue, maxValue); + if (mShowHours) { + setCurrentHour(clampedValue); + } else { + setCurrentMinute(clampedValue); } + } + + @Override + protected int getVirtualViewAt(float x, float y) { + final int id; + final int degrees = getDegreesFromXY(x, y); + if (degrees != -1) { + final int snapDegrees = snapOnly30s(degrees, 0) % 360; + if (mShowHours) { + final int hour = getHourForDegrees(snapDegrees, mIsOnInnerCircle); + id = makeId(TYPE_HOUR, hour); + } else { + final int current = getCurrentMinute(); + final int touched = getMinuteForDegrees(degrees); + final int snapped = getMinuteForDegrees(snapDegrees); + + // If the touched minute is closer to the current minute + // than it is to the snapped minute, return current. + final int minute; + if (Math.abs(current - touched) < Math.abs(snapped - touched)) { + minute = current; + } else { + minute = snapped; + } + id = makeId(TYPE_MINUTE, minute); + } + } else { + id = INVALID_ID; + } + + return id; + } + + @Override + protected void getVisibleVirtualViews(IntArray virtualViewIds) { if (mShowHours) { - setCurrentHour(value); - if (mListener != null) { - mListener.onValueSelected(HOURS, value, false); + final int min = mIs24HourMode ? 0 : 1; + final int max = mIs24HourMode ? 23 : 12; + for (int i = min; i <= max ; i++) { + virtualViewIds.add(makeId(TYPE_HOUR, i)); } } else { - setCurrentMinute(value); - if (mListener != null) { - mListener.onValueSelected(MINUTES, value, false); + final int current = getCurrentMinute(); + for (int i = 0; i < 60; i += MINUTE_INCREMENT) { + virtualViewIds.add(makeId(TYPE_MINUTE, i)); + + // If the current minute falls between two increments, + // insert an extra node for it. + if (current > i && current < i + MINUTE_INCREMENT) { + virtualViewIds.add(makeId(TYPE_MINUTE, current)); + } } } - return true; } - return false; - } + @Override + protected void onPopulateEventForVirtualView(int virtualViewId, AccessibilityEvent event) { + event.setClassName(getClass().getName()); - public void setInputEnabled(boolean inputEnabled) { - mInputEnabled = inputEnabled; - invalidate(); + final int type = getTypeFromId(virtualViewId); + final int value = getValueFromId(virtualViewId); + final CharSequence description = getVirtualViewDescription(type, value); + event.setContentDescription(description); + } + + @Override + protected void onPopulateNodeForVirtualView(int virtualViewId, AccessibilityNodeInfo node) { + node.setClassName(getClass().getName()); + node.addAction(AccessibilityAction.ACTION_CLICK); + + final int type = getTypeFromId(virtualViewId); + final int value = getValueFromId(virtualViewId); + final CharSequence description = getVirtualViewDescription(type, value); + node.setContentDescription(description); + + getBoundsForVirtualView(virtualViewId, mTempRect); + node.setBoundsInParent(mTempRect); + + final boolean selected = isVirtualViewSelected(type, value); + node.setSelected(selected); + } + + @Override + protected boolean onPerformActionForVirtualView(int virtualViewId, int action, + Bundle arguments) { + if (action == AccessibilityNodeInfo.ACTION_CLICK) { + final int type = getTypeFromId(virtualViewId); + final int value = getValueFromId(virtualViewId); + if (type == TYPE_HOUR) { + final int hour = mIs24HourMode ? value : hour12To24(value, mAmOrPm); + setCurrentHour(hour); + return true; + } else if (type == TYPE_MINUTE) { + setCurrentMinute(value); + return true; + } + } + return false; + } + + private int hour12To24(int hour12, int amOrPm) { + int hour24 = hour12; + if (hour12 == 12) { + if (amOrPm == AM) { + hour24 = 0; + } + } else if (amOrPm == PM) { + hour24 += 12; + } + return hour24; + } + + private void getBoundsForVirtualView(int virtualViewId, Rect bounds) { + final float radius; + final int type = getTypeFromId(virtualViewId); + final int value = getValueFromId(virtualViewId); + final float centerRadius; + final float degrees; + if (type == TYPE_HOUR) { + final boolean innerCircle = mIs24HourMode && value > 0 && value <= 12; + if (innerCircle) { + centerRadius = mCircleRadius[HOURS_INNER] * mNumbersRadiusMultiplier[HOURS_INNER]; + radius = mSelectionRadius[HOURS_INNER]; + } else { + centerRadius = mCircleRadius[HOURS] * mNumbersRadiusMultiplier[HOURS]; + radius = mSelectionRadius[HOURS]; + } + + degrees = getDegreesForHour(value); + } else if (type == TYPE_MINUTE) { + centerRadius = mCircleRadius[MINUTES] * mNumbersRadiusMultiplier[MINUTES]; + degrees = getDegreesForMinute(value); + radius = mSelectionRadius[MINUTES]; + } else { + // This should never happen. + centerRadius = 0; + degrees = 0; + radius = 0; + } + + final double radians = Math.toRadians(degrees); + final float xCenter = mXCenter + centerRadius * (float) Math.sin(radians); + final float yCenter = mYCenter - centerRadius * (float) Math.cos(radians); + + bounds.set((int) (xCenter - radius), (int) (yCenter - radius), + (int) (xCenter + radius), (int) (yCenter + radius)); + } + + private CharSequence getVirtualViewDescription(int type, int value) { + final CharSequence description; + if (type == TYPE_HOUR || type == TYPE_MINUTE) { + description = Integer.toString(value); + } else { + description = null; + } + return description; + } + + private boolean isVirtualViewSelected(int type, int value) { + final boolean selected; + if (type == TYPE_HOUR) { + selected = getCurrentHour() == value; + } else if (type == TYPE_MINUTE) { + selected = getCurrentMinute() == value; + } else { + selected = false; + } + return selected; + } + + private int makeId(int type, int value) { + return type << SHIFT_TYPE | value << SHIFT_VALUE; + } + + private int getTypeFromId(int id) { + return id >>> SHIFT_TYPE & MASK_TYPE; + } + + private int getValueFromId(int id) { + return id >>> SHIFT_VALUE & MASK_VALUE; + } } private static class IntHolder { diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java index 7cb3c37..80f364b 100644 --- a/core/java/android/widget/RemoteViews.java +++ b/core/java/android/widget/RemoteViews.java @@ -27,6 +27,7 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager.NameNotFoundException; +import android.content.res.ColorStateList; import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; @@ -1069,6 +1070,7 @@ public class RemoteViews implements Parcelable, Filter { static final int BITMAP = 12; static final int BUNDLE = 13; static final int INTENT = 14; + static final int COLOR_STATE_LIST = 15; String methodName; int type; @@ -1142,6 +1144,11 @@ public class RemoteViews implements Parcelable, Filter { this.value = Intent.CREATOR.createFromParcel(in); } break; + case COLOR_STATE_LIST: + if (in.readInt() != 0) { + this.value = ColorStateList.CREATOR.createFromParcel(in); + } + break; default: break; } @@ -1212,6 +1219,11 @@ public class RemoteViews implements Parcelable, Filter { ((Intent)this.value).writeToParcel(out, flags); } break; + case COLOR_STATE_LIST: + out.writeInt(this.value != null ? 1 : 0); + if (this.value != null) { + ((ColorStateList)this.value).writeToParcel(out, flags); + } default: break; } @@ -1247,6 +1259,8 @@ public class RemoteViews implements Parcelable, Filter { return Bundle.class; case INTENT: return Intent.class; + case COLOR_STATE_LIST: + return ColorStateList.class; default: return null; } @@ -2207,6 +2221,42 @@ public class RemoteViews implements Parcelable, Filter { } /** + * @hide + * Equivalent to calling {@link android.widget.ProgressBar#setProgressTintList}. + * + * @param viewId The id of the view whose tint should change + * @param tint the tint to apply, may be {@code null} to clear tint + */ + public void setProgressTintList(int viewId, ColorStateList tint) { + addAction(new ReflectionAction(viewId, "setProgressTintList", + ReflectionAction.COLOR_STATE_LIST, tint)); + } + + /** + * @hide + * Equivalent to calling {@link android.widget.ProgressBar#setProgressBackgroundTintList}. + * + * @param viewId The id of the view whose tint should change + * @param tint the tint to apply, may be {@code null} to clear tint + */ + public void setProgressBackgroundTintList(int viewId, ColorStateList tint) { + addAction(new ReflectionAction(viewId, "setProgressBackgroundTintList", + ReflectionAction.COLOR_STATE_LIST, tint)); + } + + /** + * @hide + * Equivalent to calling {@link android.widget.ProgressBar#setIndeterminateTintList}. + * + * @param viewId The id of the view whose tint should change + * @param tint the tint to apply, may be {@code null} to clear tint + */ + public void setProgressIndeterminateTintList(int viewId, ColorStateList tint) { + addAction(new ReflectionAction(viewId, "setIndeterminateTintList", + ReflectionAction.COLOR_STATE_LIST, tint)); + } + + /** * Equivalent to calling {@link android.widget.TextView#setTextColor(int)}. * * @param viewId The id of the view whose text color should change diff --git a/core/java/android/widget/SimpleMonthAdapter.java b/core/java/android/widget/SimpleMonthAdapter.java index 3bad235..5aa78c8 100644 --- a/core/java/android/widget/SimpleMonthAdapter.java +++ b/core/java/android/widget/SimpleMonthAdapter.java @@ -28,21 +28,30 @@ import java.util.HashMap; * An adapter for a list of {@link android.widget.SimpleMonthView} items. */ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayClickListener { - private static final String TAG = "SimpleMonthAdapter"; + private final Calendar mMinDate = Calendar.getInstance(); + private final Calendar mMaxDate = Calendar.getInstance(); private final Context mContext; private final DatePickerController mController; - private Calendar mSelectedDay; + private Calendar mSelectedDay; private ColorStateList mCalendarTextColors; public SimpleMonthAdapter(Context context, DatePickerController controller) { mContext = context; mController = controller; + init(); setSelectedDay(mController.getSelectedDay()); } + public void setRange(Calendar min, Calendar max) { + mMinDate.setTimeInMillis(min.getTimeInMillis()); + mMaxDate.setTimeInMillis(max.getTimeInMillis()); + + notifyDataSetInvalidated(); + } + /** * Updates the selected day and related parameters. * @@ -68,10 +77,9 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli @Override public int getCount() { - final int diffYear = mController.getMaxYear() - mController.getMinYear(); - final int diffMonth = 1 + mController.getMaxMonth() - mController.getMinMonth() - + 12 * diffYear; - return diffMonth; + final int diffYear = mMaxDate.get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR); + final int diffMonth = mMaxDate.get(Calendar.MONTH) - mMinDate.get(Calendar.MONTH); + return diffMonth + 12 * diffYear + 1; } @Override @@ -92,36 +100,34 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli @SuppressWarnings("unchecked") @Override public View getView(int position, View convertView, ViewGroup parent) { - SimpleMonthView v; - HashMap<String, Integer> drawingParams = null; + final SimpleMonthView v; if (convertView != null) { v = (SimpleMonthView) convertView; - // We store the drawing parameters in the view so it can be recycled - drawingParams = (HashMap<String, Integer>) v.getTag(); } else { v = new SimpleMonthView(mContext); + // Set up the new view - AbsListView.LayoutParams params = new AbsListView.LayoutParams( + final AbsListView.LayoutParams params = new AbsListView.LayoutParams( AbsListView.LayoutParams.MATCH_PARENT, AbsListView.LayoutParams.MATCH_PARENT); v.setLayoutParams(params); v.setClickable(true); v.setOnDayClickListener(this); + if (mCalendarTextColors != null) { v.setTextColor(mCalendarTextColors); } } - if (drawingParams == null) { - drawingParams = new HashMap<String, Integer>(); - } else { - drawingParams.clear(); - } - final int currentMonth = position + mController.getMinMonth(); - final int month = currentMonth % 12; - final int year = currentMonth / 12 + mController.getMinYear(); - int selectedDay = -1; + final int minMonth = mMinDate.get(Calendar.MONTH); + final int minYear = mMinDate.get(Calendar.YEAR); + final int currentMonth = position + minMonth; + final int month = currentMonth % 12; + final int year = currentMonth / 12 + minYear; + final int selectedDay; if (isSelectedDayInMonth(year, month)) { selectedDay = mSelectedDay.get(Calendar.DAY_OF_MONTH); + } else { + selectedDay = -1; } // Invokes requestLayout() to ensure that the recycled view is set with the appropriate @@ -129,15 +135,15 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli v.reuse(); final int enabledDayRangeStart; - if (mController.getMinMonth() == month && mController.getMinYear() == year) { - enabledDayRangeStart = mController.getMinDay(); + if (minMonth == month && minYear == year) { + enabledDayRangeStart = mMinDate.get(Calendar.DAY_OF_MONTH); } else { enabledDayRangeStart = 1; } final int enabledDayRangeEnd; - if (mController.getMaxMonth() == month && mController.getMaxYear() == year) { - enabledDayRangeEnd = mController.getMaxDay(); + if (mMaxDate.get(Calendar.MONTH) == month && mMaxDate.get(Calendar.YEAR) == year) { + enabledDayRangeEnd = mMaxDate.get(Calendar.DAY_OF_MONTH); } else { enabledDayRangeEnd = 31; } @@ -155,20 +161,25 @@ class SimpleMonthAdapter extends BaseAdapter implements SimpleMonthView.OnDayCli @Override public void onDayClick(SimpleMonthView view, Calendar day) { - if (day != null) { - onDayTapped(day); + if (day != null && isCalendarInRange(day)) { + onDaySelected(day); } } + private boolean isCalendarInRange(Calendar value) { + return value.compareTo(mMinDate) >= 0 && value.compareTo(mMaxDate) <= 0; + } + /** * Maintains the same hour/min/sec but moves the day to the tapped day. * * @param day The day that was tapped */ - protected void onDayTapped(Calendar day) { + private void onDaySelected(Calendar day) { mController.tryVibrate(); mController.onDayOfMonthSelected(day.get(Calendar.YEAR), day.get(Calendar.MONTH), day.get(Calendar.DAY_OF_MONTH)); + setSelectedDay(day); } } diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java index a76241e..d2a37ac 100644 --- a/core/java/android/widget/SimpleMonthView.java +++ b/core/java/android/widget/SimpleMonthView.java @@ -31,6 +31,7 @@ import android.text.format.DateFormat; import android.text.format.DateUtils; import android.text.format.Time; import android.util.AttributeSet; +import android.util.IntArray; import android.util.MathUtils; import android.view.MotionEvent; import android.view.View; @@ -51,8 +52,6 @@ import java.util.Locale; * within the specified month. */ class SimpleMonthView extends View { - private static final String TAG = "SimpleMonthView"; - private static final int DEFAULT_HEIGHT = 32; private static final int MIN_HEIGHT = 10; @@ -66,15 +65,15 @@ class SimpleMonthView extends View { private static final int DAY_SEPARATOR_WIDTH = 1; + private final Formatter mFormatter; + private final StringBuilder mStringBuilder; + private final int mMiniDayNumberTextSize; private final int mMonthLabelTextSize; private final int mMonthDayLabelTextSize; private final int mMonthHeaderSize; private final int mDaySelectedCircleSize; - // used for scaling to the device density - private static float mScale = 0; - /** Single-letter (when available) formatter for the day of week label. */ private SimpleDateFormat mDayFormatter = new SimpleDateFormat("EEEEE", Locale.getDefault()); @@ -91,9 +90,6 @@ class SimpleMonthView extends View { private Paint mMonthTitlePaint; private Paint mMonthDayLabelPaint; - private final Formatter mFormatter; - private final StringBuilder mStringBuilder; - private int mMonth; private int mYear; @@ -154,11 +150,14 @@ class SimpleMonthView extends View { this(context, attrs, R.attr.datePickerStyle); } - public SimpleMonthView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs); + public SimpleMonthView(Context context, AttributeSet attrs, int defStyleAttr) { + this(context, attrs, defStyleAttr, 0); + } - final Resources res = context.getResources(); + public SimpleMonthView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + final Resources res = context.getResources(); mDayOfWeekTypeface = res.getString(R.string.day_of_week_label_typeface); mMonthTitleTypeface = res.getString(R.string.sans_serif); @@ -610,7 +609,7 @@ class SimpleMonthView extends View { } @Override - protected void getVisibleVirtualViews(List<Integer> virtualViewIds) { + protected void getVisibleVirtualViews(IntArray virtualViewIds) { for (int day = 1; day <= mNumCells; day++) { virtualViewIds.add(day); } diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java index a898084..4c8aa51 100644 --- a/core/java/android/widget/Switch.java +++ b/core/java/android/widget/Switch.java @@ -39,6 +39,7 @@ import android.util.FloatProperty; import android.util.MathUtils; import android.view.Gravity; import android.view.MotionEvent; +import android.view.SoundEffectConstants; import android.view.VelocityTracker; import android.view.ViewConfiguration; import android.view.accessibility.AccessibilityEvent; @@ -797,6 +798,7 @@ public class Switch extends CompoundButton { // Commit the change if the event is up and not canceled and the switch // has not been disabled during the drag. final boolean commitChange = ev.getAction() == MotionEvent.ACTION_UP && isEnabled(); + final boolean oldState = isChecked(); final boolean newState; if (commitChange) { mVelocityTracker.computeCurrentVelocity(1000); @@ -807,10 +809,14 @@ public class Switch extends CompoundButton { newState = getTargetCheckedState(); } } else { - newState = isChecked(); + newState = oldState; + } + + if (newState != oldState) { + playSoundEffect(SoundEffectConstants.CLICK); + setChecked(newState); } - setChecked(newState); cancelSuperTouch(ev); } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 6345b79..44ccde0 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -8517,6 +8517,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } return false; case AccessibilityNodeInfo.ACTION_SET_SELECTION: { if (isFocused() && canSelectText()) { + ensureIterableTextForAccessibilitySelectable(); CharSequence text = getIterableTextForAccessibility(); if (text == null) { return false; @@ -8542,6 +8543,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } } } return false; + case AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY: + case AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY: { + ensureIterableTextForAccessibilitySelectable(); + return super.performAccessibilityAction(action, arguments); + } default: { return super.performAccessibilityAction(action, arguments); } @@ -9031,10 +9037,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener */ @Override public CharSequence getIterableTextForAccessibility() { + return mText; + } + + private void ensureIterableTextForAccessibilitySelectable() { if (!(mText instanceof Spannable)) { setText(mText, BufferType.SPANNABLE); } - return mText; } /** diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java index 85cf67b..26e02f8 100644 --- a/core/java/android/widget/TimePicker.java +++ b/core/java/android/widget/TimePicker.java @@ -86,12 +86,12 @@ public class TimePicker extends FrameLayout { switch (mode) { case MODE_CLOCK: - mDelegate = new TimePickerSpinnerDelegate( + mDelegate = new TimePickerClockDelegate( this, context, attrs, defStyleAttr, defStyleRes); break; case MODE_SPINNER: default: - mDelegate = new TimePickerClockDelegate( + mDelegate = new TimePickerSpinnerDelegate( this, context, attrs, defStyleAttr, defStyleRes); break; } diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java index 8917f39..78ee247 100644 --- a/core/java/android/widget/TimePickerClockDelegate.java +++ b/core/java/android/widget/TimePickerClockDelegate.java @@ -17,365 +17,376 @@ package android.widget; import android.content.Context; +import android.content.res.ColorStateList; import android.content.res.Configuration; +import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.AttributeSet; +import android.util.Log; +import android.util.TypedValue; +import android.view.HapticFeedbackConstants; +import android.view.KeyCharacterMap; +import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; -import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.InputMethodManager; + import com.android.internal.R; -import java.text.DateFormatSymbols; +import java.util.ArrayList; import java.util.Calendar; import java.util.Locale; -import libcore.icu.LocaleData; - -import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; -import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; - /** - * A delegate implementing the basic TimePicker + * A delegate implementing the radial clock-based TimePicker. */ -class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { +class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate implements + RadialTimePickerView.OnValueSelectedListener { + + private static final String TAG = "TimePickerClockDelegate"; + + // Index used by RadialPickerLayout + private static final int HOUR_INDEX = 0; + private static final int MINUTE_INDEX = 1; + + // NOT a real index for the purpose of what's showing. + private static final int AMPM_INDEX = 2; + + // Also NOT a real index, just used for keyboard mode. + private static final int ENABLE_PICKER_INDEX = 3; + + static final int AM = 0; + static final int PM = 1; + private static final boolean DEFAULT_ENABLED_STATE = true; + private boolean mIsEnabled = DEFAULT_ENABLED_STATE; + private static final int HOURS_IN_HALF_DAY = 12; - // state - private boolean mIs24HourView; - private boolean mIsAm; + private final View mHeaderView; + private final TextView mHourView; + private final TextView mMinuteView; + private final View mAmPmLayout; + private final CheckedTextView mAmLabel; + private final CheckedTextView mPmLabel; + private final RadialTimePickerView mRadialTimePickerView; + private final TextView mSeparatorView; - // ui components - private final NumberPicker mHourSpinner; - private final NumberPicker mMinuteSpinner; - private final NumberPicker mAmPmSpinner; - private final EditText mHourSpinnerInput; - private final EditText mMinuteSpinnerInput; - private final EditText mAmPmSpinnerInput; - private final TextView mDivider; + private final String mAmText; + private final String mPmText; - // Note that the legacy implementation of the TimePicker is - // using a button for toggling between AM/PM while the new - // version uses a NumberPicker spinner. Therefore the code - // accommodates these two cases to be backwards compatible. - private final Button mAmPmButton; + private final float mDisabledAlpha; - private final String[] mAmPmStrings; + private boolean mAllowAutoAdvance; + private int mInitialHourOfDay; + private int mInitialMinute; + private boolean mIs24HourView; + + // For hardware IME input. + private char mPlaceholderText; + private String mDoublePlaceholderText; + private String mDeletedKeyFormat; + private boolean mInKbMode; + private ArrayList<Integer> mTypedTimes = new ArrayList<Integer>(); + private Node mLegalTimesTree; + private int mAmKeyCode; + private int mPmKeyCode; + + // Accessibility strings. + private String mHourPickerDescription; + private String mSelectHours; + private String mMinutePickerDescription; + private String mSelectMinutes; + + // Most recent time announcement values for accessibility. + private CharSequence mLastAnnouncedText; + private boolean mLastAnnouncedIsHour; - private boolean mIsEnabled = DEFAULT_ENABLED_STATE; private Calendar mTempCalendar; - private boolean mHourWithTwoDigit; - private char mHourFormat; public TimePickerClockDelegate(TimePicker delegator, Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(delegator, context); // process style attributes - final TypedArray a = mContext.obtainStyledAttributes( - attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes); - final int layoutResourceId = a.getResourceId( - R.styleable.TimePicker_legacyLayout, R.layout.time_picker_legacy); - a.recycle(); + final TypedArray a = mContext.obtainStyledAttributes(attrs, + R.styleable.TimePicker, defStyleAttr, defStyleRes); + final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( + Context.LAYOUT_INFLATER_SERVICE); + final Resources res = mContext.getResources(); + + mHourPickerDescription = res.getString(R.string.hour_picker_description); + mSelectHours = res.getString(R.string.select_hours); + mMinutePickerDescription = res.getString(R.string.minute_picker_description); + mSelectMinutes = res.getString(R.string.select_minutes); + + String[] amPmStrings = TimePickerSpinnerDelegate.getAmPmStrings(context); + mAmText = amPmStrings[0]; + mPmText = amPmStrings[1]; + + final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout, + R.layout.time_picker_holo); + final View mainView = inflater.inflate(layoutResourceId, delegator); + + mHeaderView = mainView.findViewById(R.id.time_header); + mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground)); + + // Set up hour/minute labels. + mHourView = (TextView) mHeaderView.findViewById(R.id.hours); + mHourView.setOnClickListener(mClickListener); + mSeparatorView = (TextView) mHeaderView.findViewById(R.id.separator); + mMinuteView = (TextView) mHeaderView.findViewById(R.id.minutes); + mMinuteView.setOnClickListener(mClickListener); + + final int headerTimeTextAppearance = a.getResourceId( + R.styleable.TimePicker_headerTimeTextAppearance, 0); + if (headerTimeTextAppearance != 0) { + mHourView.setTextAppearance(context, headerTimeTextAppearance); + mSeparatorView.setTextAppearance(context, headerTimeTextAppearance); + mMinuteView.setTextAppearance(context, headerTimeTextAppearance); + } - final LayoutInflater inflater = LayoutInflater.from(mContext); - inflater.inflate(layoutResourceId, mDelegator, true); - - // hour - mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour); - mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { - public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { - updateInputState(); - if (!is24HourView()) { - if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) || - (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) { - mIsAm = !mIsAm; - updateAmPmControl(); - } - } - onTimeChanged(); - } - }); - mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input); - mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); - - // divider (only for the new widget style) - mDivider = (TextView) mDelegator.findViewById(R.id.divider); - if (mDivider != null) { - setDividerText(); - } - - // minute - mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute); - mMinuteSpinner.setMinValue(0); - mMinuteSpinner.setMaxValue(59); - mMinuteSpinner.setOnLongPressUpdateInterval(100); - mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); - mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { - public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { - updateInputState(); - int minValue = mMinuteSpinner.getMinValue(); - int maxValue = mMinuteSpinner.getMaxValue(); - if (oldVal == maxValue && newVal == minValue) { - int newHour = mHourSpinner.getValue() + 1; - if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) { - mIsAm = !mIsAm; - updateAmPmControl(); - } - mHourSpinner.setValue(newHour); - } else if (oldVal == minValue && newVal == maxValue) { - int newHour = mHourSpinner.getValue() - 1; - if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) { - mIsAm = !mIsAm; - updateAmPmControl(); - } - mHourSpinner.setValue(newHour); - } - onTimeChanged(); - } - }); - mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input); - mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); - - // Get the localized am/pm strings and use them in the spinner. - mAmPmStrings = getAmPmStrings(context); - - // am/pm - final View amPmView = mDelegator.findViewById(R.id.amPm); - if (amPmView instanceof Button) { - mAmPmSpinner = null; - mAmPmSpinnerInput = null; - mAmPmButton = (Button) amPmView; - mAmPmButton.setOnClickListener(new View.OnClickListener() { - public void onClick(View button) { - button.requestFocus(); - mIsAm = !mIsAm; - updateAmPmControl(); - onTimeChanged(); - } - }); - } else { - mAmPmButton = null; - mAmPmSpinner = (NumberPicker) amPmView; - mAmPmSpinner.setMinValue(0); - mAmPmSpinner.setMaxValue(1); - mAmPmSpinner.setDisplayedValues(mAmPmStrings); - mAmPmSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { - public void onValueChange(NumberPicker picker, int oldVal, int newVal) { - updateInputState(); - picker.requestFocus(); - mIsAm = !mIsAm; - updateAmPmControl(); - onTimeChanged(); - } - }); - mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input); - mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); - } - - if (isAmPmAtStart()) { - // Move the am/pm view to the beginning - ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout); - amPmParent.removeView(amPmView); - amPmParent.addView(amPmView, 0); - // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme - // for example and not for Holo Theme) - ViewGroup.MarginLayoutParams lp = - (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams(); - final int startMargin = lp.getMarginStart(); - final int endMargin = lp.getMarginEnd(); - if (startMargin != endMargin) { - lp.setMarginStart(endMargin); - lp.setMarginEnd(startMargin); - } + // TODO: This can be removed once we support themed color state lists. + final int headerSelectedTextColor = a.getColor( + R.styleable.TimePicker_headerSelectedTextColor, + res.getColor(R.color.timepicker_default_selector_color_material)); + mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(), + R.attr.state_selected, headerSelectedTextColor)); + mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(), + R.attr.state_selected, headerSelectedTextColor)); + + // Set up AM/PM labels. + mAmPmLayout = mHeaderView.findViewById(R.id.ampm_layout); + mAmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.am_label); + mAmLabel.setText(amPmStrings[0]); + mAmLabel.setOnClickListener(mClickListener); + mPmLabel = (CheckedTextView) mAmPmLayout.findViewById(R.id.pm_label); + mPmLabel.setText(amPmStrings[1]); + mPmLabel.setOnClickListener(mClickListener); + + final int headerAmPmTextAppearance = a.getResourceId( + R.styleable.TimePicker_headerAmPmTextAppearance, 0); + if (headerAmPmTextAppearance != 0) { + mAmLabel.setTextAppearance(context, headerAmPmTextAppearance); + mPmLabel.setTextAppearance(context, headerAmPmTextAppearance); } - getHourFormatData(); + a.recycle(); + + // Pull disabled alpha from theme. + final TypedValue outValue = new TypedValue(); + context.getTheme().resolveAttribute(android.R.attr.disabledAlpha, outValue, true); + mDisabledAlpha = outValue.getFloat(); - // update controls to initial state - updateHourControl(); - updateMinuteControl(); - updateAmPmControl(); + mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById( + R.id.radial_picker); - // set to current time - setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY)); - setCurrentMinute(mTempCalendar.get(Calendar.MINUTE)); + setupListeners(); - if (!isEnabled()) { - setEnabled(false); - } + mAllowAutoAdvance = true; - // set the content descriptions - setContentDescriptions(); + // Set up for keyboard mode. + mDoublePlaceholderText = res.getString(R.string.time_placeholder); + mDeletedKeyFormat = res.getString(R.string.deleted_key); + mPlaceholderText = mDoublePlaceholderText.charAt(0); + mAmKeyCode = mPmKeyCode = -1; + generateLegalTimesTree(); - // If not explicitly specified this view is important for accessibility. - if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { - mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); - } + // Initialize with current time + final Calendar calendar = Calendar.getInstance(mCurrentLocale); + final int currentHour = calendar.get(Calendar.HOUR_OF_DAY); + final int currentMinute = calendar.get(Calendar.MINUTE); + initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX); } - private void getHourFormatData() { - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, - (mIs24HourView) ? "Hm" : "hm"); - final int lengthPattern = bestDateTimePattern.length(); - mHourWithTwoDigit = false; - char hourFormat = '\0'; - // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save - // the hour format that we found. - for (int i = 0; i < lengthPattern; i++) { - final char c = bestDateTimePattern.charAt(i); - if (c == 'H' || c == 'h' || c == 'K' || c == 'k') { - mHourFormat = c; - if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) { - mHourWithTwoDigit = true; - } - break; - } - } + private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) { + mInitialHourOfDay = hourOfDay; + mInitialMinute = minute; + mIs24HourView = is24HourView; + mInKbMode = false; + updateUI(index); } - private boolean isAmPmAtStart() { - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, - "hm" /* skeleton */); + private void setupListeners() { + mHeaderView.setOnKeyListener(mKeyListener); + mHeaderView.setOnFocusChangeListener(mFocusListener); + mHeaderView.setFocusable(true); - return bestDateTimePattern.startsWith("a"); + mRadialTimePickerView.setOnValueSelectedListener(this); } - /** - * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":". - * - * See http://unicode.org/cldr/trac/browser/trunk/common/main - * - * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the - * separator as the character which is just after the hour marker in the returned pattern. - */ - private void setDividerText() { - final String skeleton = (mIs24HourView) ? "Hm" : "hm"; - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, - skeleton); - final String separatorText; - int hourIndex = bestDateTimePattern.lastIndexOf('H'); - if (hourIndex == -1) { - hourIndex = bestDateTimePattern.lastIndexOf('h'); + private void updateUI(int index) { + // Update RadialPicker values + updateRadialPicker(index); + // Enable or disable the AM/PM view. + updateHeaderAmPm(); + // Update Hour and Minutes + updateHeaderHour(mInitialHourOfDay, false); + // Update time separator + updateHeaderSeparator(); + // Update Minutes + updateHeaderMinute(mInitialMinute, false); + // Invalidate everything + mDelegator.invalidate(); + } + + private void updateRadialPicker(int index) { + mRadialTimePickerView.initialize(mInitialHourOfDay, mInitialMinute, mIs24HourView); + setCurrentItemShowing(index, false, true); + } + + private int computeMaxWidthOfNumbers(int max) { + TextView tempView = new TextView(mContext); + tempView.setTextAppearance(mContext, R.style.TextAppearance_Material_TimePicker_TimeLabel); + ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT); + tempView.setLayoutParams(lp); + int maxWidth = 0; + for (int minutes = 0; minutes < max; minutes++) { + final String text = String.format("%02d", minutes); + tempView.setText(text); + tempView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + maxWidth = Math.max(maxWidth, tempView.getMeasuredWidth()); } - if (hourIndex == -1) { - // Default case - separatorText = ":"; + return maxWidth; + } + + private void updateHeaderAmPm() { + if (mIs24HourView) { + mAmPmLayout.setVisibility(View.GONE); } else { - int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1); - if (minuteIndex == -1) { - separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1)); + final String bestDateTimePattern = DateFormat.getBestDateTimePattern( + mCurrentLocale, "hm"); + boolean amPmOnLeft = bestDateTimePattern.startsWith("a"); + if (TextUtils.getLayoutDirectionFromLocale(mCurrentLocale) == + View.LAYOUT_DIRECTION_RTL) { + amPmOnLeft = !amPmOnLeft; + } + + final ViewGroup.MarginLayoutParams params = + (ViewGroup.MarginLayoutParams) mAmPmLayout.getLayoutParams(); + + if (amPmOnLeft) { + params.leftMargin = 0; + params.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */); } else { - separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex); + params.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */); + params.rightMargin = 0; } + + mAmPmLayout.setLayoutParams(params); + mAmPmLayout.setVisibility(View.VISIBLE); + + updateAmPmLabelStates(mInitialHourOfDay < 12 ? AM : PM); } - mDivider.setText(separatorText); } + /** + * Set the current hour. + */ @Override public void setCurrentHour(Integer currentHour) { - setCurrentHour(currentHour, true); - } - - private void setCurrentHour(Integer currentHour, boolean notifyTimeChanged) { - // why was Integer used in the first place? - if (currentHour == null || currentHour == getCurrentHour()) { + if (mInitialHourOfDay == currentHour) { return; } - if (!is24HourView()) { - // convert [0,23] ordinal to wall clock display - if (currentHour >= HOURS_IN_HALF_DAY) { - mIsAm = false; - if (currentHour > HOURS_IN_HALF_DAY) { - currentHour = currentHour - HOURS_IN_HALF_DAY; - } - } else { - mIsAm = true; - if (currentHour == 0) { - currentHour = HOURS_IN_HALF_DAY; - } - } - updateAmPmControl(); - } - mHourSpinner.setValue(currentHour); - if (notifyTimeChanged) { - onTimeChanged(); - } + mInitialHourOfDay = currentHour; + updateHeaderHour(currentHour, true); + updateHeaderAmPm(); + mRadialTimePickerView.setCurrentHour(currentHour); + mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM); + mDelegator.invalidate(); + onTimeChanged(); } + /** + * @return The current hour in the range (0-23). + */ @Override public Integer getCurrentHour() { - int currentHour = mHourSpinner.getValue(); - if (is24HourView()) { + int currentHour = mRadialTimePickerView.getCurrentHour(); + if (mIs24HourView) { return currentHour; - } else if (mIsAm) { - return currentHour % HOURS_IN_HALF_DAY; } else { - return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY; + switch(mRadialTimePickerView.getAmOrPm()) { + case PM: + return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY; + case AM: + default: + return currentHour % HOURS_IN_HALF_DAY; + } } } + /** + * Set the current minute (0-59). + */ @Override public void setCurrentMinute(Integer currentMinute) { - if (currentMinute == getCurrentMinute()) { + if (mInitialMinute == currentMinute) { return; } - mMinuteSpinner.setValue(currentMinute); + mInitialMinute = currentMinute; + updateHeaderMinute(currentMinute, true); + mRadialTimePickerView.setCurrentMinute(currentMinute); + mDelegator.invalidate(); onTimeChanged(); } + /** + * @return The current minute. + */ @Override public Integer getCurrentMinute() { - return mMinuteSpinner.getValue(); + return mRadialTimePickerView.getCurrentMinute(); } + /** + * Set whether in 24 hour or AM/PM mode. + * + * @param is24HourView True = 24 hour mode. False = AM/PM. + */ @Override public void setIs24HourView(Boolean is24HourView) { - if (mIs24HourView == is24HourView) { + if (is24HourView == mIs24HourView) { return; } - // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!! - int currentHour = getCurrentHour(); - // Order is important here. mIs24HourView = is24HourView; - getHourFormatData(); - updateHourControl(); - // set value after spinner range is updated - setCurrentHour(currentHour, false); - updateMinuteControl(); - updateAmPmControl(); + generateLegalTimesTree(); + int hour = mRadialTimePickerView.getCurrentHour(); + mInitialHourOfDay = hour; + updateHeaderHour(hour, false); + updateHeaderAmPm(); + updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing()); + mDelegator.invalidate(); } + /** + * @return true if this is in 24 hour view else false. + */ @Override public boolean is24HourView() { return mIs24HourView; } @Override - public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener onTimeChangedListener) { - mOnTimeChangedListener = onTimeChangedListener; + public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener callback) { + mOnTimeChangedListener = callback; } @Override public void setEnabled(boolean enabled) { - mMinuteSpinner.setEnabled(enabled); - if (mDivider != null) { - mDivider.setEnabled(enabled); - } - mHourSpinner.setEnabled(enabled); - if (mAmPmSpinner != null) { - mAmPmSpinner.setEnabled(enabled); - } else { - mAmPmButton.setEnabled(enabled); - } + mHourView.setEnabled(enabled); + mMinuteView.setEnabled(enabled); + mAmLabel.setEnabled(enabled); + mPmLabel.setEnabled(enabled); + mRadialTimePickerView.setEnabled(enabled); mIsEnabled = enabled; } @@ -386,24 +397,38 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { @Override public int getBaseline() { - return mHourSpinner.getBaseline(); + // does not support baseline alignment + return -1; } @Override public void onConfigurationChanged(Configuration newConfig) { - setCurrentLocale(newConfig.locale); + updateUI(mRadialTimePickerView.getCurrentItemShowing()); } @Override public Parcelable onSaveInstanceState(Parcelable superState) { - return new SavedState(superState, getCurrentHour(), getCurrentMinute()); + return new SavedState(superState, getCurrentHour(), getCurrentMinute(), + is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing()); } @Override public void onRestoreInstanceState(Parcelable state) { SavedState ss = (SavedState) state; - setCurrentHour(ss.getHour()); - setCurrentMinute(ss.getMinute()); + setInKbMode(ss.inKbMode()); + setTypedTimes(ss.getTypesTimes()); + initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing()); + mRadialTimePickerView.invalidate(); + if (mInKbMode) { + tryStartingKbMode(-1); + mHourView.invalidate(); + } + } + + @Override + public void setCurrentLocale(Locale locale) { + super.setCurrentLocale(locale); + mTempCalendar = Calendar.getInstance(locale); } @Override @@ -422,9 +447,9 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { } mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour()); mTempCalendar.set(Calendar.MINUTE, getCurrentMinute()); - String selectedDateUtterance = DateUtils.formatDateTime(mContext, + String selectedDate = DateUtils.formatDateTime(mContext, mTempCalendar.getTimeInMillis(), flags); - event.getText().add(selectedDateUtterance); + event.getText().add(selectedDate); } @Override @@ -437,121 +462,48 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { info.setClassName(TimePicker.class.getName()); } - private void updateInputState() { - // Make sure that if the user changes the value and the IME is active - // for one of the inputs if this widget, the IME is closed. If the user - // changed the value via the IME and there is a next input the IME will - // be shown, otherwise the user chose another means of changing the - // value and having the IME up makes no sense. - InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); - if (inputMethodManager != null) { - if (inputMethodManager.isActive(mHourSpinnerInput)) { - mHourSpinnerInput.clearFocus(); - inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); - } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) { - mMinuteSpinnerInput.clearFocus(); - inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); - } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) { - mAmPmSpinnerInput.clearFocus(); - inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); - } - } - } - - private void updateAmPmControl() { - if (is24HourView()) { - if (mAmPmSpinner != null) { - mAmPmSpinner.setVisibility(View.GONE); - } else { - mAmPmButton.setVisibility(View.GONE); - } - } else { - int index = mIsAm ? Calendar.AM : Calendar.PM; - if (mAmPmSpinner != null) { - mAmPmSpinner.setValue(index); - mAmPmSpinner.setVisibility(View.VISIBLE); - } else { - mAmPmButton.setText(mAmPmStrings[index]); - mAmPmButton.setVisibility(View.VISIBLE); - } - } - mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); - } - /** - * Sets the current locale. + * Set whether in keyboard mode or not. * - * @param locale The current locale. + * @param inKbMode True means in keyboard mode. */ - @Override - public void setCurrentLocale(Locale locale) { - super.setCurrentLocale(locale); - mTempCalendar = Calendar.getInstance(locale); + private void setInKbMode(boolean inKbMode) { + mInKbMode = inKbMode; } - private void onTimeChanged() { - mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); - if (mOnTimeChangedListener != null) { - mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(), - getCurrentMinute()); - } + /** + * @return true if in keyboard mode + */ + private boolean inKbMode() { + return mInKbMode; } - private void updateHourControl() { - if (is24HourView()) { - // 'k' means 1-24 hour - if (mHourFormat == 'k') { - mHourSpinner.setMinValue(1); - mHourSpinner.setMaxValue(24); - } else { - mHourSpinner.setMinValue(0); - mHourSpinner.setMaxValue(23); - } - } else { - // 'K' means 0-11 hour - if (mHourFormat == 'K') { - mHourSpinner.setMinValue(0); - mHourSpinner.setMaxValue(11); - } else { - mHourSpinner.setMinValue(1); - mHourSpinner.setMaxValue(12); - } - } - mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null); + private void setTypedTimes(ArrayList<Integer> typeTimes) { + mTypedTimes = typeTimes; } - private void updateMinuteControl() { - if (is24HourView()) { - mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); - } else { - mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); - } + /** + * @return an array of typed times + */ + private ArrayList<Integer> getTypedTimes() { + return mTypedTimes; } - private void setContentDescriptions() { - // Minute - trySetContentDescription(mMinuteSpinner, R.id.increment, - R.string.time_picker_increment_minute_button); - trySetContentDescription(mMinuteSpinner, R.id.decrement, - R.string.time_picker_decrement_minute_button); - // Hour - trySetContentDescription(mHourSpinner, R.id.increment, - R.string.time_picker_increment_hour_button); - trySetContentDescription(mHourSpinner, R.id.decrement, - R.string.time_picker_decrement_hour_button); - // AM/PM - if (mAmPmSpinner != null) { - trySetContentDescription(mAmPmSpinner, R.id.increment, - R.string.time_picker_increment_set_pm_button); - trySetContentDescription(mAmPmSpinner, R.id.decrement, - R.string.time_picker_decrement_set_am_button); - } + /** + * @return the index of the current item showing + */ + private int getCurrentItemShowing() { + return mRadialTimePickerView.getCurrentItemShowing(); } - private void trySetContentDescription(View root, int viewId, int contDescResId) { - View target = root.findViewById(viewId); - if (target != null) { - target.setContentDescription(mContext.getString(contDescResId)); + /** + * Propagate the time change + */ + private void onTimeChanged() { + mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + if (mOnTimeChangedListener != null) { + mOnTimeChangedListener.onTimeChanged(mDelegator, + getCurrentHour(), getCurrentMinute()); } } @@ -559,19 +511,34 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { * Used to save / restore state of time picker */ private static class SavedState extends View.BaseSavedState { + private final int mHour; private final int mMinute; - - private SavedState(Parcelable superState, int hour, int minute) { + private final boolean mIs24HourMode; + private final boolean mInKbMode; + private final ArrayList<Integer> mTypedTimes; + private final int mCurrentItemShowing; + + private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode, + boolean isKbMode, ArrayList<Integer> typedTimes, + int currentItemShowing) { super(superState); mHour = hour; mMinute = minute; + mIs24HourMode = is24HourMode; + mInKbMode = isKbMode; + mTypedTimes = typedTimes; + mCurrentItemShowing = currentItemShowing; } private SavedState(Parcel in) { super(in); mHour = in.readInt(); mMinute = in.readInt(); + mIs24HourMode = (in.readInt() == 1); + mInKbMode = (in.readInt() == 1); + mTypedTimes = in.readArrayList(getClass().getClassLoader()); + mCurrentItemShowing = in.readInt(); } public int getHour() { @@ -582,11 +549,31 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { return mMinute; } + public boolean is24HourMode() { + return mIs24HourMode; + } + + public boolean inKbMode() { + return mInKbMode; + } + + public ArrayList<Integer> getTypesTimes() { + return mTypedTimes; + } + + public int getCurrentItemShowing() { + return mCurrentItemShowing; + } + @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(mHour); dest.writeInt(mMinute); + dest.writeInt(mIs24HourMode ? 1 : 0); + dest.writeInt(mInKbMode ? 1 : 0); + dest.writeList(mTypedTimes); + dest.writeInt(mCurrentItemShowing); } @SuppressWarnings({"unused", "hiding"}) @@ -601,11 +588,696 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate { }; } - public static String[] getAmPmStrings(Context context) { - String[] result = new String[2]; - LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); - result[0] = d.amPm[0].length() > 2 ? d.narrowAm : d.amPm[0]; - result[1] = d.amPm[1].length() > 2 ? d.narrowPm : d.amPm[1]; - return result; + private void tryVibrate() { + mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); + } + + private void updateAmPmLabelStates(int amOrPm) { + final boolean isAm = amOrPm == AM; + mAmLabel.setChecked(isAm); + mAmLabel.setAlpha(isAm ? 1 : mDisabledAlpha); + + final boolean isPm = amOrPm == PM; + mPmLabel.setChecked(isPm); + mPmLabel.setAlpha(isPm ? 1 : mDisabledAlpha); + } + + /** + * Called by the picker for updating the header display. + */ + @Override + public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) { + if (pickerIndex == HOUR_INDEX) { + if (mAllowAutoAdvance && autoAdvance) { + updateHeaderHour(newValue, false); + setCurrentItemShowing(MINUTE_INDEX, true, false); + mDelegator.announceForAccessibility(newValue + ". " + mSelectMinutes); + } else { + updateHeaderHour(newValue, true); + } + } else if (pickerIndex == MINUTE_INDEX){ + updateHeaderMinute(newValue, true); + } else if (pickerIndex == AMPM_INDEX) { + updateAmPmLabelStates(newValue); + } else if (pickerIndex == ENABLE_PICKER_INDEX) { + if (!isTypedTimeFullyLegal()) { + mTypedTimes.clear(); + } + finishKbMode(); + } + } + + private void updateHeaderHour(int value, boolean announce) { + final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, + (mIs24HourView) ? "Hm" : "hm"); + final int lengthPattern = bestDateTimePattern.length(); + boolean hourWithTwoDigit = false; + char hourFormat = '\0'; + // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save + // the hour format that we found. + for (int i = 0; i < lengthPattern; i++) { + final char c = bestDateTimePattern.charAt(i); + if (c == 'H' || c == 'h' || c == 'K' || c == 'k') { + hourFormat = c; + if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) { + hourWithTwoDigit = true; + } + break; + } + } + final String format; + if (hourWithTwoDigit) { + format = "%02d"; + } else { + format = "%d"; + } + if (mIs24HourView) { + // 'k' means 1-24 hour + if (hourFormat == 'k' && value == 0) { + value = 24; + } + } else { + // 'K' means 0-11 hour + value = modulo12(value, hourFormat == 'K'); + } + CharSequence text = String.format(format, value); + mHourView.setText(text); + if (announce) { + tryAnnounceForAccessibility(text, true); + } + } + + private void tryAnnounceForAccessibility(CharSequence text, boolean isHour) { + if (mLastAnnouncedIsHour != isHour || !text.equals(mLastAnnouncedText)) { + // TODO: Find a better solution, potentially live regions? + mDelegator.announceForAccessibility(text); + mLastAnnouncedText = text; + mLastAnnouncedIsHour = isHour; + } + } + + private static int modulo12(int n, boolean startWithZero) { + int value = n % 12; + if (value == 0 && !startWithZero) { + value = 12; + } + return value; + } + + /** + * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":". + * + * See http://unicode.org/cldr/trac/browser/trunk/common/main + * + * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the + * separator as the character which is just after the hour marker in the returned pattern. + */ + private void updateHeaderSeparator() { + final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, + (mIs24HourView) ? "Hm" : "hm"); + final String separatorText; + // See http://www.unicode.org/reports/tr35/tr35-dates.html for hour formats + final char[] hourFormats = {'H', 'h', 'K', 'k'}; + int hIndex = lastIndexOfAny(bestDateTimePattern, hourFormats); + if (hIndex == -1) { + // Default case + separatorText = ":"; + } else { + separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1)); + } + mSeparatorView.setText(separatorText); + } + + static private int lastIndexOfAny(String str, char[] any) { + final int lengthAny = any.length; + if (lengthAny > 0) { + for (int i = str.length() - 1; i >= 0; i--) { + char c = str.charAt(i); + for (int j = 0; j < lengthAny; j++) { + if (c == any[j]) { + return i; + } + } + } + } + return -1; + } + + private void updateHeaderMinute(int value, boolean announceForAccessibility) { + if (value == 60) { + value = 0; + } + final CharSequence text = String.format(mCurrentLocale, "%02d", value); + mMinuteView.setText(text); + if (announceForAccessibility) { + tryAnnounceForAccessibility(text, false); + } + } + + /** + * Show either Hours or Minutes. + */ + private void setCurrentItemShowing(int index, boolean animateCircle, boolean announce) { + mRadialTimePickerView.setCurrentItemShowing(index, animateCircle); + + if (index == HOUR_INDEX) { + if (announce) { + mDelegator.announceForAccessibility(mSelectHours); + } + } else { + if (announce) { + mDelegator.announceForAccessibility(mSelectMinutes); + } + } + + mHourView.setSelected(index == HOUR_INDEX); + mMinuteView.setSelected(index == MINUTE_INDEX); + } + + private void setAmOrPm(int amOrPm) { + updateAmPmLabelStates(amOrPm); + mRadialTimePickerView.setAmOrPm(amOrPm); + } + + /** + * For keyboard mode, processes key events. + * + * @param keyCode the pressed key. + * + * @return true if the key was successfully processed, false otherwise. + */ + private boolean processKeyUp(int keyCode) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + if (mInKbMode) { + if (!mTypedTimes.isEmpty()) { + int deleted = deleteLastTypedKey(); + String deletedKeyStr; + if (deleted == getAmOrPmKeyCode(AM)) { + deletedKeyStr = mAmText; + } else if (deleted == getAmOrPmKeyCode(PM)) { + deletedKeyStr = mPmText; + } else { + deletedKeyStr = String.format("%d", getValFromKeyCode(deleted)); + } + mDelegator.announceForAccessibility( + String.format(mDeletedKeyFormat, deletedKeyStr)); + updateDisplay(true); + } + } + } else if (keyCode == KeyEvent.KEYCODE_0 || keyCode == KeyEvent.KEYCODE_1 + || keyCode == KeyEvent.KEYCODE_2 || keyCode == KeyEvent.KEYCODE_3 + || keyCode == KeyEvent.KEYCODE_4 || keyCode == KeyEvent.KEYCODE_5 + || keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7 + || keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9 + || (!mIs24HourView && + (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) { + if (!mInKbMode) { + if (mRadialTimePickerView == null) { + // Something's wrong, because time picker should definitely not be null. + Log.e(TAG, "Unable to initiate keyboard mode, TimePicker was null."); + return true; + } + mTypedTimes.clear(); + tryStartingKbMode(keyCode); + return true; + } + // We're already in keyboard mode. + if (addKeyIfLegal(keyCode)) { + updateDisplay(false); + } + return true; + } + return false; + } + + /** + * Try to start keyboard mode with the specified key. + * + * @param keyCode The key to use as the first press. Keyboard mode will not be started if the + * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting + * key. + */ + private void tryStartingKbMode(int keyCode) { + if (keyCode == -1 || addKeyIfLegal(keyCode)) { + mInKbMode = true; + onValidationChanged(false); + updateDisplay(false); + mRadialTimePickerView.setInputEnabled(false); + } } + + private boolean addKeyIfLegal(int keyCode) { + // If we're in 24hour mode, we'll need to check if the input is full. If in AM/PM mode, + // we'll need to see if AM/PM have been typed. + if ((mIs24HourView && mTypedTimes.size() == 4) || + (!mIs24HourView && isTypedTimeFullyLegal())) { + return false; + } + + mTypedTimes.add(keyCode); + if (!isTypedTimeLegalSoFar()) { + deleteLastTypedKey(); + return false; + } + + int val = getValFromKeyCode(keyCode); + mDelegator.announceForAccessibility(String.format("%d", val)); + // Automatically fill in 0's if AM or PM was legally entered. + if (isTypedTimeFullyLegal()) { + if (!mIs24HourView && mTypedTimes.size() <= 3) { + mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0); + mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0); + } + onValidationChanged(true); + } + + return true; + } + + /** + * Traverse the tree to see if the keys that have been typed so far are legal as is, + * or may become legal as more keys are typed (excluding backspace). + */ + private boolean isTypedTimeLegalSoFar() { + Node node = mLegalTimesTree; + for (int keyCode : mTypedTimes) { + node = node.canReach(keyCode); + if (node == null) { + return false; + } + } + return true; + } + + /** + * Check if the time that has been typed so far is completely legal, as is. + */ + private boolean isTypedTimeFullyLegal() { + if (mIs24HourView) { + // For 24-hour mode, the time is legal if the hours and minutes are each legal. Note: + // getEnteredTime() will ONLY call isTypedTimeFullyLegal() when NOT in 24hour mode. + int[] values = getEnteredTime(null); + return (values[0] >= 0 && values[1] >= 0 && values[1] < 60); + } else { + // For AM/PM mode, the time is legal if it contains an AM or PM, as those can only be + // legally added at specific times based on the tree's algorithm. + return (mTypedTimes.contains(getAmOrPmKeyCode(AM)) || + mTypedTimes.contains(getAmOrPmKeyCode(PM))); + } + } + + private int deleteLastTypedKey() { + int deleted = mTypedTimes.remove(mTypedTimes.size() - 1); + if (!isTypedTimeFullyLegal()) { + onValidationChanged(false); + } + return deleted; + } + + /** + * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time. + */ + private void finishKbMode() { + mInKbMode = false; + if (!mTypedTimes.isEmpty()) { + int values[] = getEnteredTime(null); + mRadialTimePickerView.setCurrentHour(values[0]); + mRadialTimePickerView.setCurrentMinute(values[1]); + if (!mIs24HourView) { + mRadialTimePickerView.setAmOrPm(values[2]); + } + mTypedTimes.clear(); + } + updateDisplay(false); + mRadialTimePickerView.setInputEnabled(true); + } + + /** + * Update the hours, minutes, and AM/PM displays with the typed times. If the typedTimes is + * empty, either show an empty display (filled with the placeholder text), or update from the + * timepicker's values. + * + * @param allowEmptyDisplay if true, then if the typedTimes is empty, use the placeholder text. + * Otherwise, revert to the timepicker's values. + */ + private void updateDisplay(boolean allowEmptyDisplay) { + if (!allowEmptyDisplay && mTypedTimes.isEmpty()) { + int hour = mRadialTimePickerView.getCurrentHour(); + int minute = mRadialTimePickerView.getCurrentMinute(); + updateHeaderHour(hour, false); + updateHeaderMinute(minute, false); + if (!mIs24HourView) { + updateAmPmLabelStates(hour < 12 ? AM : PM); + } + setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true); + onValidationChanged(true); + } else { + boolean[] enteredZeros = {false, false}; + int[] values = getEnteredTime(enteredZeros); + String hourFormat = enteredZeros[0] ? "%02d" : "%2d"; + String minuteFormat = (enteredZeros[1]) ? "%02d" : "%2d"; + String hourStr = (values[0] == -1) ? mDoublePlaceholderText : + String.format(hourFormat, values[0]).replace(' ', mPlaceholderText); + String minuteStr = (values[1] == -1) ? mDoublePlaceholderText : + String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText); + mHourView.setText(hourStr); + mHourView.setSelected(false); + mMinuteView.setText(minuteStr); + mMinuteView.setSelected(false); + if (!mIs24HourView) { + updateAmPmLabelStates(values[2]); + } + } + } + + private int getValFromKeyCode(int keyCode) { + switch (keyCode) { + case KeyEvent.KEYCODE_0: + return 0; + case KeyEvent.KEYCODE_1: + return 1; + case KeyEvent.KEYCODE_2: + return 2; + case KeyEvent.KEYCODE_3: + return 3; + case KeyEvent.KEYCODE_4: + return 4; + case KeyEvent.KEYCODE_5: + return 5; + case KeyEvent.KEYCODE_6: + return 6; + case KeyEvent.KEYCODE_7: + return 7; + case KeyEvent.KEYCODE_8: + return 8; + case KeyEvent.KEYCODE_9: + return 9; + default: + return -1; + } + } + + /** + * Get the currently-entered time, as integer values of the hours and minutes typed. + * + * @param enteredZeros A size-2 boolean array, which the caller should initialize, and which + * may then be used for the caller to know whether zeros had been explicitly entered as either + * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's. + * + * @return A size-3 int array. The first value will be the hours, the second value will be the + * minutes, and the third will be either AM or PM. + */ + private int[] getEnteredTime(boolean[] enteredZeros) { + int amOrPm = -1; + int startIndex = 1; + if (!mIs24HourView && isTypedTimeFullyLegal()) { + int keyCode = mTypedTimes.get(mTypedTimes.size() - 1); + if (keyCode == getAmOrPmKeyCode(AM)) { + amOrPm = AM; + } else if (keyCode == getAmOrPmKeyCode(PM)){ + amOrPm = PM; + } + startIndex = 2; + } + int minute = -1; + int hour = -1; + for (int i = startIndex; i <= mTypedTimes.size(); i++) { + int val = getValFromKeyCode(mTypedTimes.get(mTypedTimes.size() - i)); + if (i == startIndex) { + minute = val; + } else if (i == startIndex+1) { + minute += 10 * val; + if (enteredZeros != null && val == 0) { + enteredZeros[1] = true; + } + } else if (i == startIndex+2) { + hour = val; + } else if (i == startIndex+3) { + hour += 10 * val; + if (enteredZeros != null && val == 0) { + enteredZeros[0] = true; + } + } + } + + return new int[] { hour, minute, amOrPm }; + } + + /** + * Get the keycode value for AM and PM in the current language. + */ + private int getAmOrPmKeyCode(int amOrPm) { + // Cache the codes. + if (mAmKeyCode == -1 || mPmKeyCode == -1) { + // Find the first character in the AM/PM text that is unique. + KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); + char amChar; + char pmChar; + for (int i = 0; i < Math.max(mAmText.length(), mPmText.length()); i++) { + amChar = mAmText.toLowerCase(mCurrentLocale).charAt(i); + pmChar = mPmText.toLowerCase(mCurrentLocale).charAt(i); + if (amChar != pmChar) { + KeyEvent[] events = kcm.getEvents(new char[]{amChar, pmChar}); + // There should be 4 events: a down and up for both AM and PM. + if (events != null && events.length == 4) { + mAmKeyCode = events[0].getKeyCode(); + mPmKeyCode = events[2].getKeyCode(); + } else { + Log.e(TAG, "Unable to find keycodes for AM and PM."); + } + break; + } + } + } + if (amOrPm == AM) { + return mAmKeyCode; + } else if (amOrPm == PM) { + return mPmKeyCode; + } + + return -1; + } + + /** + * Create a tree for deciding what keys can legally be typed. + */ + private void generateLegalTimesTree() { + // Create a quick cache of numbers to their keycodes. + final int k0 = KeyEvent.KEYCODE_0; + final int k1 = KeyEvent.KEYCODE_1; + final int k2 = KeyEvent.KEYCODE_2; + final int k3 = KeyEvent.KEYCODE_3; + final int k4 = KeyEvent.KEYCODE_4; + final int k5 = KeyEvent.KEYCODE_5; + final int k6 = KeyEvent.KEYCODE_6; + final int k7 = KeyEvent.KEYCODE_7; + final int k8 = KeyEvent.KEYCODE_8; + final int k9 = KeyEvent.KEYCODE_9; + + // The root of the tree doesn't contain any numbers. + mLegalTimesTree = new Node(); + if (mIs24HourView) { + // We'll be re-using these nodes, so we'll save them. + Node minuteFirstDigit = new Node(k0, k1, k2, k3, k4, k5); + Node minuteSecondDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + // The first digit must be followed by the second digit. + minuteFirstDigit.addChild(minuteSecondDigit); + + // The first digit may be 0-1. + Node firstDigit = new Node(k0, k1); + mLegalTimesTree.addChild(firstDigit); + + // When the first digit is 0-1, the second digit may be 0-5. + Node secondDigit = new Node(k0, k1, k2, k3, k4, k5); + firstDigit.addChild(secondDigit); + // We may now be followed by the first minute digit. E.g. 00:09, 15:58. + secondDigit.addChild(minuteFirstDigit); + + // When the first digit is 0-1, and the second digit is 0-5, the third digit may be 6-9. + Node thirdDigit = new Node(k6, k7, k8, k9); + // The time must now be finished. E.g. 0:55, 1:08. + secondDigit.addChild(thirdDigit); + + // When the first digit is 0-1, the second digit may be 6-9. + secondDigit = new Node(k6, k7, k8, k9); + firstDigit.addChild(secondDigit); + // We must now be followed by the first minute digit. E.g. 06:50, 18:20. + secondDigit.addChild(minuteFirstDigit); + + // The first digit may be 2. + firstDigit = new Node(k2); + mLegalTimesTree.addChild(firstDigit); + + // When the first digit is 2, the second digit may be 0-3. + secondDigit = new Node(k0, k1, k2, k3); + firstDigit.addChild(secondDigit); + // We must now be followed by the first minute digit. E.g. 20:50, 23:09. + secondDigit.addChild(minuteFirstDigit); + + // When the first digit is 2, the second digit may be 4-5. + secondDigit = new Node(k4, k5); + firstDigit.addChild(secondDigit); + // We must now be followd by the last minute digit. E.g. 2:40, 2:53. + secondDigit.addChild(minuteSecondDigit); + + // The first digit may be 3-9. + firstDigit = new Node(k3, k4, k5, k6, k7, k8, k9); + mLegalTimesTree.addChild(firstDigit); + // We must now be followed by the first minute digit. E.g. 3:57, 8:12. + firstDigit.addChild(minuteFirstDigit); + } else { + // We'll need to use the AM/PM node a lot. + // Set up AM and PM to respond to "a" and "p". + Node ampm = new Node(getAmOrPmKeyCode(AM), getAmOrPmKeyCode(PM)); + + // The first hour digit may be 1. + Node firstDigit = new Node(k1); + mLegalTimesTree.addChild(firstDigit); + // We'll allow quick input of on-the-hour times. E.g. 1pm. + firstDigit.addChild(ampm); + + // When the first digit is 1, the second digit may be 0-2. + Node secondDigit = new Node(k0, k1, k2); + firstDigit.addChild(secondDigit); + // Also for quick input of on-the-hour times. E.g. 10pm, 12am. + secondDigit.addChild(ampm); + + // When the first digit is 1, and the second digit is 0-2, the third digit may be 0-5. + Node thirdDigit = new Node(k0, k1, k2, k3, k4, k5); + secondDigit.addChild(thirdDigit); + // The time may be finished now. E.g. 1:02pm, 1:25am. + thirdDigit.addChild(ampm); + + // When the first digit is 1, the second digit is 0-2, and the third digit is 0-5, + // the fourth digit may be 0-9. + Node fourthDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + thirdDigit.addChild(fourthDigit); + // The time must be finished now. E.g. 10:49am, 12:40pm. + fourthDigit.addChild(ampm); + + // When the first digit is 1, and the second digit is 0-2, the third digit may be 6-9. + thirdDigit = new Node(k6, k7, k8, k9); + secondDigit.addChild(thirdDigit); + // The time must be finished now. E.g. 1:08am, 1:26pm. + thirdDigit.addChild(ampm); + + // When the first digit is 1, the second digit may be 3-5. + secondDigit = new Node(k3, k4, k5); + firstDigit.addChild(secondDigit); + + // When the first digit is 1, and the second digit is 3-5, the third digit may be 0-9. + thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + secondDigit.addChild(thirdDigit); + // The time must be finished now. E.g. 1:39am, 1:50pm. + thirdDigit.addChild(ampm); + + // The hour digit may be 2-9. + firstDigit = new Node(k2, k3, k4, k5, k6, k7, k8, k9); + mLegalTimesTree.addChild(firstDigit); + // We'll allow quick input of on-the-hour-times. E.g. 2am, 5pm. + firstDigit.addChild(ampm); + + // When the first digit is 2-9, the second digit may be 0-5. + secondDigit = new Node(k0, k1, k2, k3, k4, k5); + firstDigit.addChild(secondDigit); + + // When the first digit is 2-9, and the second digit is 0-5, the third digit may be 0-9. + thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); + secondDigit.addChild(thirdDigit); + // The time must be finished now. E.g. 2:57am, 9:30pm. + thirdDigit.addChild(ampm); + } + } + + /** + * Simple node class to be used for traversal to check for legal times. + * mLegalKeys represents the keys that can be typed to get to the node. + * mChildren are the children that can be reached from this node. + */ + private class Node { + private int[] mLegalKeys; + private ArrayList<Node> mChildren; + + public Node(int... legalKeys) { + mLegalKeys = legalKeys; + mChildren = new ArrayList<Node>(); + } + + public void addChild(Node child) { + mChildren.add(child); + } + + public boolean containsKey(int key) { + for (int i = 0; i < mLegalKeys.length; i++) { + if (mLegalKeys[i] == key) { + return true; + } + } + return false; + } + + public Node canReach(int key) { + if (mChildren == null) { + return null; + } + for (Node child : mChildren) { + if (child.containsKey(key)) { + return child; + } + } + return null; + } + } + + private final View.OnClickListener mClickListener = new View.OnClickListener() { + @Override + public void onClick(View v) { + + final int amOrPm; + switch (v.getId()) { + case R.id.am_label: + setAmOrPm(AM); + break; + case R.id.pm_label: + setAmOrPm(PM); + break; + case R.id.hours: + setCurrentItemShowing(HOUR_INDEX, true, true); + break; + case R.id.minutes: + setCurrentItemShowing(MINUTE_INDEX, true, true); + break; + default: + // Failed to handle this click, don't vibrate. + return; + } + + tryVibrate(); + } + }; + + private final View.OnKeyListener mKeyListener = new View.OnKeyListener() { + @Override + public boolean onKey(View v, int keyCode, KeyEvent event) { + if (event.getAction() == KeyEvent.ACTION_UP) { + return processKeyUp(keyCode); + } + return false; + } + }; + + private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() { + @Override + public void onFocusChange(View v, boolean hasFocus) { + if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) { + finishKbMode(); + + if (mOnTimeChangedListener != null) { + mOnTimeChangedListener.onTimeChanged(mDelegator, + mRadialTimePickerView.getCurrentHour(), + mRadialTimePickerView.getCurrentMinute()); + } + } + } + }; } diff --git a/core/java/android/widget/TimePickerSpinnerDelegate.java b/core/java/android/widget/TimePickerSpinnerDelegate.java index 73e05e8..e162f4a 100644 --- a/core/java/android/widget/TimePickerSpinnerDelegate.java +++ b/core/java/android/widget/TimePickerSpinnerDelegate.java @@ -17,380 +17,365 @@ package android.widget; import android.content.Context; -import android.content.res.ColorStateList; import android.content.res.Configuration; -import android.content.res.Resources; import android.content.res.TypedArray; import android.os.Parcel; import android.os.Parcelable; -import android.text.TextUtils; import android.text.format.DateFormat; import android.text.format.DateUtils; import android.util.AttributeSet; -import android.util.Log; -import android.view.HapticFeedbackConstants; -import android.view.KeyCharacterMap; -import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; - +import android.view.inputmethod.EditorInfo; +import android.view.inputmethod.InputMethodManager; import com.android.internal.R; -import java.util.ArrayList; +import java.text.DateFormatSymbols; import java.util.Calendar; import java.util.Locale; -/** - * A view for selecting the time of day, in either 24 hour or AM/PM mode. - */ -class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate implements - RadialTimePickerView.OnValueSelectedListener { - - private static final String TAG = "TimePickerDelegate"; - - // Index used by RadialPickerLayout - private static final int HOUR_INDEX = 0; - private static final int MINUTE_INDEX = 1; - - // NOT a real index for the purpose of what's showing. - private static final int AMPM_INDEX = 2; +import libcore.icu.LocaleData; - // Also NOT a real index, just used for keyboard mode. - private static final int ENABLE_PICKER_INDEX = 3; - - private static final int AM = 0; - private static final int PM = 1; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO; +import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_YES; +/** + * A delegate implementing the basic spinner-based TimePicker. + */ +class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate { private static final boolean DEFAULT_ENABLED_STATE = true; - private boolean mIsEnabled = DEFAULT_ENABLED_STATE; - private static final int HOURS_IN_HALF_DAY = 12; - private View mHeaderView; - private TextView mHourView; - private TextView mMinuteView; - private TextView mAmPmTextView; - private RadialTimePickerView mRadialTimePickerView; - private TextView mSeparatorView; + // state + private boolean mIs24HourView; + private boolean mIsAm; - private String mAmText; - private String mPmText; + // ui components + private final NumberPicker mHourSpinner; + private final NumberPicker mMinuteSpinner; + private final NumberPicker mAmPmSpinner; + private final EditText mHourSpinnerInput; + private final EditText mMinuteSpinnerInput; + private final EditText mAmPmSpinnerInput; + private final TextView mDivider; - private boolean mAllowAutoAdvance; - private int mInitialHourOfDay; - private int mInitialMinute; - private boolean mIs24HourView; + // Note that the legacy implementation of the TimePicker is + // using a button for toggling between AM/PM while the new + // version uses a NumberPicker spinner. Therefore the code + // accommodates these two cases to be backwards compatible. + private final Button mAmPmButton; - // For hardware IME input. - private char mPlaceholderText; - private String mDoublePlaceholderText; - private String mDeletedKeyFormat; - private boolean mInKbMode; - private ArrayList<Integer> mTypedTimes = new ArrayList<Integer>(); - private Node mLegalTimesTree; - private int mAmKeyCode; - private int mPmKeyCode; - - // Accessibility strings. - private String mHourPickerDescription; - private String mSelectHours; - private String mMinutePickerDescription; - private String mSelectMinutes; + private final String[] mAmPmStrings; + private boolean mIsEnabled = DEFAULT_ENABLED_STATE; private Calendar mTempCalendar; + private boolean mHourWithTwoDigit; + private char mHourFormat; public TimePickerSpinnerDelegate(TimePicker delegator, Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(delegator, context); // process style attributes - final TypedArray a = mContext.obtainStyledAttributes(attrs, - R.styleable.TimePicker, defStyleAttr, defStyleRes); - final LayoutInflater inflater = (LayoutInflater) mContext.getSystemService( - Context.LAYOUT_INFLATER_SERVICE); - final Resources res = mContext.getResources(); - - mHourPickerDescription = res.getString(R.string.hour_picker_description); - mSelectHours = res.getString(R.string.select_hours); - mMinutePickerDescription = res.getString(R.string.minute_picker_description); - mSelectMinutes = res.getString(R.string.select_minutes); - - String[] amPmStrings = TimePickerClockDelegate.getAmPmStrings(context); - mAmText = amPmStrings[0]; - mPmText = amPmStrings[1]; - - final int layoutResourceId = a.getResourceId(R.styleable.TimePicker_internalLayout, - R.layout.time_picker_holo); - final View mainView = inflater.inflate(layoutResourceId, null); - mDelegator.addView(mainView); - - mHourView = (TextView) mainView.findViewById(R.id.hours); - mSeparatorView = (TextView) mainView.findViewById(R.id.separator); - mMinuteView = (TextView) mainView.findViewById(R.id.minutes); - mAmPmTextView = (TextView) mainView.findViewById(R.id.ampm_label); - - // Set up text appearances from style. - final int headerTimeTextAppearance = a.getResourceId( - R.styleable.TimePicker_headerTimeTextAppearance, 0); - if (headerTimeTextAppearance != 0) { - mHourView.setTextAppearance(context, headerTimeTextAppearance); - mSeparatorView.setTextAppearance(context, headerTimeTextAppearance); - mMinuteView.setTextAppearance(context, headerTimeTextAppearance); - } + final TypedArray a = mContext.obtainStyledAttributes( + attrs, R.styleable.TimePicker, defStyleAttr, defStyleRes); + final int layoutResourceId = a.getResourceId( + R.styleable.TimePicker_legacyLayout, R.layout.time_picker_legacy); + a.recycle(); - final int headerSelectedTextColor = a.getColor( - R.styleable.TimePicker_headerSelectedTextColor, - res.getColor(R.color.timepicker_default_selector_color_material)); - mHourView.setTextColor(ColorStateList.addFirstIfMissing(mHourView.getTextColors(), - R.attr.state_selected, headerSelectedTextColor)); - mMinuteView.setTextColor(ColorStateList.addFirstIfMissing(mMinuteView.getTextColors(), - R.attr.state_selected, headerSelectedTextColor)); - - final int headerAmPmTextAppearance = a.getResourceId( - R.styleable.TimePicker_headerAmPmTextAppearance, 0); - if (headerAmPmTextAppearance != 0) { - mAmPmTextView.setTextAppearance(context, headerAmPmTextAppearance); + final LayoutInflater inflater = LayoutInflater.from(mContext); + inflater.inflate(layoutResourceId, mDelegator, true); + + // hour + mHourSpinner = (NumberPicker) delegator.findViewById(R.id.hour); + mHourSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { + public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { + updateInputState(); + if (!is24HourView()) { + if ((oldVal == HOURS_IN_HALF_DAY - 1 && newVal == HOURS_IN_HALF_DAY) || + (oldVal == HOURS_IN_HALF_DAY && newVal == HOURS_IN_HALF_DAY - 1)) { + mIsAm = !mIsAm; + updateAmPmControl(); + } + } + onTimeChanged(); + } + }); + mHourSpinnerInput = (EditText) mHourSpinner.findViewById(R.id.numberpicker_input); + mHourSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); + + // divider (only for the new widget style) + mDivider = (TextView) mDelegator.findViewById(R.id.divider); + if (mDivider != null) { + setDividerText(); + } + + // minute + mMinuteSpinner = (NumberPicker) mDelegator.findViewById(R.id.minute); + mMinuteSpinner.setMinValue(0); + mMinuteSpinner.setMaxValue(59); + mMinuteSpinner.setOnLongPressUpdateInterval(100); + mMinuteSpinner.setFormatter(NumberPicker.getTwoDigitFormatter()); + mMinuteSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { + public void onValueChange(NumberPicker spinner, int oldVal, int newVal) { + updateInputState(); + int minValue = mMinuteSpinner.getMinValue(); + int maxValue = mMinuteSpinner.getMaxValue(); + if (oldVal == maxValue && newVal == minValue) { + int newHour = mHourSpinner.getValue() + 1; + if (!is24HourView() && newHour == HOURS_IN_HALF_DAY) { + mIsAm = !mIsAm; + updateAmPmControl(); + } + mHourSpinner.setValue(newHour); + } else if (oldVal == minValue && newVal == maxValue) { + int newHour = mHourSpinner.getValue() - 1; + if (!is24HourView() && newHour == HOURS_IN_HALF_DAY - 1) { + mIsAm = !mIsAm; + updateAmPmControl(); + } + mHourSpinner.setValue(newHour); + } + onTimeChanged(); + } + }); + mMinuteSpinnerInput = (EditText) mMinuteSpinner.findViewById(R.id.numberpicker_input); + mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); + + // Get the localized am/pm strings and use them in the spinner. + mAmPmStrings = getAmPmStrings(context); + + // am/pm + final View amPmView = mDelegator.findViewById(R.id.amPm); + if (amPmView instanceof Button) { + mAmPmSpinner = null; + mAmPmSpinnerInput = null; + mAmPmButton = (Button) amPmView; + mAmPmButton.setOnClickListener(new View.OnClickListener() { + public void onClick(View button) { + button.requestFocus(); + mIsAm = !mIsAm; + updateAmPmControl(); + onTimeChanged(); + } + }); + } else { + mAmPmButton = null; + mAmPmSpinner = (NumberPicker) amPmView; + mAmPmSpinner.setMinValue(0); + mAmPmSpinner.setMaxValue(1); + mAmPmSpinner.setDisplayedValues(mAmPmStrings); + mAmPmSpinner.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() { + public void onValueChange(NumberPicker picker, int oldVal, int newVal) { + updateInputState(); + picker.requestFocus(); + mIsAm = !mIsAm; + updateAmPmControl(); + onTimeChanged(); + } + }); + mAmPmSpinnerInput = (EditText) mAmPmSpinner.findViewById(R.id.numberpicker_input); + mAmPmSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); + } + + if (isAmPmAtStart()) { + // Move the am/pm view to the beginning + ViewGroup amPmParent = (ViewGroup) delegator.findViewById(R.id.timePickerLayout); + amPmParent.removeView(amPmView); + amPmParent.addView(amPmView, 0); + // Swap layout margins if needed. They may be not symmetrical (Old Standard Theme + // for example and not for Holo Theme) + ViewGroup.MarginLayoutParams lp = + (ViewGroup.MarginLayoutParams) amPmView.getLayoutParams(); + final int startMargin = lp.getMarginStart(); + final int endMargin = lp.getMarginEnd(); + if (startMargin != endMargin) { + lp.setMarginStart(endMargin); + lp.setMarginEnd(startMargin); + } } - mHeaderView = mainView.findViewById(R.id.time_header); - mHeaderView.setBackground(a.getDrawable(R.styleable.TimePicker_headerBackground)); - - a.recycle(); + getHourFormatData(); - mRadialTimePickerView = (RadialTimePickerView) mainView.findViewById( - R.id.radial_picker); + // update controls to initial state + updateHourControl(); + updateMinuteControl(); + updateAmPmControl(); - setupListeners(); + // set to current time + setCurrentHour(mTempCalendar.get(Calendar.HOUR_OF_DAY)); + setCurrentMinute(mTempCalendar.get(Calendar.MINUTE)); - mAllowAutoAdvance = true; + if (!isEnabled()) { + setEnabled(false); + } - // Set up for keyboard mode. - mDoublePlaceholderText = res.getString(R.string.time_placeholder); - mDeletedKeyFormat = res.getString(R.string.deleted_key); - mPlaceholderText = mDoublePlaceholderText.charAt(0); - mAmKeyCode = mPmKeyCode = -1; - generateLegalTimesTree(); + // set the content descriptions + setContentDescriptions(); - // Initialize with current time - final Calendar calendar = Calendar.getInstance(mCurrentLocale); - final int currentHour = calendar.get(Calendar.HOUR_OF_DAY); - final int currentMinute = calendar.get(Calendar.MINUTE); - initialize(currentHour, currentMinute, false /* 12h */, HOUR_INDEX); - } - - private void initialize(int hourOfDay, int minute, boolean is24HourView, int index) { - mInitialHourOfDay = hourOfDay; - mInitialMinute = minute; - mIs24HourView = is24HourView; - mInKbMode = false; - updateUI(index); + // If not explicitly specified this view is important for accessibility. + if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) { + mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); + } } - private void setupListeners() { - mHeaderView.setOnKeyListener(mKeyListener); - mHeaderView.setOnFocusChangeListener(mFocusListener); - mHeaderView.setFocusable(true); - - mRadialTimePickerView.setOnValueSelectedListener(this); - - mHourView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setCurrentItemShowing(HOUR_INDEX, true, true); - tryVibrate(); - } - }); - mMinuteView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - setCurrentItemShowing(MINUTE_INDEX, true, true); - tryVibrate(); + private void getHourFormatData() { + final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, + (mIs24HourView) ? "Hm" : "hm"); + final int lengthPattern = bestDateTimePattern.length(); + mHourWithTwoDigit = false; + char hourFormat = '\0'; + // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save + // the hour format that we found. + for (int i = 0; i < lengthPattern; i++) { + final char c = bestDateTimePattern.charAt(i); + if (c == 'H' || c == 'h' || c == 'K' || c == 'k') { + mHourFormat = c; + if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) { + mHourWithTwoDigit = true; + } + break; } - }); + } } - private void updateUI(int index) { - // Update RadialPicker values - updateRadialPicker(index); - // Enable or disable the AM/PM view. - updateHeaderAmPm(); - // Update Hour and Minutes - updateHeaderHour(mInitialHourOfDay, true); - // Update time separator - updateHeaderSeparator(); - // Update Minutes - updateHeaderMinute(mInitialMinute); - // Invalidate everything - mDelegator.invalidate(); - } + private boolean isAmPmAtStart() { + final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, + "hm" /* skeleton */); - private void updateRadialPicker(int index) { - mRadialTimePickerView.initialize(mInitialHourOfDay, mInitialMinute, mIs24HourView); - setCurrentItemShowing(index, false, true); + return bestDateTimePattern.startsWith("a"); } - private int computeMaxWidthOfNumbers(int max) { - TextView tempView = new TextView(mContext); - tempView.setTextAppearance(mContext, R.style.TextAppearance_Material_TimePicker_TimeLabel); - ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - tempView.setLayoutParams(lp); - int maxWidth = 0; - for (int minutes = 0; minutes < max; minutes++) { - final String text = String.format("%02d", minutes); - tempView.setText(text); - tempView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - maxWidth = Math.max(maxWidth, tempView.getMeasuredWidth()); + /** + * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":". + * + * See http://unicode.org/cldr/trac/browser/trunk/common/main + * + * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the + * separator as the character which is just after the hour marker in the returned pattern. + */ + private void setDividerText() { + final String skeleton = (mIs24HourView) ? "Hm" : "hm"; + final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, + skeleton); + final String separatorText; + int hourIndex = bestDateTimePattern.lastIndexOf('H'); + if (hourIndex == -1) { + hourIndex = bestDateTimePattern.lastIndexOf('h'); } - return maxWidth; - } - - private void updateHeaderAmPm() { - if (mIs24HourView) { - mAmPmTextView.setVisibility(View.GONE); + if (hourIndex == -1) { + // Default case + separatorText = ":"; } else { - mAmPmTextView.setVisibility(View.VISIBLE); - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, - "hm"); - - boolean amPmOnLeft = bestDateTimePattern.startsWith("a"); - if (TextUtils.getLayoutDirectionFromLocale(mCurrentLocale) == - View.LAYOUT_DIRECTION_RTL) { - amPmOnLeft = !amPmOnLeft; - } - - RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) - mAmPmTextView.getLayoutParams(); - - if (amPmOnLeft) { - layoutParams.rightMargin = computeMaxWidthOfNumbers(12 /* for hours */); - layoutParams.removeRule(RelativeLayout.RIGHT_OF); - layoutParams.addRule(RelativeLayout.LEFT_OF, R.id.separator); + int minuteIndex = bestDateTimePattern.indexOf('m', hourIndex + 1); + if (minuteIndex == -1) { + separatorText = Character.toString(bestDateTimePattern.charAt(hourIndex + 1)); } else { - layoutParams.leftMargin = computeMaxWidthOfNumbers(60 /* for minutes */); - layoutParams.removeRule(RelativeLayout.LEFT_OF); - layoutParams.addRule(RelativeLayout.RIGHT_OF, R.id.separator); + separatorText = bestDateTimePattern.substring(hourIndex + 1, minuteIndex); } - - updateAmPmDisplay(mInitialHourOfDay < 12 ? AM : PM); - mAmPmTextView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - tryVibrate(); - int amOrPm = mRadialTimePickerView.getAmOrPm(); - if (amOrPm == AM) { - amOrPm = PM; - } else if (amOrPm == PM){ - amOrPm = AM; - } - updateAmPmDisplay(amOrPm); - mRadialTimePickerView.setAmOrPm(amOrPm); - } - }); } + mDivider.setText(separatorText); } - /** - * Set the current hour. - */ @Override public void setCurrentHour(Integer currentHour) { - if (mInitialHourOfDay == currentHour) { + setCurrentHour(currentHour, true); + } + + private void setCurrentHour(Integer currentHour, boolean notifyTimeChanged) { + // why was Integer used in the first place? + if (currentHour == null || currentHour == getCurrentHour()) { return; } - mInitialHourOfDay = currentHour; - updateHeaderHour(currentHour, true /* accessibility announce */); - updateHeaderAmPm(); - mRadialTimePickerView.setCurrentHour(currentHour); - mRadialTimePickerView.setAmOrPm(mInitialHourOfDay < 12 ? AM : PM); - mDelegator.invalidate(); - onTimeChanged(); + if (!is24HourView()) { + // convert [0,23] ordinal to wall clock display + if (currentHour >= HOURS_IN_HALF_DAY) { + mIsAm = false; + if (currentHour > HOURS_IN_HALF_DAY) { + currentHour = currentHour - HOURS_IN_HALF_DAY; + } + } else { + mIsAm = true; + if (currentHour == 0) { + currentHour = HOURS_IN_HALF_DAY; + } + } + updateAmPmControl(); + } + mHourSpinner.setValue(currentHour); + if (notifyTimeChanged) { + onTimeChanged(); + } } - /** - * @return The current hour in the range (0-23). - */ @Override public Integer getCurrentHour() { - int currentHour = mRadialTimePickerView.getCurrentHour(); - if (mIs24HourView) { + int currentHour = mHourSpinner.getValue(); + if (is24HourView()) { return currentHour; + } else if (mIsAm) { + return currentHour % HOURS_IN_HALF_DAY; } else { - switch(mRadialTimePickerView.getAmOrPm()) { - case PM: - return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY; - case AM: - default: - return currentHour % HOURS_IN_HALF_DAY; - } + return (currentHour % HOURS_IN_HALF_DAY) + HOURS_IN_HALF_DAY; } } - /** - * Set the current minute (0-59). - */ @Override public void setCurrentMinute(Integer currentMinute) { - if (mInitialMinute == currentMinute) { + if (currentMinute == getCurrentMinute()) { return; } - mInitialMinute = currentMinute; - updateHeaderMinute(currentMinute); - mRadialTimePickerView.setCurrentMinute(currentMinute); - mDelegator.invalidate(); + mMinuteSpinner.setValue(currentMinute); onTimeChanged(); } - /** - * @return The current minute. - */ @Override public Integer getCurrentMinute() { - return mRadialTimePickerView.getCurrentMinute(); + return mMinuteSpinner.getValue(); } - /** - * Set whether in 24 hour or AM/PM mode. - * - * @param is24HourView True = 24 hour mode. False = AM/PM. - */ @Override public void setIs24HourView(Boolean is24HourView) { - if (is24HourView == mIs24HourView) { + if (mIs24HourView == is24HourView) { return; } + // cache the current hour since spinner range changes and BEFORE changing mIs24HourView!! + int currentHour = getCurrentHour(); + // Order is important here. mIs24HourView = is24HourView; - generateLegalTimesTree(); - int hour = mRadialTimePickerView.getCurrentHour(); - mInitialHourOfDay = hour; - updateHeaderHour(hour, false /* no accessibility announce */); - updateHeaderAmPm(); - updateRadialPicker(mRadialTimePickerView.getCurrentItemShowing()); - mDelegator.invalidate(); + getHourFormatData(); + updateHourControl(); + // set value after spinner range is updated + setCurrentHour(currentHour, false); + updateMinuteControl(); + updateAmPmControl(); } - /** - * @return true if this is in 24 hour view else false. - */ @Override public boolean is24HourView() { return mIs24HourView; } @Override - public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener callback) { - mOnTimeChangedListener = callback; + public void setOnTimeChangedListener(TimePicker.OnTimeChangedListener onTimeChangedListener) { + mOnTimeChangedListener = onTimeChangedListener; } @Override public void setEnabled(boolean enabled) { - mHourView.setEnabled(enabled); - mMinuteView.setEnabled(enabled); - mAmPmTextView.setEnabled(enabled); - mRadialTimePickerView.setEnabled(enabled); + mMinuteSpinner.setEnabled(enabled); + if (mDivider != null) { + mDivider.setEnabled(enabled); + } + mHourSpinner.setEnabled(enabled); + if (mAmPmSpinner != null) { + mAmPmSpinner.setEnabled(enabled); + } else { + mAmPmButton.setEnabled(enabled); + } mIsEnabled = enabled; } @@ -401,38 +386,24 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im @Override public int getBaseline() { - // does not support baseline alignment - return -1; + return mHourSpinner.getBaseline(); } @Override public void onConfigurationChanged(Configuration newConfig) { - updateUI(mRadialTimePickerView.getCurrentItemShowing()); + setCurrentLocale(newConfig.locale); } @Override public Parcelable onSaveInstanceState(Parcelable superState) { - return new SavedState(superState, getCurrentHour(), getCurrentMinute(), - is24HourView(), inKbMode(), getTypedTimes(), getCurrentItemShowing()); + return new SavedState(superState, getCurrentHour(), getCurrentMinute()); } @Override public void onRestoreInstanceState(Parcelable state) { SavedState ss = (SavedState) state; - setInKbMode(ss.inKbMode()); - setTypedTimes(ss.getTypesTimes()); - initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing()); - mRadialTimePickerView.invalidate(); - if (mInKbMode) { - tryStartingKbMode(-1); - mHourView.invalidate(); - } - } - - @Override - public void setCurrentLocale(Locale locale) { - super.setCurrentLocale(locale); - mTempCalendar = Calendar.getInstance(locale); + setCurrentHour(ss.getHour()); + setCurrentMinute(ss.getMinute()); } @Override @@ -451,9 +422,9 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im } mTempCalendar.set(Calendar.HOUR_OF_DAY, getCurrentHour()); mTempCalendar.set(Calendar.MINUTE, getCurrentMinute()); - String selectedDate = DateUtils.formatDateTime(mContext, + String selectedDateUtterance = DateUtils.formatDateTime(mContext, mTempCalendar.getTimeInMillis(), flags); - event.getText().add(selectedDate); + event.getText().add(selectedDateUtterance); } @Override @@ -466,48 +437,121 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im info.setClassName(TimePicker.class.getName()); } + private void updateInputState() { + // Make sure that if the user changes the value and the IME is active + // for one of the inputs if this widget, the IME is closed. If the user + // changed the value via the IME and there is a next input the IME will + // be shown, otherwise the user chose another means of changing the + // value and having the IME up makes no sense. + InputMethodManager inputMethodManager = InputMethodManager.peekInstance(); + if (inputMethodManager != null) { + if (inputMethodManager.isActive(mHourSpinnerInput)) { + mHourSpinnerInput.clearFocus(); + inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); + } else if (inputMethodManager.isActive(mMinuteSpinnerInput)) { + mMinuteSpinnerInput.clearFocus(); + inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); + } else if (inputMethodManager.isActive(mAmPmSpinnerInput)) { + mAmPmSpinnerInput.clearFocus(); + inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0); + } + } + } + + private void updateAmPmControl() { + if (is24HourView()) { + if (mAmPmSpinner != null) { + mAmPmSpinner.setVisibility(View.GONE); + } else { + mAmPmButton.setVisibility(View.GONE); + } + } else { + int index = mIsAm ? Calendar.AM : Calendar.PM; + if (mAmPmSpinner != null) { + mAmPmSpinner.setValue(index); + mAmPmSpinner.setVisibility(View.VISIBLE); + } else { + mAmPmButton.setText(mAmPmStrings[index]); + mAmPmButton.setVisibility(View.VISIBLE); + } + } + mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + } + /** - * Set whether in keyboard mode or not. + * Sets the current locale. * - * @param inKbMode True means in keyboard mode. + * @param locale The current locale. */ - private void setInKbMode(boolean inKbMode) { - mInKbMode = inKbMode; + @Override + public void setCurrentLocale(Locale locale) { + super.setCurrentLocale(locale); + mTempCalendar = Calendar.getInstance(locale); } - /** - * @return true if in keyboard mode - */ - private boolean inKbMode() { - return mInKbMode; + private void onTimeChanged() { + mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); + if (mOnTimeChangedListener != null) { + mOnTimeChangedListener.onTimeChanged(mDelegator, getCurrentHour(), + getCurrentMinute()); + } } - private void setTypedTimes(ArrayList<Integer> typeTimes) { - mTypedTimes = typeTimes; + private void updateHourControl() { + if (is24HourView()) { + // 'k' means 1-24 hour + if (mHourFormat == 'k') { + mHourSpinner.setMinValue(1); + mHourSpinner.setMaxValue(24); + } else { + mHourSpinner.setMinValue(0); + mHourSpinner.setMaxValue(23); + } + } else { + // 'K' means 0-11 hour + if (mHourFormat == 'K') { + mHourSpinner.setMinValue(0); + mHourSpinner.setMaxValue(11); + } else { + mHourSpinner.setMinValue(1); + mHourSpinner.setMaxValue(12); + } + } + mHourSpinner.setFormatter(mHourWithTwoDigit ? NumberPicker.getTwoDigitFormatter() : null); } - /** - * @return an array of typed times - */ - private ArrayList<Integer> getTypedTimes() { - return mTypedTimes; + private void updateMinuteControl() { + if (is24HourView()) { + mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_DONE); + } else { + mMinuteSpinnerInput.setImeOptions(EditorInfo.IME_ACTION_NEXT); + } } - /** - * @return the index of the current item showing - */ - private int getCurrentItemShowing() { - return mRadialTimePickerView.getCurrentItemShowing(); + private void setContentDescriptions() { + // Minute + trySetContentDescription(mMinuteSpinner, R.id.increment, + R.string.time_picker_increment_minute_button); + trySetContentDescription(mMinuteSpinner, R.id.decrement, + R.string.time_picker_decrement_minute_button); + // Hour + trySetContentDescription(mHourSpinner, R.id.increment, + R.string.time_picker_increment_hour_button); + trySetContentDescription(mHourSpinner, R.id.decrement, + R.string.time_picker_decrement_hour_button); + // AM/PM + if (mAmPmSpinner != null) { + trySetContentDescription(mAmPmSpinner, R.id.increment, + R.string.time_picker_increment_set_pm_button); + trySetContentDescription(mAmPmSpinner, R.id.decrement, + R.string.time_picker_decrement_set_am_button); + } } - /** - * Propagate the time change - */ - private void onTimeChanged() { - mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED); - if (mOnTimeChangedListener != null) { - mOnTimeChangedListener.onTimeChanged(mDelegator, - getCurrentHour(), getCurrentMinute()); + private void trySetContentDescription(View root, int viewId, int contDescResId) { + View target = root.findViewById(viewId); + if (target != null) { + target.setContentDescription(mContext.getString(contDescResId)); } } @@ -515,34 +559,19 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im * Used to save / restore state of time picker */ private static class SavedState extends View.BaseSavedState { - private final int mHour; private final int mMinute; - private final boolean mIs24HourMode; - private final boolean mInKbMode; - private final ArrayList<Integer> mTypedTimes; - private final int mCurrentItemShowing; - - private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode, - boolean isKbMode, ArrayList<Integer> typedTimes, - int currentItemShowing) { + + private SavedState(Parcelable superState, int hour, int minute) { super(superState); mHour = hour; mMinute = minute; - mIs24HourMode = is24HourMode; - mInKbMode = isKbMode; - mTypedTimes = typedTimes; - mCurrentItemShowing = currentItemShowing; } private SavedState(Parcel in) { super(in); mHour = in.readInt(); mMinute = in.readInt(); - mIs24HourMode = (in.readInt() == 1); - mInKbMode = (in.readInt() == 1); - mTypedTimes = in.readArrayList(getClass().getClassLoader()); - mCurrentItemShowing = in.readInt(); } public int getHour() { @@ -553,31 +582,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im return mMinute; } - public boolean is24HourMode() { - return mIs24HourMode; - } - - public boolean inKbMode() { - return mInKbMode; - } - - public ArrayList<Integer> getTypesTimes() { - return mTypedTimes; - } - - public int getCurrentItemShowing() { - return mCurrentItemShowing; - } - @Override public void writeToParcel(Parcel dest, int flags) { super.writeToParcel(dest, flags); dest.writeInt(mHour); dest.writeInt(mMinute); - dest.writeInt(mIs24HourMode ? 1 : 0); - dest.writeInt(mInKbMode ? 1 : 0); - dest.writeList(mTypedTimes); - dest.writeInt(mCurrentItemShowing); } @SuppressWarnings({"unused", "hiding"}) @@ -592,667 +601,11 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate im }; } - private void tryVibrate() { - mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK); - } - - private void updateAmPmDisplay(int amOrPm) { - if (amOrPm == AM) { - mAmPmTextView.setText(mAmText); - mRadialTimePickerView.announceForAccessibility(mAmText); - } else if (amOrPm == PM){ - mAmPmTextView.setText(mPmText); - mRadialTimePickerView.announceForAccessibility(mPmText); - } else { - mAmPmTextView.setText(mDoublePlaceholderText); - } - } - - /** - * Called by the picker for updating the header display. - */ - @Override - public void onValueSelected(int pickerIndex, int newValue, boolean autoAdvance) { - if (pickerIndex == HOUR_INDEX) { - updateHeaderHour(newValue, false); - String announcement = String.format("%d", newValue); - if (mAllowAutoAdvance && autoAdvance) { - setCurrentItemShowing(MINUTE_INDEX, true, false); - announcement += ". " + mSelectMinutes; - } else { - mRadialTimePickerView.setContentDescription( - mHourPickerDescription + ": " + newValue); - } - - mRadialTimePickerView.announceForAccessibility(announcement); - } else if (pickerIndex == MINUTE_INDEX){ - updateHeaderMinute(newValue); - mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + newValue); - } else if (pickerIndex == AMPM_INDEX) { - updateAmPmDisplay(newValue); - } else if (pickerIndex == ENABLE_PICKER_INDEX) { - if (!isTypedTimeFullyLegal()) { - mTypedTimes.clear(); - } - finishKbMode(); - } - } - - private void updateHeaderHour(int value, boolean announce) { - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, - (mIs24HourView) ? "Hm" : "hm"); - final int lengthPattern = bestDateTimePattern.length(); - boolean hourWithTwoDigit = false; - char hourFormat = '\0'; - // Check if the returned pattern is single or double 'H', 'h', 'K', 'k'. We also save - // the hour format that we found. - for (int i = 0; i < lengthPattern; i++) { - final char c = bestDateTimePattern.charAt(i); - if (c == 'H' || c == 'h' || c == 'K' || c == 'k') { - hourFormat = c; - if (i + 1 < lengthPattern && c == bestDateTimePattern.charAt(i + 1)) { - hourWithTwoDigit = true; - } - break; - } - } - final String format; - if (hourWithTwoDigit) { - format = "%02d"; - } else { - format = "%d"; - } - if (mIs24HourView) { - // 'k' means 1-24 hour - if (hourFormat == 'k' && value == 0) { - value = 24; - } - } else { - // 'K' means 0-11 hour - value = modulo12(value, hourFormat == 'K'); - } - CharSequence text = String.format(format, value); - mHourView.setText(text); - if (announce) { - mRadialTimePickerView.announceForAccessibility(text); - } - } - - private static int modulo12(int n, boolean startWithZero) { - int value = n % 12; - if (value == 0 && !startWithZero) { - value = 12; - } - return value; - } - - /** - * The time separator is defined in the Unicode CLDR and cannot be supposed to be ":". - * - * See http://unicode.org/cldr/trac/browser/trunk/common/main - * - * We pass the correct "skeleton" depending on 12 or 24 hours view and then extract the - * separator as the character which is just after the hour marker in the returned pattern. - */ - private void updateHeaderSeparator() { - final String bestDateTimePattern = DateFormat.getBestDateTimePattern(mCurrentLocale, - (mIs24HourView) ? "Hm" : "hm"); - final String separatorText; - // See http://www.unicode.org/reports/tr35/tr35-dates.html for hour formats - final char[] hourFormats = {'H', 'h', 'K', 'k'}; - int hIndex = lastIndexOfAny(bestDateTimePattern, hourFormats); - if (hIndex == -1) { - // Default case - separatorText = ":"; - } else { - separatorText = Character.toString(bestDateTimePattern.charAt(hIndex + 1)); - } - mSeparatorView.setText(separatorText); - } - - static private int lastIndexOfAny(String str, char[] any) { - final int lengthAny = any.length; - if (lengthAny > 0) { - for (int i = str.length() - 1; i >= 0; i--) { - char c = str.charAt(i); - for (int j = 0; j < lengthAny; j++) { - if (c == any[j]) { - return i; - } - } - } - } - return -1; - } - - private void updateHeaderMinute(int value) { - if (value == 60) { - value = 0; - } - CharSequence text = String.format(mCurrentLocale, "%02d", value); - mRadialTimePickerView.announceForAccessibility(text); - mMinuteView.setText(text); - } - - /** - * Show either Hours or Minutes. - */ - private void setCurrentItemShowing(int index, boolean animateCircle, boolean announce) { - mRadialTimePickerView.setCurrentItemShowing(index, animateCircle); - - if (index == HOUR_INDEX) { - int hours = mRadialTimePickerView.getCurrentHour(); - if (!mIs24HourView) { - hours = hours % 12; - } - mRadialTimePickerView.setContentDescription(mHourPickerDescription + ": " + hours); - if (announce) { - mRadialTimePickerView.announceForAccessibility(mSelectHours); - } - } else { - int minutes = mRadialTimePickerView.getCurrentMinute(); - mRadialTimePickerView.setContentDescription(mMinutePickerDescription + ": " + minutes); - if (announce) { - mRadialTimePickerView.announceForAccessibility(mSelectMinutes); - } - } - - mHourView.setSelected(index == HOUR_INDEX); - mMinuteView.setSelected(index == MINUTE_INDEX); - } - - /** - * For keyboard mode, processes key events. - * - * @param keyCode the pressed key. - * - * @return true if the key was successfully processed, false otherwise. - */ - private boolean processKeyUp(int keyCode) { - if (keyCode == KeyEvent.KEYCODE_DEL) { - if (mInKbMode) { - if (!mTypedTimes.isEmpty()) { - int deleted = deleteLastTypedKey(); - String deletedKeyStr; - if (deleted == getAmOrPmKeyCode(AM)) { - deletedKeyStr = mAmText; - } else if (deleted == getAmOrPmKeyCode(PM)) { - deletedKeyStr = mPmText; - } else { - deletedKeyStr = String.format("%d", getValFromKeyCode(deleted)); - } - mRadialTimePickerView.announceForAccessibility( - String.format(mDeletedKeyFormat, deletedKeyStr)); - updateDisplay(true); - } - } - } else if (keyCode == KeyEvent.KEYCODE_0 || keyCode == KeyEvent.KEYCODE_1 - || keyCode == KeyEvent.KEYCODE_2 || keyCode == KeyEvent.KEYCODE_3 - || keyCode == KeyEvent.KEYCODE_4 || keyCode == KeyEvent.KEYCODE_5 - || keyCode == KeyEvent.KEYCODE_6 || keyCode == KeyEvent.KEYCODE_7 - || keyCode == KeyEvent.KEYCODE_8 || keyCode == KeyEvent.KEYCODE_9 - || (!mIs24HourView && - (keyCode == getAmOrPmKeyCode(AM) || keyCode == getAmOrPmKeyCode(PM)))) { - if (!mInKbMode) { - if (mRadialTimePickerView == null) { - // Something's wrong, because time picker should definitely not be null. - Log.e(TAG, "Unable to initiate keyboard mode, TimePicker was null."); - return true; - } - mTypedTimes.clear(); - tryStartingKbMode(keyCode); - return true; - } - // We're already in keyboard mode. - if (addKeyIfLegal(keyCode)) { - updateDisplay(false); - } - return true; - } - return false; - } - - /** - * Try to start keyboard mode with the specified key. - * - * @param keyCode The key to use as the first press. Keyboard mode will not be started if the - * key is not legal to start with. Or, pass in -1 to get into keyboard mode without a starting - * key. - */ - private void tryStartingKbMode(int keyCode) { - if (keyCode == -1 || addKeyIfLegal(keyCode)) { - mInKbMode = true; - onValidationChanged(false); - updateDisplay(false); - mRadialTimePickerView.setInputEnabled(false); - } - } - - private boolean addKeyIfLegal(int keyCode) { - // If we're in 24hour mode, we'll need to check if the input is full. If in AM/PM mode, - // we'll need to see if AM/PM have been typed. - if ((mIs24HourView && mTypedTimes.size() == 4) || - (!mIs24HourView && isTypedTimeFullyLegal())) { - return false; - } - - mTypedTimes.add(keyCode); - if (!isTypedTimeLegalSoFar()) { - deleteLastTypedKey(); - return false; - } - - int val = getValFromKeyCode(keyCode); - mRadialTimePickerView.announceForAccessibility(String.format("%d", val)); - // Automatically fill in 0's if AM or PM was legally entered. - if (isTypedTimeFullyLegal()) { - if (!mIs24HourView && mTypedTimes.size() <= 3) { - mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0); - mTypedTimes.add(mTypedTimes.size() - 1, KeyEvent.KEYCODE_0); - } - onValidationChanged(true); - } - - return true; + public static String[] getAmPmStrings(Context context) { + String[] result = new String[2]; + LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale); + result[0] = d.amPm[0].length() > 2 ? d.narrowAm : d.amPm[0]; + result[1] = d.amPm[1].length() > 2 ? d.narrowPm : d.amPm[1]; + return result; } - - /** - * Traverse the tree to see if the keys that have been typed so far are legal as is, - * or may become legal as more keys are typed (excluding backspace). - */ - private boolean isTypedTimeLegalSoFar() { - Node node = mLegalTimesTree; - for (int keyCode : mTypedTimes) { - node = node.canReach(keyCode); - if (node == null) { - return false; - } - } - return true; - } - - /** - * Check if the time that has been typed so far is completely legal, as is. - */ - private boolean isTypedTimeFullyLegal() { - if (mIs24HourView) { - // For 24-hour mode, the time is legal if the hours and minutes are each legal. Note: - // getEnteredTime() will ONLY call isTypedTimeFullyLegal() when NOT in 24hour mode. - int[] values = getEnteredTime(null); - return (values[0] >= 0 && values[1] >= 0 && values[1] < 60); - } else { - // For AM/PM mode, the time is legal if it contains an AM or PM, as those can only be - // legally added at specific times based on the tree's algorithm. - return (mTypedTimes.contains(getAmOrPmKeyCode(AM)) || - mTypedTimes.contains(getAmOrPmKeyCode(PM))); - } - } - - private int deleteLastTypedKey() { - int deleted = mTypedTimes.remove(mTypedTimes.size() - 1); - if (!isTypedTimeFullyLegal()) { - onValidationChanged(false); - } - return deleted; - } - - /** - * Get out of keyboard mode. If there is nothing in typedTimes, revert to TimePicker's time. - */ - private void finishKbMode() { - mInKbMode = false; - if (!mTypedTimes.isEmpty()) { - int values[] = getEnteredTime(null); - mRadialTimePickerView.setCurrentHour(values[0]); - mRadialTimePickerView.setCurrentMinute(values[1]); - if (!mIs24HourView) { - mRadialTimePickerView.setAmOrPm(values[2]); - } - mTypedTimes.clear(); - } - updateDisplay(false); - mRadialTimePickerView.setInputEnabled(true); - } - - /** - * Update the hours, minutes, and AM/PM displays with the typed times. If the typedTimes is - * empty, either show an empty display (filled with the placeholder text), or update from the - * timepicker's values. - * - * @param allowEmptyDisplay if true, then if the typedTimes is empty, use the placeholder text. - * Otherwise, revert to the timepicker's values. - */ - private void updateDisplay(boolean allowEmptyDisplay) { - if (!allowEmptyDisplay && mTypedTimes.isEmpty()) { - int hour = mRadialTimePickerView.getCurrentHour(); - int minute = mRadialTimePickerView.getCurrentMinute(); - updateHeaderHour(hour, true); - updateHeaderMinute(minute); - if (!mIs24HourView) { - updateAmPmDisplay(hour < 12 ? AM : PM); - } - setCurrentItemShowing(mRadialTimePickerView.getCurrentItemShowing(), true, true); - onValidationChanged(true); - } else { - boolean[] enteredZeros = {false, false}; - int[] values = getEnteredTime(enteredZeros); - String hourFormat = enteredZeros[0] ? "%02d" : "%2d"; - String minuteFormat = (enteredZeros[1]) ? "%02d" : "%2d"; - String hourStr = (values[0] == -1) ? mDoublePlaceholderText : - String.format(hourFormat, values[0]).replace(' ', mPlaceholderText); - String minuteStr = (values[1] == -1) ? mDoublePlaceholderText : - String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText); - mHourView.setText(hourStr); - mHourView.setSelected(false); - mMinuteView.setText(minuteStr); - mMinuteView.setSelected(false); - if (!mIs24HourView) { - updateAmPmDisplay(values[2]); - } - } - } - - private int getValFromKeyCode(int keyCode) { - switch (keyCode) { - case KeyEvent.KEYCODE_0: - return 0; - case KeyEvent.KEYCODE_1: - return 1; - case KeyEvent.KEYCODE_2: - return 2; - case KeyEvent.KEYCODE_3: - return 3; - case KeyEvent.KEYCODE_4: - return 4; - case KeyEvent.KEYCODE_5: - return 5; - case KeyEvent.KEYCODE_6: - return 6; - case KeyEvent.KEYCODE_7: - return 7; - case KeyEvent.KEYCODE_8: - return 8; - case KeyEvent.KEYCODE_9: - return 9; - default: - return -1; - } - } - - /** - * Get the currently-entered time, as integer values of the hours and minutes typed. - * - * @param enteredZeros A size-2 boolean array, which the caller should initialize, and which - * may then be used for the caller to know whether zeros had been explicitly entered as either - * hours of minutes. This is helpful for deciding whether to show the dashes, or actual 0's. - * - * @return A size-3 int array. The first value will be the hours, the second value will be the - * minutes, and the third will be either AM or PM. - */ - private int[] getEnteredTime(boolean[] enteredZeros) { - int amOrPm = -1; - int startIndex = 1; - if (!mIs24HourView && isTypedTimeFullyLegal()) { - int keyCode = mTypedTimes.get(mTypedTimes.size() - 1); - if (keyCode == getAmOrPmKeyCode(AM)) { - amOrPm = AM; - } else if (keyCode == getAmOrPmKeyCode(PM)){ - amOrPm = PM; - } - startIndex = 2; - } - int minute = -1; - int hour = -1; - for (int i = startIndex; i <= mTypedTimes.size(); i++) { - int val = getValFromKeyCode(mTypedTimes.get(mTypedTimes.size() - i)); - if (i == startIndex) { - minute = val; - } else if (i == startIndex+1) { - minute += 10 * val; - if (enteredZeros != null && val == 0) { - enteredZeros[1] = true; - } - } else if (i == startIndex+2) { - hour = val; - } else if (i == startIndex+3) { - hour += 10 * val; - if (enteredZeros != null && val == 0) { - enteredZeros[0] = true; - } - } - } - - return new int[] { hour, minute, amOrPm }; - } - - /** - * Get the keycode value for AM and PM in the current language. - */ - private int getAmOrPmKeyCode(int amOrPm) { - // Cache the codes. - if (mAmKeyCode == -1 || mPmKeyCode == -1) { - // Find the first character in the AM/PM text that is unique. - KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.VIRTUAL_KEYBOARD); - char amChar; - char pmChar; - for (int i = 0; i < Math.max(mAmText.length(), mPmText.length()); i++) { - amChar = mAmText.toLowerCase(mCurrentLocale).charAt(i); - pmChar = mPmText.toLowerCase(mCurrentLocale).charAt(i); - if (amChar != pmChar) { - KeyEvent[] events = kcm.getEvents(new char[]{amChar, pmChar}); - // There should be 4 events: a down and up for both AM and PM. - if (events != null && events.length == 4) { - mAmKeyCode = events[0].getKeyCode(); - mPmKeyCode = events[2].getKeyCode(); - } else { - Log.e(TAG, "Unable to find keycodes for AM and PM."); - } - break; - } - } - } - if (amOrPm == AM) { - return mAmKeyCode; - } else if (amOrPm == PM) { - return mPmKeyCode; - } - - return -1; - } - - /** - * Create a tree for deciding what keys can legally be typed. - */ - private void generateLegalTimesTree() { - // Create a quick cache of numbers to their keycodes. - final int k0 = KeyEvent.KEYCODE_0; - final int k1 = KeyEvent.KEYCODE_1; - final int k2 = KeyEvent.KEYCODE_2; - final int k3 = KeyEvent.KEYCODE_3; - final int k4 = KeyEvent.KEYCODE_4; - final int k5 = KeyEvent.KEYCODE_5; - final int k6 = KeyEvent.KEYCODE_6; - final int k7 = KeyEvent.KEYCODE_7; - final int k8 = KeyEvent.KEYCODE_8; - final int k9 = KeyEvent.KEYCODE_9; - - // The root of the tree doesn't contain any numbers. - mLegalTimesTree = new Node(); - if (mIs24HourView) { - // We'll be re-using these nodes, so we'll save them. - Node minuteFirstDigit = new Node(k0, k1, k2, k3, k4, k5); - Node minuteSecondDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); - // The first digit must be followed by the second digit. - minuteFirstDigit.addChild(minuteSecondDigit); - - // The first digit may be 0-1. - Node firstDigit = new Node(k0, k1); - mLegalTimesTree.addChild(firstDigit); - - // When the first digit is 0-1, the second digit may be 0-5. - Node secondDigit = new Node(k0, k1, k2, k3, k4, k5); - firstDigit.addChild(secondDigit); - // We may now be followed by the first minute digit. E.g. 00:09, 15:58. - secondDigit.addChild(minuteFirstDigit); - - // When the first digit is 0-1, and the second digit is 0-5, the third digit may be 6-9. - Node thirdDigit = new Node(k6, k7, k8, k9); - // The time must now be finished. E.g. 0:55, 1:08. - secondDigit.addChild(thirdDigit); - - // When the first digit is 0-1, the second digit may be 6-9. - secondDigit = new Node(k6, k7, k8, k9); - firstDigit.addChild(secondDigit); - // We must now be followed by the first minute digit. E.g. 06:50, 18:20. - secondDigit.addChild(minuteFirstDigit); - - // The first digit may be 2. - firstDigit = new Node(k2); - mLegalTimesTree.addChild(firstDigit); - - // When the first digit is 2, the second digit may be 0-3. - secondDigit = new Node(k0, k1, k2, k3); - firstDigit.addChild(secondDigit); - // We must now be followed by the first minute digit. E.g. 20:50, 23:09. - secondDigit.addChild(minuteFirstDigit); - - // When the first digit is 2, the second digit may be 4-5. - secondDigit = new Node(k4, k5); - firstDigit.addChild(secondDigit); - // We must now be followd by the last minute digit. E.g. 2:40, 2:53. - secondDigit.addChild(minuteSecondDigit); - - // The first digit may be 3-9. - firstDigit = new Node(k3, k4, k5, k6, k7, k8, k9); - mLegalTimesTree.addChild(firstDigit); - // We must now be followed by the first minute digit. E.g. 3:57, 8:12. - firstDigit.addChild(minuteFirstDigit); - } else { - // We'll need to use the AM/PM node a lot. - // Set up AM and PM to respond to "a" and "p". - Node ampm = new Node(getAmOrPmKeyCode(AM), getAmOrPmKeyCode(PM)); - - // The first hour digit may be 1. - Node firstDigit = new Node(k1); - mLegalTimesTree.addChild(firstDigit); - // We'll allow quick input of on-the-hour times. E.g. 1pm. - firstDigit.addChild(ampm); - - // When the first digit is 1, the second digit may be 0-2. - Node secondDigit = new Node(k0, k1, k2); - firstDigit.addChild(secondDigit); - // Also for quick input of on-the-hour times. E.g. 10pm, 12am. - secondDigit.addChild(ampm); - - // When the first digit is 1, and the second digit is 0-2, the third digit may be 0-5. - Node thirdDigit = new Node(k0, k1, k2, k3, k4, k5); - secondDigit.addChild(thirdDigit); - // The time may be finished now. E.g. 1:02pm, 1:25am. - thirdDigit.addChild(ampm); - - // When the first digit is 1, the second digit is 0-2, and the third digit is 0-5, - // the fourth digit may be 0-9. - Node fourthDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); - thirdDigit.addChild(fourthDigit); - // The time must be finished now. E.g. 10:49am, 12:40pm. - fourthDigit.addChild(ampm); - - // When the first digit is 1, and the second digit is 0-2, the third digit may be 6-9. - thirdDigit = new Node(k6, k7, k8, k9); - secondDigit.addChild(thirdDigit); - // The time must be finished now. E.g. 1:08am, 1:26pm. - thirdDigit.addChild(ampm); - - // When the first digit is 1, the second digit may be 3-5. - secondDigit = new Node(k3, k4, k5); - firstDigit.addChild(secondDigit); - - // When the first digit is 1, and the second digit is 3-5, the third digit may be 0-9. - thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); - secondDigit.addChild(thirdDigit); - // The time must be finished now. E.g. 1:39am, 1:50pm. - thirdDigit.addChild(ampm); - - // The hour digit may be 2-9. - firstDigit = new Node(k2, k3, k4, k5, k6, k7, k8, k9); - mLegalTimesTree.addChild(firstDigit); - // We'll allow quick input of on-the-hour-times. E.g. 2am, 5pm. - firstDigit.addChild(ampm); - - // When the first digit is 2-9, the second digit may be 0-5. - secondDigit = new Node(k0, k1, k2, k3, k4, k5); - firstDigit.addChild(secondDigit); - - // When the first digit is 2-9, and the second digit is 0-5, the third digit may be 0-9. - thirdDigit = new Node(k0, k1, k2, k3, k4, k5, k6, k7, k8, k9); - secondDigit.addChild(thirdDigit); - // The time must be finished now. E.g. 2:57am, 9:30pm. - thirdDigit.addChild(ampm); - } - } - - /** - * Simple node class to be used for traversal to check for legal times. - * mLegalKeys represents the keys that can be typed to get to the node. - * mChildren are the children that can be reached from this node. - */ - private class Node { - private int[] mLegalKeys; - private ArrayList<Node> mChildren; - - public Node(int... legalKeys) { - mLegalKeys = legalKeys; - mChildren = new ArrayList<Node>(); - } - - public void addChild(Node child) { - mChildren.add(child); - } - - public boolean containsKey(int key) { - for (int i = 0; i < mLegalKeys.length; i++) { - if (mLegalKeys[i] == key) { - return true; - } - } - return false; - } - - public Node canReach(int key) { - if (mChildren == null) { - return null; - } - for (Node child : mChildren) { - if (child.containsKey(key)) { - return child; - } - } - return null; - } - } - - private final View.OnKeyListener mKeyListener = new View.OnKeyListener() { - @Override - public boolean onKey(View v, int keyCode, KeyEvent event) { - if (event.getAction() == KeyEvent.ACTION_UP) { - return processKeyUp(keyCode); - } - return false; - } - }; - - private final View.OnFocusChangeListener mFocusListener = new View.OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (!hasFocus && mInKbMode && isTypedTimeFullyLegal()) { - finishKbMode(); - - if (mOnTimeChangedListener != null) { - mOnTimeChangedListener.onTimeChanged(mDelegator, - mRadialTimePickerView.getCurrentHour(), - mRadialTimePickerView.getCurrentMinute()); - } - } - } - }; } diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java index dd165ae..be4cdc1 100644 --- a/core/java/android/widget/Toast.java +++ b/core/java/android/widget/Toast.java @@ -235,6 +235,14 @@ public class Toast { public int getYOffset() { return mTN.mY; } + + /** + * Gets the LayoutParams for the Toast window. + * @hide + */ + public WindowManager.LayoutParams getWindowParams() { + return mTN.mParams; + } /** * Make a standard toast that just contains a text view. diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index 1ce19ce..d8e39e3 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -66,7 +66,9 @@ import java.util.List; * <li><em>A navigation button.</em> This may be an Up arrow, navigation menu toggle, close, * collapse, done or another glyph of the app's choosing. This button should always be used * to access other navigational destinations within the container of the Toolbar and - * its signified content or otherwise leave the current context signified by the Toolbar.</li> + * its signified content or otherwise leave the current context signified by the Toolbar. + * The navigation button is vertically aligned within the Toolbar's + * {@link android.R.styleable#View_minHeight minimum height}, if set.</li> * <li><em>A branded logo image.</em> This may extend to the height of the bar and can be * arbitrarily wide.</li> * <li><em>A title and subtitle.</em> The title should be a signpost for the Toolbar's current @@ -82,8 +84,9 @@ import java.util.List; * <li><em>An {@link ActionMenuView action menu}.</em> The menu of actions will pin to the * end of the Toolbar offering a few * <a href="http://developer.android.com/design/patterns/actionbar.html#ActionButtons"> - * frequent, important or typical</a> actions along with an optional overflow menu for - * additional actions.</li> + * frequent, important or typical</a> actions along with an optional overflow menu for + * additional actions. Action buttons are vertically aligned within the Toolbar's + * {@link android.R.styleable#View_minHeight minimum height}, if set.</li> * </ul> * </p> * diff --git a/core/java/android/widget/YearPickerView.java b/core/java/android/widget/YearPickerView.java index 2bf07f9..24ed7ce 100644 --- a/core/java/android/widget/YearPickerView.java +++ b/core/java/android/widget/YearPickerView.java @@ -18,7 +18,6 @@ package android.widget; import android.content.Context; import android.content.res.Resources; -import android.content.res.TypedArray; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; @@ -33,10 +32,15 @@ import com.android.internal.R; */ class YearPickerView extends ListView implements AdapterView.OnItemClickListener, OnDateChangedListener { + private final Calendar mMinDate = Calendar.getInstance(); + private final Calendar mMaxDate = Calendar.getInstance(); + + private final YearAdapter mAdapter; + private final int mViewSize; + private final int mChildSize; + private DatePickerController mController; - private YearAdapter mAdapter; - private int mViewSize; - private int mChildSize; + private int mSelectedPosition = -1; private int mYearSelectedCircleColor; @@ -72,15 +76,23 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener setOnItemClickListener(this); setDividerHeight(0); + + mAdapter = new YearAdapter(getContext(), R.layout.year_label_text_view); + setAdapter(mAdapter); + } + + public void setRange(Calendar min, Calendar max) { + mMinDate.setTimeInMillis(min.getTimeInMillis()); + mMaxDate.setTimeInMillis(max.getTimeInMillis()); + + updateAdapterData(); } public void init(DatePickerController controller) { mController = controller; mController.registerOnDateChangedListener(this); - mAdapter = new YearAdapter(getContext(), R.layout.year_label_text_view); updateAdapterData(); - setAdapter(mAdapter); onDateChanged(); } @@ -98,8 +110,9 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener private void updateAdapterData() { mAdapter.clear(); - final int maxYear = mController.getMaxYear(); - for (int year = mController.getMinYear(); year <= maxYear; year++) { + + final int maxYear = mMaxDate.get(Calendar.YEAR); + for (int year = mMinDate.get(Calendar.YEAR); year <= maxYear; year++) { mAdapter.add(year); } } @@ -173,12 +186,13 @@ class YearPickerView extends ListView implements AdapterView.OnItemClickListener updateAdapterData(); mAdapter.notifyDataSetChanged(); postSetSelectionCentered( - mController.getSelectedDay().get(Calendar.YEAR) - mController.getMinYear()); + mController.getSelectedDay().get(Calendar.YEAR) - mMinDate.get(Calendar.YEAR)); } @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); + if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { event.setFromIndex(0); event.setToIndex(0); diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index 5267811..0bc1a8d 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -16,13 +16,20 @@ package com.android.internal.app; +import android.app.Activity; +import android.content.ComponentName; import android.content.Intent; +import android.content.IntentSender; import android.os.Bundle; import android.os.Parcelable; import android.util.Log; +import android.util.Slog; public class ChooserActivity extends ResolverActivity { + private static final String TAG = "ChooserActivity"; + private Bundle mReplacementExtras; + private IntentSender mChosenComponentSender; @Override protected void onCreate(Bundle savedInstanceState) { @@ -60,11 +67,14 @@ public class ChooserActivity extends ResolverActivity { initialIntents[i] = in; } } + mChosenComponentSender = intent.getParcelableExtra( + Intent.EXTRA_CHOSEN_COMPONENT_INTENT_SENDER); setSafeForwardingMode(true); super.onCreate(savedInstanceState, target, title, defaultTitleRes, initialIntents, null, false); } + @Override public Intent getReplacementIntent(String packageName, Intent defIntent) { if (mReplacementExtras != null) { final Bundle replExtras = mReplacementExtras.getBundle(packageName); @@ -77,6 +87,22 @@ public class ChooserActivity extends ResolverActivity { return defIntent; } + @Override + public void onActivityStarted(Intent intent) { + if (mChosenComponentSender != null) { + final ComponentName target = intent.getComponent(); + if (target != null) { + final Intent fillIn = new Intent().putExtra(Intent.EXTRA_CHOSEN_COMPONENT, target); + try { + mChosenComponentSender.sendIntent(this, Activity.RESULT_OK, fillIn, null, null); + } catch (IntentSender.SendIntentException e) { + Slog.e(TAG, "Unable to launch supplied IntentSender to report " + + "the chosen component: " + e); + } + } + } + } + private void modifyTargetIntent(Intent in) { final String action = in.getAction(); if (Intent.ACTION_SEND.equals(action) || diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 0062e2d..ccffa19 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -74,6 +74,9 @@ import java.util.List; import java.util.Map; import java.util.Set; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR; +import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN; + /** * This activity is displayed when the system attempts to start an Intent for * which there is more than one matching activity, allowing the user to decide @@ -269,6 +272,9 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic mListView = (ListView) findViewById(R.id.resolver_list); mListView.setVisibility(View.GONE); } + // Prevent the Resolver window from becoming the top fullscreen window and thus from taking + // control of the system bars. + getWindow().clearFlags(FLAG_LAYOUT_IN_SCREEN|FLAG_LAYOUT_INSET_DECOR); final ResolverDrawerLayout rdl = (ResolverDrawerLayout) findViewById(R.id.contentPanel); if (rdl != null) { @@ -638,10 +644,12 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic public void safelyStartActivity(Intent intent) { if (!mSafeForwardingMode) { startActivity(intent); + onActivityStarted(intent); return; } try { startActivityAsCaller(intent, null, UserHandle.USER_NULL); + onActivityStarted(intent); } catch (RuntimeException e) { String launchedFromPackage; try { @@ -656,6 +664,10 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic } } + public void onActivityStarted(Intent intent) { + // Do nothing + } + void showAppDetails(ResolveInfo ri) { Intent in = new Intent().setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) .setData(Uri.fromParts("package", ri.activityInfo.packageName, null)) @@ -819,6 +831,11 @@ public class ResolverActivity extends Activity implements AdapterView.OnItemClic } ResolveInfo ri = new ResolveInfo(); ri.activityInfo = ai; + UserManager userManager = + (UserManager) getSystemService(Context.USER_SERVICE); + if (userManager.isManagedProfile()) { + ri.noResourceId = true; + } if (ii instanceof LabeledIntent) { LabeledIntent li = (LabeledIntent)ii; ri.resolvePackageName = li.getSourcePackage(); diff --git a/core/java/com/android/internal/http/multipart/FilePart.java b/core/java/com/android/internal/http/multipart/FilePart.java index bfcda00..45e4be6 100644 --- a/core/java/com/android/internal/http/multipart/FilePart.java +++ b/core/java/com/android/internal/http/multipart/FilePart.java @@ -51,9 +51,14 @@ import org.apache.commons.logging.LogFactory; * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> * - * @since 2.0 + * @since 2.0 * + * @deprecated Please use {@link java.net.URLConnection} and friends instead. + * The Apache HTTP client is no longer maintained and may be removed in a future + * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> + * for further details. */ +@Deprecated public class FilePart extends PartBase { /** Default content encoding of file attachments. */ diff --git a/core/java/com/android/internal/http/multipart/MultipartEntity.java b/core/java/com/android/internal/http/multipart/MultipartEntity.java index 2c5e7f6..5319251 100644 --- a/core/java/com/android/internal/http/multipart/MultipartEntity.java +++ b/core/java/com/android/internal/http/multipart/MultipartEntity.java @@ -80,7 +80,13 @@ import org.apache.commons.logging.LogFactory; * </pre> * * @since 3.0 + * + * @deprecated Please use {@link java.net.URLConnection} and friends instead. + * The Apache HTTP client is no longer maintained and may be removed in a future + * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> + * for further details. */ +@Deprecated public class MultipartEntity extends AbstractHttpEntity { private static final Log log = LogFactory.getLog(MultipartEntity.class); diff --git a/core/java/com/android/internal/http/multipart/Part.java b/core/java/com/android/internal/http/multipart/Part.java index cb1b546..1d66dc6 100644 --- a/core/java/com/android/internal/http/multipart/Part.java +++ b/core/java/com/android/internal/http/multipart/Part.java @@ -48,7 +48,13 @@ import org.apache.commons.logging.LogFactory; * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> * * @since 2.0 + * + * @deprecated Please use {@link java.net.URLConnection} and friends instead. + * The Apache HTTP client is no longer maintained and may be removed in a future + * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> + * for further details. */ +@Deprecated public abstract class Part { /** Log object for this class. */ diff --git a/core/java/com/android/internal/http/multipart/StringPart.java b/core/java/com/android/internal/http/multipart/StringPart.java index c98257e..73d0f90 100644 --- a/core/java/com/android/internal/http/multipart/StringPart.java +++ b/core/java/com/android/internal/http/multipart/StringPart.java @@ -46,7 +46,13 @@ import org.apache.commons.logging.LogFactory; * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> * * @since 2.0 + * + * @deprecated Please use {@link java.net.URLConnection} and friends instead. + * The Apache HTTP client is no longer maintained and may be removed in a future + * release. Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a> + * for further details. */ +@Deprecated public class StringPart extends PartBase { /** Log object for this class. */ diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl index 8794d31..e6bcea1 100644 --- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl +++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl @@ -43,6 +43,7 @@ interface IStatusBarService void onPanelRevealed(); void onPanelHidden(); void onNotificationClick(String key); + void onNotificationActionClick(String key, int actionIndex); void onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message, int userId); void onClearAllNotifications(int userId); diff --git a/core/java/com/android/internal/util/MemInfoReader.java b/core/java/com/android/internal/util/MemInfoReader.java index 5f240f7..1dd9464 100644 --- a/core/java/com/android/internal/util/MemInfoReader.java +++ b/core/java/com/android/internal/util/MemInfoReader.java @@ -34,40 +34,65 @@ public final class MemInfoReader { } } + /** + * Total amount of RAM available to the kernel. + */ public long getTotalSize() { return mInfos[Debug.MEMINFO_TOTAL] * 1024; } + /** + * Amount of RAM that is not being used for anything. + */ public long getFreeSize() { return mInfos[Debug.MEMINFO_FREE] * 1024; } + /** + * Amount of RAM that the kernel is being used for caches, not counting caches + * that are mapped in to processes. + */ public long getCachedSize() { - return mInfos[Debug.MEMINFO_CACHED] * 1024; + return getCachedSizeKb() * 1024; } + /** + * Amount of RAM that is in use by the kernel for actual allocations. + */ + public long getKernelUsedSize() { + return getKernelUsedSizeKb() * 1024; + } + + /** + * Total amount of RAM available to the kernel. + */ public long getTotalSizeKb() { return mInfos[Debug.MEMINFO_TOTAL]; } + /** + * Amount of RAM that is not being used for anything. + */ public long getFreeSizeKb() { return mInfos[Debug.MEMINFO_FREE]; } + /** + * Amount of RAM that the kernel is being used for caches, not counting caches + * that are mapped in to processes. + */ public long getCachedSizeKb() { - return mInfos[Debug.MEMINFO_CACHED]; - } - - public long getBuffersSizeKb() { - return mInfos[Debug.MEMINFO_BUFFERS]; - } - - public long getShmemSizeKb() { - return mInfos[Debug.MEMINFO_SHMEM]; + return mInfos[Debug.MEMINFO_BUFFERS] + + mInfos[Debug.MEMINFO_CACHED] - mInfos[Debug.MEMINFO_MAPPED]; } - public long getSlabSizeKb() { - return mInfos[Debug.MEMINFO_SLAB]; + /** + * Amount of RAM that is in use by the kernel for actual allocations. + */ + public long getKernelUsedSizeKb() { + return mInfos[Debug.MEMINFO_SHMEM] + mInfos[Debug.MEMINFO_SLAB] + + mInfos[Debug.MEMINFO_VM_ALLOC_USED] + mInfos[Debug.MEMINFO_PAGE_TABLES] + + mInfos[Debug.MEMINFO_KERNEL_STACK]; } public long getSwapTotalSizeKb() { diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java index 40f58e9..99bb1ac 100644 --- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java +++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java @@ -54,6 +54,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On private final boolean mOverflowOnly; private final int mPopupMaxWidth; private final int mPopupStyleAttr; + private final int mPopupStyleRes; private View mAnchorView; private ListPopupWindow mPopup; @@ -73,21 +74,27 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On private int mDropDownGravity = Gravity.NO_GRAVITY; public MenuPopupHelper(Context context, MenuBuilder menu) { - this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle); + this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0); } public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) { - this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle); + this(context, menu, anchorView, false, com.android.internal.R.attr.popupMenuStyle, 0); } public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView, boolean overflowOnly, int popupStyleAttr) { + this(context, menu, anchorView, overflowOnly, popupStyleAttr, 0); + } + + public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView, + boolean overflowOnly, int popupStyleAttr, int popupStyleRes) { mContext = context; mInflater = LayoutInflater.from(context); mMenu = menu; mAdapter = new MenuAdapter(mMenu); mOverflowOnly = overflowOnly; mPopupStyleAttr = popupStyleAttr; + mPopupStyleRes = popupStyleRes; final Resources res = context.getResources(); mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2, @@ -122,7 +129,7 @@ public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.On } public boolean tryShow() { - mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr); + mPopup = new ListPopupWindow(mContext, null, mPopupStyleAttr, mPopupStyleRes); mPopup.setOnDismissListener(this); mPopup.setOnItemClickListener(this); mPopup.setAdapter(mAdapter); diff --git a/core/java/com/android/internal/widget/AccountItemView.java b/core/java/com/android/internal/widget/AccountItemView.java new file mode 100644 index 0000000..a521428 --- /dev/null +++ b/core/java/com/android/internal/widget/AccountItemView.java @@ -0,0 +1,102 @@ +/* +* Copyright (C) 2011-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.internal.widget; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.text.TextUtils; +import android.util.AttributeSet; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.internal.R; +import com.android.internal.widget.AccountViewAdapter.AccountElements; + + +/** + * An LinearLayout view, to show Accounts elements. + */ +public class AccountItemView extends LinearLayout { + + private ImageView mAccountIcon; + private TextView mAccountName; + private TextView mAccountNumber; + + /** + * Constructor. + */ + public AccountItemView(Context context) { + this(context, null); + } + + /** + * Constructor. + */ + public AccountItemView(Context context, AttributeSet attrs) { + super(context, attrs); + LayoutInflater inflator = (LayoutInflater) + context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + View view = inflator.inflate(R.layout.simple_account_item, null); + addView(view); + initViewItem(view); + } + + private void initViewItem(View view) { + mAccountIcon = (ImageView)view.findViewById(android.R.id.icon); + mAccountName = (TextView)view.findViewById(android.R.id.title); + mAccountNumber = (TextView)view.findViewById(android.R.id.summary); + } + + public void setViewItem(AccountElements element) { + Drawable drawable = element.getDrawable(); + if (drawable != null) { + setAccountIcon(drawable); + } else { + setAccountIcon(element.getIcon()); + } + setAccountName(element.getName()); + setAccountNumber(element.getNumber()); + } + + public void setAccountIcon(int resId) { + mAccountIcon.setImageResource(resId); + } + + public void setAccountIcon(Drawable drawable) { + mAccountIcon.setBackgroundDrawable(drawable); + } + + public void setAccountName(String name) { + setText(mAccountName, name); + } + + public void setAccountNumber(String number) { + setText(mAccountNumber, number); + } + + private void setText(TextView view, String text) { + if (TextUtils.isEmpty(text)) { + view.setVisibility(View.GONE); + } else { + view.setText(text); + view.setVisibility(View.VISIBLE); + } + } +} diff --git a/core/java/com/android/internal/widget/AccountViewAdapter.java b/core/java/com/android/internal/widget/AccountViewAdapter.java new file mode 100644 index 0000000..8a7a9a6 --- /dev/null +++ b/core/java/com/android/internal/widget/AccountViewAdapter.java @@ -0,0 +1,127 @@ +/* +* Copyright (C) 2011-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.internal.widget; + +import android.content.Context; +import android.graphics.drawable.Drawable; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import java.util.List; + +public class AccountViewAdapter extends BaseAdapter { + + private List<AccountElements> mData; + private Context mContext; + + /** + * Constructor + * + * @param context The context where the View associated with this Adapter is running + * @param data A list with AccountElements data type. The list contains the data of each + * account and the each member of AccountElements will correspond to one item view. + */ + public AccountViewAdapter(Context context, final List<AccountElements> data) { + mContext = context; + mData = data; + } + + @Override + public int getCount() { + return mData.size(); + } + + @Override + public Object getItem(int position) { + return mData.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + public void updateData(final List<AccountElements> data) { + mData = data; + notifyDataSetChanged(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + AccountItemView view; + if (convertView == null) { + view = new AccountItemView(mContext); + } else { + view = (AccountItemView) convertView; + } + AccountElements elements = (AccountElements) getItem(position); + view.setViewItem(elements); + return view; + } + + public static class AccountElements { + private int mIcon; + private Drawable mDrawable; + private String mName; + private String mNumber; + + /** + * Constructor + * A structure with basic element of an Account, icon, name and number + * + * @param icon Account icon id + * @param name Account name + * @param num Account number + */ + public AccountElements(int icon, String name, String number) { + this(icon, null, name, number); + } + + /** + * Constructor + * A structure with basic element of an Account, drawable, name and number + * + * @param drawable Account drawable + * @param name Account name + * @param num Account number + */ + public AccountElements(Drawable drawable, String name, String number) { + this(0, drawable, name, number); + } + + private AccountElements(int icon, Drawable drawable, String name, String number) { + mIcon = icon; + mDrawable = drawable; + mName = name; + mNumber = number; + } + + public int getIcon() { + return mIcon; + } + public String getName() { + return mName; + } + public String getNumber() { + return mNumber; + } + public Drawable getDrawable() { + return mDrawable; + } + } +} diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java index 91e5330..b9a85e5 100644 --- a/core/java/com/android/internal/widget/ActionBarView.java +++ b/core/java/com/android/internal/widget/ActionBarView.java @@ -19,8 +19,6 @@ package com.android.internal.widget; import android.animation.LayoutTransition; import android.app.ActionBar; import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.drawable.Drawable; @@ -29,9 +27,7 @@ import android.os.Parcelable; import android.text.Layout; import android.text.TextUtils; import android.util.AttributeSet; -import android.util.TypedValue; import android.view.CollapsibleActionView; -import android.view.ContextThemeWrapper; import android.view.Gravity; import android.view.LayoutInflater; import android.view.Menu; @@ -111,10 +107,10 @@ public class ActionBarView extends AbsActionBarView implements DecorToolbar { private int mProgressBarPadding; private int mItemPadding; - private int mTitleStyleRes; - private int mSubtitleStyleRes; - private int mProgressStyle; - private int mIndeterminateProgressStyle; + private final int mTitleStyleRes; + private final int mSubtitleStyleRes; + private final int mProgressStyle; + private final int mIndeterminateProgressStyle; private boolean mUserTitle; private boolean mIncludeTabs; diff --git a/core/java/com/android/internal/widget/ExploreByTouchHelper.java b/core/java/com/android/internal/widget/ExploreByTouchHelper.java index 11c4ca1..0e046cb 100644 --- a/core/java/com/android/internal/widget/ExploreByTouchHelper.java +++ b/core/java/com/android/internal/widget/ExploreByTouchHelper.java @@ -19,6 +19,7 @@ package com.android.internal.widget; import android.content.Context; import android.graphics.Rect; import android.os.Bundle; +import android.util.IntArray; import android.view.accessibility.*; import android.view.MotionEvent; import android.view.View; @@ -26,11 +27,9 @@ import android.view.ViewParent; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.accessibility.AccessibilityNodeInfo; +import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; import android.view.accessibility.AccessibilityNodeProvider; -import java.util.LinkedList; -import java.util.List; - /** * ExploreByTouchHelper is a utility class for implementing accessibility * support in custom {@link android.view.View}s that represent a collection of View-like @@ -54,14 +53,20 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { /** Default class name used for virtual views. */ private static final String DEFAULT_CLASS_NAME = View.class.getName(); - // Temporary, reusable data structures. - private final Rect mTempScreenRect = new Rect(); - private final Rect mTempParentRect = new Rect(); - private final Rect mTempVisibleRect = new Rect(); - private final int[] mTempGlobalRect = new int[2]; + /** Default bounds used to determine if the client didn't set any. */ + private static final Rect INVALID_PARENT_BOUNDS = new Rect( + Integer.MAX_VALUE, Integer.MAX_VALUE, Integer.MIN_VALUE, Integer.MIN_VALUE); + + // Lazily-created temporary data structures used when creating nodes. + private Rect mTempScreenRect; + private Rect mTempParentRect; + private int[] mTempGlobalRect; + + /** Lazily-created temporary data structure used to compute visibility. */ + private Rect mTempVisibleRect; - /** View's context **/ - private Context mContext; + /** Lazily-created temporary data structure used to obtain child IDs. */ + private IntArray mTempArray; /** System accessibility manager, used to check state and send events. */ private final AccessibilityManager mManager; @@ -69,6 +74,9 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { /** View whose internal structure is exposed through this helper. */ private final View mView; + /** Context of the host view. **/ + private final Context mContext; + /** Node provider that handles creating nodes and performing actions. */ private ExploreByTouchNodeProvider mNodeProvider; @@ -328,11 +336,17 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { onInitializeAccessibilityNodeInfo(mView, node); // Add the virtual descendants. - final LinkedList<Integer> virtualViewIds = new LinkedList<Integer>(); + if (mTempArray == null) { + mTempArray = new IntArray(); + } else { + mTempArray.clear(); + } + final IntArray virtualViewIds = mTempArray; getVisibleVirtualViews(virtualViewIds); - for (Integer childVirtualViewId : virtualViewIds) { - node.addChild(mView, childVirtualViewId); + final int N = virtualViewIds.size(); + for (int i = 0; i < N; i++) { + node.addChild(mView, virtualViewIds.get(i)); } return node; @@ -367,11 +381,17 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { * @return An {@link AccessibilityNodeInfo} for the specified item. */ private AccessibilityNodeInfo createNodeForChild(int virtualViewId) { + ensureTempRects(); + final Rect tempParentRect = mTempParentRect; + final int[] tempGlobalRect = mTempGlobalRect; + final Rect tempScreenRect = mTempScreenRect; + final AccessibilityNodeInfo node = AccessibilityNodeInfo.obtain(); // Ensure the client has good defaults. node.setEnabled(true); node.setClassName(DEFAULT_CLASS_NAME); + node.setBoundsInParent(INVALID_PARENT_BOUNDS); // Allow the client to populate the node. onPopulateNodeForVirtualView(virtualViewId, node); @@ -382,8 +402,8 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { + "populateNodeForVirtualViewId()"); } - node.getBoundsInParent(mTempParentRect); - if (mTempParentRect.isEmpty()) { + node.getBoundsInParent(tempParentRect); + if (tempParentRect.equals(INVALID_PARENT_BOUNDS)) { throw new RuntimeException("Callbacks must set parent bounds in " + "populateNodeForVirtualViewId()"); } @@ -406,29 +426,35 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { // Manage internal accessibility focus state. if (mFocusedVirtualViewId == virtualViewId) { node.setAccessibilityFocused(true); - node.addAction(AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS); + node.addAction(AccessibilityAction.ACTION_CLEAR_ACCESSIBILITY_FOCUS); } else { node.setAccessibilityFocused(false); - node.addAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS); + node.addAction(AccessibilityAction.ACTION_ACCESSIBILITY_FOCUS); } // Set the visibility based on the parent bound. - if (intersectVisibleToUser(mTempParentRect)) { + if (intersectVisibleToUser(tempParentRect)) { node.setVisibleToUser(true); - node.setBoundsInParent(mTempParentRect); + node.setBoundsInParent(tempParentRect); } // Calculate screen-relative bound. - mView.getLocationOnScreen(mTempGlobalRect); - final int offsetX = mTempGlobalRect[0]; - final int offsetY = mTempGlobalRect[1]; - mTempScreenRect.set(mTempParentRect); - mTempScreenRect.offset(offsetX, offsetY); - node.setBoundsInScreen(mTempScreenRect); + mView.getLocationOnScreen(tempGlobalRect); + final int offsetX = tempGlobalRect[0]; + final int offsetY = tempGlobalRect[1]; + tempScreenRect.set(tempParentRect); + tempScreenRect.offset(offsetX, offsetY); + node.setBoundsInScreen(tempScreenRect); return node; } + private void ensureTempRects() { + mTempGlobalRect = new int[2]; + mTempParentRect = new Rect(); + mTempScreenRect = new Rect(); + } + private boolean performAction(int virtualViewId, int action, Bundle arguments) { switch (virtualViewId) { case View.NO_ID: @@ -446,13 +472,13 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { switch (action) { case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: case AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS: - return manageFocusForChild(virtualViewId, action, arguments); + return manageFocusForChild(virtualViewId, action); default: return onPerformActionForVirtualView(virtualViewId, action, arguments); } } - private boolean manageFocusForChild(int virtualViewId, int action, Bundle arguments) { + private boolean manageFocusForChild(int virtualViewId, int action) { switch (action) { case AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS: return requestAccessibilityFocus(virtualViewId); @@ -498,12 +524,16 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { } // If no portion of the parent is visible, this view is not visible. - if (!mView.getLocalVisibleRect(mTempVisibleRect)) { + if (mTempVisibleRect == null) { + mTempVisibleRect = new Rect(); + } + final Rect tempVisibleRect = mTempVisibleRect; + if (!mView.getLocalVisibleRect(tempVisibleRect)) { return false; } // Check if the view intersects the visible portion of the parent. - return localRect.intersect(mTempVisibleRect); + return localRect.intersect(tempVisibleRect); } /** @@ -583,7 +613,7 @@ public abstract class ExploreByTouchHelper extends View.AccessibilityDelegate { * * @param virtualViewIds The list to populate with visible items */ - protected abstract void getVisibleVirtualViews(List<Integer> virtualViewIds); + protected abstract void getVisibleVirtualViews(IntArray virtualViewIds); /** * Populates an {@link AccessibilityEvent} with information about the diff --git a/core/java/com/android/internal/widget/SwipeDismissLayout.java b/core/java/com/android/internal/widget/SwipeDismissLayout.java index 97b1634..99b1bae 100644 --- a/core/java/com/android/internal/widget/SwipeDismissLayout.java +++ b/core/java/com/android/internal/widget/SwipeDismissLayout.java @@ -17,6 +17,7 @@ package com.android.internal.widget; import android.animation.TimeInterpolator; +import android.app.Activity; import android.content.Context; import android.util.AttributeSet; import android.util.Log; @@ -102,6 +103,13 @@ public class SwipeDismissLayout extends FrameLayout { android.R.integer.config_shortAnimTime); mCancelInterpolator = new DecelerateInterpolator(1.5f); mDismissInterpolator = new AccelerateInterpolator(1.5f); + // SwipeDismissLayout assumes that the host Activity is translucent + // and temporarily disables translucency when it is fully visible. + // As soon as the user starts swiping, we will re-enable + // translucency. + if (context instanceof Activity) { + ((Activity) context).convertFromTranslucent(); + } } public void setOnDismissedListener(OnDismissedListener listener) { @@ -197,6 +205,9 @@ public class SwipeDismissLayout extends FrameLayout { mLastX = ev.getRawX(); updateSwiping(ev); if (mSwiping) { + if (getContext() instanceof Activity) { + ((Activity) getContext()).convertToTranslucent(null, null); + } setProgress(ev.getRawX() - mDownX); break; } @@ -218,6 +229,9 @@ public class SwipeDismissLayout extends FrameLayout { } protected void cancel() { + if (getContext() instanceof Activity) { + ((Activity) getContext()).convertFromTranslucent(); + } if (mProgressListener != null) { mProgressListener.onSwipeCancelled(this); } diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp index 8ea28ec..a578b5d 100644 --- a/core/jni/android/graphics/BitmapFactory.cpp +++ b/core/jni/android/graphics/BitmapFactory.cpp @@ -315,7 +315,8 @@ static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding } SkBitmap decodingBitmap; - if (!decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode)) { + if (decoder->decode(stream, &decodingBitmap, prefColorType, decodeMode) + != SkImageDecoder::kSuccess) { return nullObjectReturn("decoder->decode returned false"); } @@ -478,7 +479,7 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi NPE_CHECK_RETURN_ZERO(env, fileDescriptor); - jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); + int descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor); struct stat fdStat; if (fstat(descriptor, &fdStat) == -1) { @@ -486,16 +487,27 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi return nullObjectReturn("fstat return -1"); } - // Restore the descriptor's offset on exiting this function. + // Restore the descriptor's offset on exiting this function. Even though + // we dup the descriptor, both the original and dup refer to the same open + // file description and changes to the file offset in one impact the other. AutoFDSeek autoRestore(descriptor); - FILE* file = fdopen(descriptor, "r"); + // Duplicate the descriptor here to prevent leaking memory. A leak occurs + // if we only close the file descriptor and not the file object it is used to + // create. If we don't explicitly clean up the file (which in turn closes the + // descriptor) the buffers allocated internally by fseek will be leaked. + int dupDescriptor = dup(descriptor); + + FILE* file = fdopen(dupDescriptor, "r"); if (file == NULL) { + // cleanup the duplicated descriptor since it will not be closed when the + // file is cleaned up (fclose). + close(dupDescriptor); return nullObjectReturn("Could not open file"); } SkAutoTUnref<SkFILEStream> fileStream(new SkFILEStream(file, - SkFILEStream::kCallerRetains_Ownership)); + SkFILEStream::kCallerPasses_Ownership)); // Use a buffered stream. Although an SkFILEStream can be rewound, this // ensures that SkImageDecoder::Factory never rewinds beyond the diff --git a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp index b64ab0d..a67740c 100644 --- a/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp +++ b/core/jni/android/graphics/CreateJavaOutputStreamAdaptor.cpp @@ -78,6 +78,8 @@ private: env->ExceptionDescribe(); env->ExceptionClear(); SkDebugf("---- read threw an exception\n"); + // Consider the stream to be at the end, since there was an error. + fIsAtEnd = true; return 0; } @@ -92,6 +94,9 @@ private: env->ExceptionDescribe(); env->ExceptionClear(); SkDebugf("---- read:GetByteArrayRegion threw an exception\n"); + // The error was not with the stream itself, but consider it to be at the + // end, since we do not have a way to recover. + fIsAtEnd = true; return 0; } diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp index cbd20e9..01ab699 100644 --- a/core/jni/android/graphics/Matrix.cpp +++ b/core/jni/android/graphics/Matrix.cpp @@ -308,46 +308,47 @@ public: static JNINativeMethod methods[] = { {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer}, {"native_create","(J)J", (void*) SkMatrixGlue::create}, - {"native_isIdentity","(J)Z", (void*) SkMatrixGlue::isIdentity}, - {"native_isAffine","(J)Z", (void*) SkMatrixGlue::isAffine}, - {"native_rectStaysRect","(J)Z", (void*) SkMatrixGlue::rectStaysRect}, - {"native_reset","(J)V", (void*) SkMatrixGlue::reset}, - {"native_set","(JJ)V", (void*) SkMatrixGlue::set}, - {"native_setTranslate","(JFF)V", (void*) SkMatrixGlue::setTranslate}, - {"native_setScale","(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF}, - {"native_setScale","(JFF)V", (void*) SkMatrixGlue::setScale__FF}, - {"native_setRotate","(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF}, - {"native_setRotate","(JF)V", (void*) SkMatrixGlue::setRotate__F}, - {"native_setSinCos","(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF}, - {"native_setSinCos","(JFF)V", (void*) SkMatrixGlue::setSinCos__FF}, - {"native_setSkew","(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF}, - {"native_setSkew","(JFF)V", (void*) SkMatrixGlue::setSkew__FF}, - {"native_setConcat","(JJJ)V", (void*) SkMatrixGlue::setConcat}, - {"native_preTranslate","(JFF)V", (void*) SkMatrixGlue::preTranslate}, - {"native_preScale","(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF}, - {"native_preScale","(JFF)V", (void*) SkMatrixGlue::preScale__FF}, - {"native_preRotate","(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF}, - {"native_preRotate","(JF)V", (void*) SkMatrixGlue::preRotate__F}, - {"native_preSkew","(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF}, - {"native_preSkew","(JFF)V", (void*) SkMatrixGlue::preSkew__FF}, - {"native_preConcat","(JJ)V", (void*) SkMatrixGlue::preConcat}, - {"native_postTranslate","(JFF)V", (void*) SkMatrixGlue::postTranslate}, - {"native_postScale","(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF}, - {"native_postScale","(JFF)V", (void*) SkMatrixGlue::postScale__FF}, - {"native_postRotate","(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF}, - {"native_postRotate","(JF)V", (void*) SkMatrixGlue::postRotate__F}, - {"native_postSkew","(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF}, - {"native_postSkew","(JFF)V", (void*) SkMatrixGlue::postSkew__FF}, - {"native_postConcat","(JJ)V", (void*) SkMatrixGlue::postConcat}, - {"native_setRectToRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z", (void*) SkMatrixGlue::setRectToRect}, - {"native_setPolyToPoly","(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly}, - {"native_invert","(JJ)Z", (void*) SkMatrixGlue::invert}, - {"native_mapPoints","(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints}, - {"native_mapRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z", (void*) SkMatrixGlue::mapRect__RectFRectF}, - {"native_mapRadius","(JF)F", (void*) SkMatrixGlue::mapRadius}, - {"native_getValues","(J[F)V", (void*) SkMatrixGlue::getValues}, - {"native_setValues","(J[F)V", (void*) SkMatrixGlue::setValues}, - {"native_equals", "(JJ)Z", (void*) SkMatrixGlue::equals} + + {"native_isIdentity","!(J)Z", (void*) SkMatrixGlue::isIdentity}, + {"native_isAffine","!(J)Z", (void*) SkMatrixGlue::isAffine}, + {"native_rectStaysRect","!(J)Z", (void*) SkMatrixGlue::rectStaysRect}, + {"native_reset","!(J)V", (void*) SkMatrixGlue::reset}, + {"native_set","!(JJ)V", (void*) SkMatrixGlue::set}, + {"native_setTranslate","!(JFF)V", (void*) SkMatrixGlue::setTranslate}, + {"native_setScale","!(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF}, + {"native_setScale","!(JFF)V", (void*) SkMatrixGlue::setScale__FF}, + {"native_setRotate","!(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF}, + {"native_setRotate","!(JF)V", (void*) SkMatrixGlue::setRotate__F}, + {"native_setSinCos","!(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF}, + {"native_setSinCos","!(JFF)V", (void*) SkMatrixGlue::setSinCos__FF}, + {"native_setSkew","!(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF}, + {"native_setSkew","!(JFF)V", (void*) SkMatrixGlue::setSkew__FF}, + {"native_setConcat","!(JJJ)V", (void*) SkMatrixGlue::setConcat}, + {"native_preTranslate","!(JFF)V", (void*) SkMatrixGlue::preTranslate}, + {"native_preScale","!(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF}, + {"native_preScale","!(JFF)V", (void*) SkMatrixGlue::preScale__FF}, + {"native_preRotate","!(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF}, + {"native_preRotate","!(JF)V", (void*) SkMatrixGlue::preRotate__F}, + {"native_preSkew","!(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF}, + {"native_preSkew","!(JFF)V", (void*) SkMatrixGlue::preSkew__FF}, + {"native_preConcat","!(JJ)V", (void*) SkMatrixGlue::preConcat}, + {"native_postTranslate","!(JFF)V", (void*) SkMatrixGlue::postTranslate}, + {"native_postScale","!(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF}, + {"native_postScale","!(JFF)V", (void*) SkMatrixGlue::postScale__FF}, + {"native_postRotate","!(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF}, + {"native_postRotate","!(JF)V", (void*) SkMatrixGlue::postRotate__F}, + {"native_postSkew","!(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF}, + {"native_postSkew","!(JFF)V", (void*) SkMatrixGlue::postSkew__FF}, + {"native_postConcat","!(JJ)V", (void*) SkMatrixGlue::postConcat}, + {"native_setRectToRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z", (void*) SkMatrixGlue::setRectToRect}, + {"native_setPolyToPoly","!(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly}, + {"native_invert","!(JJ)Z", (void*) SkMatrixGlue::invert}, + {"native_mapPoints","!(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints}, + {"native_mapRect","!(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z", (void*) SkMatrixGlue::mapRect__RectFRectF}, + {"native_mapRadius","!(JF)F", (void*) SkMatrixGlue::mapRadius}, + {"native_getValues","!(J[F)V", (void*) SkMatrixGlue::getValues}, + {"native_setValues","!(J[F)V", (void*) SkMatrixGlue::setValues}, + {"native_equals", "!(JJ)Z", (void*) SkMatrixGlue::equals} }; static jfieldID sNativeInstanceField; diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp index 4bb31fc..6b02326 100644 --- a/core/jni/android/graphics/Paint.cpp +++ b/core/jni/android/graphics/Paint.cpp @@ -939,58 +939,60 @@ static JNINativeMethod methods[] = { {"finalizer", "(J)V", (void*) PaintGlue::finalizer}, {"native_init","()J", (void*) PaintGlue::init}, {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint}, - {"native_reset","(J)V", (void*) PaintGlue::reset}, - {"native_set","(JJ)V", (void*) PaintGlue::assign}, - {"getFlags","()I", (void*) PaintGlue::getFlags}, - {"setFlags","(I)V", (void*) PaintGlue::setFlags}, - {"getHinting","()I", (void*) PaintGlue::getHinting}, - {"setHinting","(I)V", (void*) PaintGlue::setHinting}, - {"setAntiAlias","(Z)V", (void*) PaintGlue::setAntiAlias}, - {"setSubpixelText","(Z)V", (void*) PaintGlue::setSubpixelText}, - {"setLinearText","(Z)V", (void*) PaintGlue::setLinearText}, - {"setUnderlineText","(Z)V", (void*) PaintGlue::setUnderlineText}, - {"setStrikeThruText","(Z)V", (void*) PaintGlue::setStrikeThruText}, - {"setFakeBoldText","(Z)V", (void*) PaintGlue::setFakeBoldText}, - {"setFilterBitmap","(Z)V", (void*) PaintGlue::setFilterBitmap}, - {"setDither","(Z)V", (void*) PaintGlue::setDither}, - {"native_getStyle","(J)I", (void*) PaintGlue::getStyle}, - {"native_setStyle","(JI)V", (void*) PaintGlue::setStyle}, - {"getColor","()I", (void*) PaintGlue::getColor}, - {"setColor","(I)V", (void*) PaintGlue::setColor}, - {"getAlpha","()I", (void*) PaintGlue::getAlpha}, - {"setAlpha","(I)V", (void*) PaintGlue::setAlpha}, - {"getStrokeWidth","()F", (void*) PaintGlue::getStrokeWidth}, - {"setStrokeWidth","(F)V", (void*) PaintGlue::setStrokeWidth}, - {"getStrokeMiter","()F", (void*) PaintGlue::getStrokeMiter}, - {"setStrokeMiter","(F)V", (void*) PaintGlue::setStrokeMiter}, - {"native_getStrokeCap","(J)I", (void*) PaintGlue::getStrokeCap}, - {"native_setStrokeCap","(JI)V", (void*) PaintGlue::setStrokeCap}, - {"native_getStrokeJoin","(J)I", (void*) PaintGlue::getStrokeJoin}, - {"native_setStrokeJoin","(JI)V", (void*) PaintGlue::setStrokeJoin}, - {"native_getFillPath","(JJJ)Z", (void*) PaintGlue::getFillPath}, - {"native_setShader","(JJ)J", (void*) PaintGlue::setShader}, - {"native_setColorFilter","(JJ)J", (void*) PaintGlue::setColorFilter}, - {"native_setXfermode","(JJ)J", (void*) PaintGlue::setXfermode}, - {"native_setPathEffect","(JJ)J", (void*) PaintGlue::setPathEffect}, - {"native_setMaskFilter","(JJ)J", (void*) PaintGlue::setMaskFilter}, - {"native_setTypeface","(JJ)J", (void*) PaintGlue::setTypeface}, - {"native_setRasterizer","(JJ)J", (void*) PaintGlue::setRasterizer}, - {"native_getTextAlign","(J)I", (void*) PaintGlue::getTextAlign}, - {"native_setTextAlign","(JI)V", (void*) PaintGlue::setTextAlign}, - {"native_setTextLocale","(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale}, - {"isElegantTextHeight","()Z", (void*) PaintGlue::isElegantTextHeight}, - {"setElegantTextHeight","(Z)V", (void*) PaintGlue::setElegantTextHeight}, - {"getTextSize","()F", (void*) PaintGlue::getTextSize}, - {"setTextSize","(F)V", (void*) PaintGlue::setTextSize}, - {"getTextScaleX","()F", (void*) PaintGlue::getTextScaleX}, - {"setTextScaleX","(F)V", (void*) PaintGlue::setTextScaleX}, - {"getTextSkewX","()F", (void*) PaintGlue::getTextSkewX}, - {"setTextSkewX","(F)V", (void*) PaintGlue::setTextSkewX}, - {"native_getLetterSpacing","(J)F", (void*) PaintGlue::getLetterSpacing}, - {"native_setLetterSpacing","(JF)V", (void*) PaintGlue::setLetterSpacing}, + + {"native_reset","!(J)V", (void*) PaintGlue::reset}, + {"native_set","!(JJ)V", (void*) PaintGlue::assign}, + {"getFlags","!()I", (void*) PaintGlue::getFlags}, + {"setFlags","!(I)V", (void*) PaintGlue::setFlags}, + {"getHinting","!()I", (void*) PaintGlue::getHinting}, + {"setHinting","!(I)V", (void*) PaintGlue::setHinting}, + {"setAntiAlias","!(Z)V", (void*) PaintGlue::setAntiAlias}, + {"setSubpixelText","!(Z)V", (void*) PaintGlue::setSubpixelText}, + {"setLinearText","!(Z)V", (void*) PaintGlue::setLinearText}, + {"setUnderlineText","!(Z)V", (void*) PaintGlue::setUnderlineText}, + {"setStrikeThruText","!(Z)V", (void*) PaintGlue::setStrikeThruText}, + {"setFakeBoldText","!(Z)V", (void*) PaintGlue::setFakeBoldText}, + {"setFilterBitmap","!(Z)V", (void*) PaintGlue::setFilterBitmap}, + {"setDither","!(Z)V", (void*) PaintGlue::setDither}, + {"native_getStyle","!(J)I", (void*) PaintGlue::getStyle}, + {"native_setStyle","!(JI)V", (void*) PaintGlue::setStyle}, + {"getColor","!()I", (void*) PaintGlue::getColor}, + {"setColor","!(I)V", (void*) PaintGlue::setColor}, + {"getAlpha","!()I", (void*) PaintGlue::getAlpha}, + {"setAlpha","!(I)V", (void*) PaintGlue::setAlpha}, + {"getStrokeWidth","!()F", (void*) PaintGlue::getStrokeWidth}, + {"setStrokeWidth","!(F)V", (void*) PaintGlue::setStrokeWidth}, + {"getStrokeMiter","!()F", (void*) PaintGlue::getStrokeMiter}, + {"setStrokeMiter","!(F)V", (void*) PaintGlue::setStrokeMiter}, + {"native_getStrokeCap","!(J)I", (void*) PaintGlue::getStrokeCap}, + {"native_setStrokeCap","!(JI)V", (void*) PaintGlue::setStrokeCap}, + {"native_getStrokeJoin","!(J)I", (void*) PaintGlue::getStrokeJoin}, + {"native_setStrokeJoin","!(JI)V", (void*) PaintGlue::setStrokeJoin}, + {"native_getFillPath","!(JJJ)Z", (void*) PaintGlue::getFillPath}, + {"native_setShader","!(JJ)J", (void*) PaintGlue::setShader}, + {"native_setColorFilter","!(JJ)J", (void*) PaintGlue::setColorFilter}, + {"native_setXfermode","!(JJ)J", (void*) PaintGlue::setXfermode}, + {"native_setPathEffect","!(JJ)J", (void*) PaintGlue::setPathEffect}, + {"native_setMaskFilter","!(JJ)J", (void*) PaintGlue::setMaskFilter}, + {"native_setTypeface","!(JJ)J", (void*) PaintGlue::setTypeface}, + {"native_setRasterizer","!(JJ)J", (void*) PaintGlue::setRasterizer}, + {"native_getTextAlign","!(J)I", (void*) PaintGlue::getTextAlign}, + {"native_setTextAlign","!(JI)V", (void*) PaintGlue::setTextAlign}, + {"native_setTextLocale","!(JLjava/lang/String;)V", (void*) PaintGlue::setTextLocale}, + {"isElegantTextHeight","!()Z", (void*) PaintGlue::isElegantTextHeight}, + {"setElegantTextHeight","!(Z)V", (void*) PaintGlue::setElegantTextHeight}, + {"getTextSize","!()F", (void*) PaintGlue::getTextSize}, + {"setTextSize","!(F)V", (void*) PaintGlue::setTextSize}, + {"getTextScaleX","!()F", (void*) PaintGlue::getTextScaleX}, + {"setTextScaleX","!(F)V", (void*) PaintGlue::setTextScaleX}, + {"getTextSkewX","!()F", (void*) PaintGlue::getTextSkewX}, + {"setTextSkewX","!(F)V", (void*) PaintGlue::setTextSkewX}, + {"native_getLetterSpacing","!(J)F", (void*) PaintGlue::getLetterSpacing}, + {"native_setLetterSpacing","!(JF)V", (void*) PaintGlue::setLetterSpacing}, {"native_setFontFeatureSettings","(JLjava/lang/String;)V", (void*) PaintGlue::setFontFeatureSettings}, - {"ascent","()F", (void*) PaintGlue::ascent}, - {"descent","()F", (void*) PaintGlue::descent}, + {"ascent","!()F", (void*) PaintGlue::ascent}, + {"descent","!()F", (void*) PaintGlue::descent}, + {"getFontMetrics", "(Landroid/graphics/Paint$FontMetrics;)F", (void*)PaintGlue::getFontMetrics}, {"getFontMetricsInt", "(Landroid/graphics/Paint$FontMetricsInt;)I", (void*)PaintGlue::getFontMetricsInt}, {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII}, @@ -1014,8 +1016,9 @@ static JNINativeMethod methods[] = { (void*) PaintGlue::getStringBounds }, {"nativeGetCharArrayBounds", "(JJ[CIIILandroid/graphics/Rect;)V", (void*) PaintGlue::getCharArrayBounds }, - {"native_setShadowLayer", "(JFFFI)V", (void*)PaintGlue::setShadowLayer}, - {"native_hasShadowLayer", "(J)Z", (void*)PaintGlue::hasShadowLayer} + + {"native_setShadowLayer", "!(JFFFI)V", (void*)PaintGlue::setShadowLayer}, + {"native_hasShadowLayer", "!(J)Z", (void*)PaintGlue::hasShadowLayer} }; static jfieldID req_fieldID(jfieldID id) { diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index f8bab24..4cff56d 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -48,13 +48,20 @@ struct fields_t { jfieldID canDisableShutterSound; jfieldID face_rect; jfieldID face_score; + jfieldID face_id; + jfieldID face_left_eye; + jfieldID face_right_eye; + jfieldID face_mouth; jfieldID rect_left; jfieldID rect_top; jfieldID rect_right; jfieldID rect_bottom; + jfieldID point_x; + jfieldID point_y; jmethodID post_event; jmethodID rect_constructor; jmethodID face_constructor; + jmethodID point_constructor; }; static fields_t fields; @@ -88,6 +95,7 @@ private: sp<Camera> mCamera; // strong reference to native object jclass mFaceClass; // strong reference to Face class jclass mRectClass; // strong reference to Rect class + jclass mPointClass; // strong reference to Point class Mutex mLock; /* @@ -144,6 +152,9 @@ JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, jclass rectClazz = env->FindClass("android/graphics/Rect"); mRectClass = (jclass) env->NewGlobalRef(rectClazz); + jclass pointClazz = env->FindClass("android/graphics/Point"); + mPointClass = (jclass) env->NewGlobalRef(pointClazz); + mManualBufferMode = false; mManualCameraCallbackSet = false; } @@ -170,6 +181,10 @@ void JNICameraContext::release() env->DeleteGlobalRef(mRectClass); mRectClass = NULL; } + if (mPointClass != NULL) { + env->DeleteGlobalRef(mPointClass); + mPointClass = NULL; + } clearCallbackBuffers_l(env); mCamera.clear(); } @@ -356,6 +371,33 @@ void JNICameraContext::postMetadata(JNIEnv *env, int32_t msgType, camera_frame_m env->SetObjectField(face, fields.face_rect, rect); env->SetIntField(face, fields.face_score, metadata->faces[i].score); + bool optionalFields = metadata->faces[i].id != 0 + && metadata->faces[i].left_eye[0] != -2000 && metadata->faces[i].left_eye[1] != -2000 + && metadata->faces[i].right_eye[0] != -2000 && metadata->faces[i].right_eye[1] != -2000 + && metadata->faces[i].mouth[0] != -2000 && metadata->faces[i].mouth[1] != -2000; + if (optionalFields) { + int32_t id = metadata->faces[i].id; + env->SetIntField(face, fields.face_id, id); + + jobject leftEye = env->NewObject(mPointClass, fields.point_constructor); + env->SetIntField(leftEye, fields.point_x, metadata->faces[i].left_eye[0]); + env->SetIntField(leftEye, fields.point_y, metadata->faces[i].left_eye[1]); + env->SetObjectField(face, fields.face_left_eye, leftEye); + env->DeleteLocalRef(leftEye); + + jobject rightEye = env->NewObject(mPointClass, fields.point_constructor); + env->SetIntField(rightEye, fields.point_x, metadata->faces[i].right_eye[0]); + env->SetIntField(rightEye, fields.point_y, metadata->faces[i].right_eye[1]); + env->SetObjectField(face, fields.face_right_eye, rightEye); + env->DeleteLocalRef(rightEye); + + jobject mouth = env->NewObject(mPointClass, fields.point_constructor); + env->SetIntField(mouth, fields.point_x, metadata->faces[i].mouth[0]); + env->SetIntField(mouth, fields.point_y, metadata->faces[i].mouth[1]); + env->SetObjectField(face, fields.face_mouth, mouth); + env->DeleteLocalRef(mouth); + } + env->DeleteLocalRef(face); env->DeleteLocalRef(rect); } @@ -1020,11 +1062,17 @@ int register_android_hardware_Camera(JNIEnv *env) { "android/hardware/Camera$CameraInfo", "canDisableShutterSound", "Z", &fields.canDisableShutterSound }, { "android/hardware/Camera$Face", "rect", "Landroid/graphics/Rect;", &fields.face_rect }, + { "android/hardware/Camera$Face", "leftEye", "Landroid/graphics/Point;", &fields.face_left_eye}, + { "android/hardware/Camera$Face", "rightEye", "Landroid/graphics/Point;", &fields.face_right_eye}, + { "android/hardware/Camera$Face", "mouth", "Landroid/graphics/Point;", &fields.face_mouth}, { "android/hardware/Camera$Face", "score", "I", &fields.face_score }, + { "android/hardware/Camera$Face", "id", "I", &fields.face_id}, { "android/graphics/Rect", "left", "I", &fields.rect_left }, { "android/graphics/Rect", "top", "I", &fields.rect_top }, { "android/graphics/Rect", "right", "I", &fields.rect_right }, { "android/graphics/Rect", "bottom", "I", &fields.rect_bottom }, + { "android/graphics/Point", "x", "I", &fields.point_x}, + { "android/graphics/Point", "y", "I", &fields.point_y}, }; if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0) @@ -1052,6 +1100,13 @@ int register_android_hardware_Camera(JNIEnv *env) return -1; } + clazz = env->FindClass("android/graphics/Point"); + fields.point_constructor = env->GetMethodID(clazz, "<init>", "()V"); + if (fields.point_constructor == NULL) { + ALOGE("Can't find android/graphics/Point()"); + return -1; + } + // Register native functions return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera", camMethods, NELEM(camMethods)); diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp index 7b3528b..9ec9993 100644 --- a/core/jni/android_os_Debug.cpp +++ b/core/jni/android_os_Debug.cpp @@ -552,6 +552,10 @@ enum { MEMINFO_SWAP_TOTAL, MEMINFO_SWAP_FREE, MEMINFO_ZRAM_TOTAL, + MEMINFO_MAPPED, + MEMINFO_VMALLOC_USED, + MEMINFO_PAGE_TABLES, + MEMINFO_KERNEL_STACK, MEMINFO_COUNT }; @@ -590,6 +594,11 @@ static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray o "Slab:", "SwapTotal:", "SwapFree:", + "ZRam:", + "Mapped:", + "VmallocUsed:", + "PageTables:", + "KernelStack:", NULL }; static const int tagsLen[] = { @@ -601,12 +610,17 @@ static void android_os_Debug_getMemInfo(JNIEnv *env, jobject clazz, jlongArray o 5, 10, 9, + 5, + 7, + 12, + 11, + 12, 0 }; - long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + long mem[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; char* p = buffer; - while (*p && numFound < 8) { + while (*p && numFound < 13) { int i = 0; while (tags[i]) { if (strncmp(p, tags[i], tagsLen[i]) == 0) { diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp index 050037e..621df72 100644 --- a/core/jni/android_view_RenderNode.cpp +++ b/core/jni/android_view_RenderNode.cpp @@ -483,68 +483,68 @@ static JNINativeMethod gMethods[] = { { "nOutput", "(J)V", (void*) android_view_RenderNode_output }, { "nGetDebugSize", "(J)I", (void*) android_view_RenderNode_getDebugSize }, - { "nSetLayerType", "(JI)Z", (void*) android_view_RenderNode_setLayerType }, - { "nSetLayerPaint", "(JJ)Z", (void*) android_view_RenderNode_setLayerPaint }, - { "nSetStaticMatrix", "(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix }, - { "nSetAnimationMatrix", "(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix }, - { "nSetClipToBounds", "(JZ)Z", (void*) android_view_RenderNode_setClipToBounds }, - { "nSetClipBounds", "(JIIII)Z", (void*) android_view_RenderNode_setClipBounds }, - { "nSetClipBoundsEmpty", "(J)Z", (void*) android_view_RenderNode_setClipBoundsEmpty }, - { "nSetProjectBackwards", "(JZ)Z", (void*) android_view_RenderNode_setProjectBackwards }, - { "nSetProjectionReceiver","(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver }, + { "nSetLayerType", "!(JI)Z", (void*) android_view_RenderNode_setLayerType }, + { "nSetLayerPaint", "!(JJ)Z", (void*) android_view_RenderNode_setLayerPaint }, + { "nSetStaticMatrix", "!(JJ)Z", (void*) android_view_RenderNode_setStaticMatrix }, + { "nSetAnimationMatrix", "!(JJ)Z", (void*) android_view_RenderNode_setAnimationMatrix }, + { "nSetClipToBounds", "!(JZ)Z", (void*) android_view_RenderNode_setClipToBounds }, + { "nSetClipBounds", "!(JIIII)Z", (void*) android_view_RenderNode_setClipBounds }, + { "nSetClipBoundsEmpty", "!(J)Z", (void*) android_view_RenderNode_setClipBoundsEmpty }, + { "nSetProjectBackwards", "!(JZ)Z", (void*) android_view_RenderNode_setProjectBackwards }, + { "nSetProjectionReceiver","!(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver }, { "nSetOutlineRoundRect", "(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect }, { "nSetOutlineConvexPath", "(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath }, { "nSetOutlineEmpty", "(J)Z", (void*) android_view_RenderNode_setOutlineEmpty }, { "nSetOutlineNone", "(J)Z", (void*) android_view_RenderNode_setOutlineNone }, - { "nHasShadow", "(J)Z", (void*) android_view_RenderNode_hasShadow }, - { "nSetClipToOutline", "(JZ)Z", (void*) android_view_RenderNode_setClipToOutline }, + { "nHasShadow", "!(J)Z", (void*) android_view_RenderNode_hasShadow }, + { "nSetClipToOutline", "!(JZ)Z", (void*) android_view_RenderNode_setClipToOutline }, { "nSetRevealClip", "(JZFFF)Z", (void*) android_view_RenderNode_setRevealClip }, - { "nSetAlpha", "(JF)Z", (void*) android_view_RenderNode_setAlpha }, - { "nSetHasOverlappingRendering", "(JZ)Z", + { "nSetAlpha", "!(JF)Z", (void*) android_view_RenderNode_setAlpha }, + { "nSetHasOverlappingRendering", "!(JZ)Z", (void*) android_view_RenderNode_setHasOverlappingRendering }, - { "nSetElevation", "(JF)Z", (void*) android_view_RenderNode_setElevation }, - { "nSetTranslationX", "(JF)Z", (void*) android_view_RenderNode_setTranslationX }, - { "nSetTranslationY", "(JF)Z", (void*) android_view_RenderNode_setTranslationY }, - { "nSetTranslationZ", "(JF)Z", (void*) android_view_RenderNode_setTranslationZ }, - { "nSetRotation", "(JF)Z", (void*) android_view_RenderNode_setRotation }, - { "nSetRotationX", "(JF)Z", (void*) android_view_RenderNode_setRotationX }, - { "nSetRotationY", "(JF)Z", (void*) android_view_RenderNode_setRotationY }, - { "nSetScaleX", "(JF)Z", (void*) android_view_RenderNode_setScaleX }, - { "nSetScaleY", "(JF)Z", (void*) android_view_RenderNode_setScaleY }, - { "nSetPivotX", "(JF)Z", (void*) android_view_RenderNode_setPivotX }, - { "nSetPivotY", "(JF)Z", (void*) android_view_RenderNode_setPivotY }, - { "nSetCameraDistance", "(JF)Z", (void*) android_view_RenderNode_setCameraDistance }, - { "nSetLeft", "(JI)Z", (void*) android_view_RenderNode_setLeft }, - { "nSetTop", "(JI)Z", (void*) android_view_RenderNode_setTop }, - { "nSetRight", "(JI)Z", (void*) android_view_RenderNode_setRight }, - { "nSetBottom", "(JI)Z", (void*) android_view_RenderNode_setBottom }, - { "nSetLeftTopRightBottom","(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom }, - { "nOffsetLeftAndRight", "(JI)Z", (void*) android_view_RenderNode_offsetLeftAndRight }, - { "nOffsetTopAndBottom", "(JI)Z", (void*) android_view_RenderNode_offsetTopAndBottom }, - - { "nHasOverlappingRendering", "(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering }, - { "nGetClipToOutline", "(J)Z", (void*) android_view_RenderNode_getClipToOutline }, - { "nGetAlpha", "(J)F", (void*) android_view_RenderNode_getAlpha }, - { "nGetCameraDistance", "(J)F", (void*) android_view_RenderNode_getCameraDistance }, - { "nGetScaleX", "(J)F", (void*) android_view_RenderNode_getScaleX }, - { "nGetScaleY", "(J)F", (void*) android_view_RenderNode_getScaleY }, - { "nGetElevation", "(J)F", (void*) android_view_RenderNode_getElevation }, - { "nGetTranslationX", "(J)F", (void*) android_view_RenderNode_getTranslationX }, - { "nGetTranslationY", "(J)F", (void*) android_view_RenderNode_getTranslationY }, - { "nGetTranslationZ", "(J)F", (void*) android_view_RenderNode_getTranslationZ }, - { "nGetRotation", "(J)F", (void*) android_view_RenderNode_getRotation }, - { "nGetRotationX", "(J)F", (void*) android_view_RenderNode_getRotationX }, - { "nGetRotationY", "(J)F", (void*) android_view_RenderNode_getRotationY }, - { "nIsPivotExplicitlySet", "(J)Z", (void*) android_view_RenderNode_isPivotExplicitlySet }, - { "nHasIdentityMatrix", "(J)Z", (void*) android_view_RenderNode_hasIdentityMatrix }, - - { "nGetTransformMatrix", "(JJ)V", (void*) android_view_RenderNode_getTransformMatrix }, - { "nGetInverseTransformMatrix","(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix }, - - { "nGetPivotX", "(J)F", (void*) android_view_RenderNode_getPivotX }, - { "nGetPivotY", "(J)F", (void*) android_view_RenderNode_getPivotY }, + { "nSetElevation", "!(JF)Z", (void*) android_view_RenderNode_setElevation }, + { "nSetTranslationX", "!(JF)Z", (void*) android_view_RenderNode_setTranslationX }, + { "nSetTranslationY", "!(JF)Z", (void*) android_view_RenderNode_setTranslationY }, + { "nSetTranslationZ", "!(JF)Z", (void*) android_view_RenderNode_setTranslationZ }, + { "nSetRotation", "!(JF)Z", (void*) android_view_RenderNode_setRotation }, + { "nSetRotationX", "!(JF)Z", (void*) android_view_RenderNode_setRotationX }, + { "nSetRotationY", "!(JF)Z", (void*) android_view_RenderNode_setRotationY }, + { "nSetScaleX", "!(JF)Z", (void*) android_view_RenderNode_setScaleX }, + { "nSetScaleY", "!(JF)Z", (void*) android_view_RenderNode_setScaleY }, + { "nSetPivotX", "!(JF)Z", (void*) android_view_RenderNode_setPivotX }, + { "nSetPivotY", "!(JF)Z", (void*) android_view_RenderNode_setPivotY }, + { "nSetCameraDistance", "!(JF)Z", (void*) android_view_RenderNode_setCameraDistance }, + { "nSetLeft", "!(JI)Z", (void*) android_view_RenderNode_setLeft }, + { "nSetTop", "!(JI)Z", (void*) android_view_RenderNode_setTop }, + { "nSetRight", "!(JI)Z", (void*) android_view_RenderNode_setRight }, + { "nSetBottom", "!(JI)Z", (void*) android_view_RenderNode_setBottom }, + { "nSetLeftTopRightBottom","!(JIIII)Z", (void*) android_view_RenderNode_setLeftTopRightBottom }, + { "nOffsetLeftAndRight", "!(JI)Z", (void*) android_view_RenderNode_offsetLeftAndRight }, + { "nOffsetTopAndBottom", "!(JI)Z", (void*) android_view_RenderNode_offsetTopAndBottom }, + + { "nHasOverlappingRendering", "!(J)Z", (void*) android_view_RenderNode_hasOverlappingRendering }, + { "nGetClipToOutline", "!(J)Z", (void*) android_view_RenderNode_getClipToOutline }, + { "nGetAlpha", "!(J)F", (void*) android_view_RenderNode_getAlpha }, + { "nGetCameraDistance", "!(J)F", (void*) android_view_RenderNode_getCameraDistance }, + { "nGetScaleX", "!(J)F", (void*) android_view_RenderNode_getScaleX }, + { "nGetScaleY", "!(J)F", (void*) android_view_RenderNode_getScaleY }, + { "nGetElevation", "!(J)F", (void*) android_view_RenderNode_getElevation }, + { "nGetTranslationX", "!(J)F", (void*) android_view_RenderNode_getTranslationX }, + { "nGetTranslationY", "!(J)F", (void*) android_view_RenderNode_getTranslationY }, + { "nGetTranslationZ", "!(J)F", (void*) android_view_RenderNode_getTranslationZ }, + { "nGetRotation", "!(J)F", (void*) android_view_RenderNode_getRotation }, + { "nGetRotationX", "!(J)F", (void*) android_view_RenderNode_getRotationX }, + { "nGetRotationY", "!(J)F", (void*) android_view_RenderNode_getRotationY }, + { "nIsPivotExplicitlySet", "!(J)Z", (void*) android_view_RenderNode_isPivotExplicitlySet }, + { "nHasIdentityMatrix", "!(J)Z", (void*) android_view_RenderNode_hasIdentityMatrix }, + + { "nGetTransformMatrix", "!(JJ)V", (void*) android_view_RenderNode_getTransformMatrix }, + { "nGetInverseTransformMatrix","!(JJ)V", (void*) android_view_RenderNode_getInverseTransformMatrix }, + + { "nGetPivotX", "!(J)F", (void*) android_view_RenderNode_getPivotX }, + { "nGetPivotY", "!(J)F", (void*) android_view_RenderNode_getPivotY }, { "nAddAnimator", "(JJ)V", (void*) android_view_RenderNode_addAnimator }, { "nEndAllAnimators", "(J)V", (void*) android_view_RenderNode_endAllAnimators }, diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp index 9bb8195..a0b2ca8 100644 --- a/core/jni/android_view_Surface.cpp +++ b/core/jni/android_view_Surface.cpp @@ -47,6 +47,11 @@ #include <ScopedUtfChars.h> +#include <AnimationContext.h> +#include <DisplayListRenderer.h> +#include <RenderNode.h> +#include <renderthread/RenderProxy.h> + // ---------------------------------------------------------------------------- namespace android { @@ -352,8 +357,54 @@ static void nativeWriteToParcel(JNIEnv* env, jclass clazz, parcel->writeStrongBinder( self != 0 ? self->getIGraphicBufferProducer()->asBinder() : NULL); } +namespace uirenderer { + +using namespace android::uirenderer::renderthread; + +class ContextFactory : public IContextFactory { +public: + virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) { + return new AnimationContext(clock); + } +}; + +static jlong create(JNIEnv* env, jclass clazz, jlong rootNodePtr, jlong surfacePtr) { + RenderNode* rootNode = reinterpret_cast<RenderNode*>(rootNodePtr); + sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr)); + ContextFactory factory; + RenderProxy* proxy = new RenderProxy(false, rootNode, &factory); + proxy->loadSystemProperties(); + proxy->setSwapBehavior(kSwap_discardBuffer); + proxy->initialize(surface); + // Shadows can't be used via this interface, so just set the light source + // to all 0s. (and width & height are unused, TODO remove them) + proxy->setup(0, 0, (Vector3){0, 0, 0}, 0, 0, 0); + return (jlong) proxy; +} + +static void setSurface(JNIEnv* env, jclass clazz, jlong rendererPtr, jlong surfacePtr) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr); + sp<Surface> surface(reinterpret_cast<Surface*>(surfacePtr)); + proxy->updateSurface(surface); +} + +static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr); + nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC); + proxy->syncAndDrawFrame(frameTimeNs, 0, 1.0f); +} + +static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) { + RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr); + delete proxy; +} + +} // uirenderer + // ---------------------------------------------------------------------------- +namespace hwui = android::uirenderer; + static JNINativeMethod gSurfaceMethods[] = { {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J", (void*)nativeCreateFromSurfaceTexture }, @@ -375,6 +426,12 @@ static JNINativeMethod gSurfaceMethods[] = { (void*)nativeReadFromParcel }, {"nativeWriteToParcel", "(JLandroid/os/Parcel;)V", (void*)nativeWriteToParcel }, + + // HWUI context + {"nHwuiCreate", "(JJ)J", (void*) hwui::create }, + {"nHwuiSetSurface", "(JJ)V", (void*) hwui::setSurface }, + {"nHwuiDraw", "(J)V", (void*) hwui::draw }, + {"nHwuiDestroy", "(J)V", (void*) hwui::destroy }, }; int register_android_view_Surface(JNIEnv* env) diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f35b2e8..8e0cd52 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -271,6 +271,8 @@ <protected-broadcast android:name="android.intent.action.PHONE_STATE" /> + <protected-broadcast android:name="android.intent.action.SUB_DEFAULT_CHANGED" /> + <protected-broadcast android:name="android.location.GPS_ENABLED_CHANGE" /> <protected-broadcast android:name="android.location.PROVIDERS_CHANGED" /> <protected-broadcast android:name="android.location.MODE_CHANGED" /> @@ -291,6 +293,15 @@ <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_PROGRESS" /> <protected-broadcast android:name="android.nfc.handover.intent.action.TRANSFER_DONE" /> + <protected-broadcast android:name="android.intent.action.ACTION_DEFAULT_SUBSCRIPTION_CHANGED" /> + <protected-broadcast android:name="android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED" /> + <protected-broadcast android:name="android.intent.action.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED" /> + <protected-broadcast android:name="android.intent.action.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED" /> + <protected-broadcast android:name="android.intent.action.ACTION_SUBINFO_CONTENT_CHANGE" /> + <protected-broadcast android:name="android.intent.action.ACTION_SUBINFO_RECORD_UPDATED" /> + + <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE" /> + <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" /> <!-- ====================================== --> <!-- Permissions for things that cost money --> @@ -1080,6 +1091,14 @@ android:label="@string/permlab_hardware_test" android:description="@string/permdesc_hardware_test" /> + <!-- @SystemApi Allows access to FM + @hide This is not a third-party API (intended for system apps).--> + <permission android:name="android.permission.ACCESS_FM_RADIO" + android:permissionGroup="android.permission-group.HARDWARE_CONTROLS" + android:protectionLevel="signature|system" + android:label="@string/permlab_fm" + android:description="@string/permdesc_fm" /> + <!-- Allows access to configure network interfaces, configure/use IPSec, etc. @hide --> <permission android:name="android.permission.NET_ADMIN" @@ -1250,6 +1269,18 @@ android:description="@string/permdesc_use_sip" android:label="@string/permlab_use_sip" /> + <!-- Protects the ability to register any PhoneAccount with a capability flags of either + PhoneAccount#CAPABILITY_CALL_PROVIDER or PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. --> + <permission android:name="android.permission.REGISTER_PROVIDER_OR_SUBSCRIPTION" + android:permissionGroup="android.permission-group.PHONE_CALLS" + android:description="@string/permdesc_register_provider" + android:label="@string/permlab_register_provider" /> + + <permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" + android:permissionGroup="android.permission-group.PHONE_CALLS" + android:description="@string/permdesc_connection_manager" + android:label="@string/permlab_connection_manager" /> + <!-- @SystemApi Allows an application to bind to InCallService implementations. @hide --> <permission android:name="android.permission.BIND_INCALL_SERVICE" diff --git a/core/res/res/anim/activity_close_exit.xml b/core/res/res/anim/activity_close_exit.xml index 52c3adf..d8c42ed 100644 --- a/core/res/res/anim/activity_close_exit.xml +++ b/core/res/res/anim/activity_close_exit.xml @@ -20,13 +20,13 @@ <set xmlns:android="http://schemas.android.com/apk/res/android" android:shareInterpolator="false" android:zAdjustment="top"> <alpha android:fromAlpha="1.0" android:toAlpha="0.0" - android:interpolator="@interpolator/accelerate_quart" + android:interpolator="@interpolator/linear" android:fillEnabled="true" android:fillBefore="false" android:fillAfter="true" android:startOffset="100" android:duration="150"/> - <translate android:fromYDelta="0%" android:toYDelta="5%" + <translate android:fromYDelta="0%" android:toYDelta="8%" android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true" - android:interpolator="@interpolator/accelerate_quint" + android:interpolator="@interpolator/accelerate_quart" android:duration="250"/> </set>
\ No newline at end of file diff --git a/core/res/res/animator/fragment_close_enter.xml b/core/res/res/animator/fragment_close_enter.xml index 0b2e2cf..dccf372 100644 --- a/core/res/res/animator/fragment_close_enter.xml +++ b/core/res/res/animator/fragment_close_enter.xml @@ -13,13 +13,14 @@ ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and -** limitations under the License. +** limitations under the License. */ --> -<set xmlns:android="http://schemas.android.com/apk/res/android" android:zAdjustment="normal"> - <objectAnimator - android:interpolator="@interpolator/decelerate_quad" - android:valueFrom="0.0" android:valueTo="1.0" +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <objectAnimator + android:interpolator="@interpolator/decelerate_cubic" + android:valueFrom="0" + android:valueTo="1" android:valueType="floatType" android:propertyName="alpha" android:duration="300"/> diff --git a/core/res/res/animator/fragment_close_exit.xml b/core/res/res/animator/fragment_close_exit.xml index e0ab607..ddede70 100644 --- a/core/res/res/animator/fragment_close_exit.xml +++ b/core/res/res/animator/fragment_close_exit.xml @@ -13,25 +13,14 @@ ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and -** limitations under the License. +** limitations under the License. */ --> -<set xmlns:android="http://schemas.android.com/apk/res/android" android:zAdjustment="top"> - <objectAnimator - android:interpolator="@interpolator/decelerate_quad" - android:valueFrom="1.0" android:valueTo="0.8" - android:valueType="floatType" - android:propertyName="scaleY" - android:duration="300"/> - <objectAnimator - android:interpolator="@interpolator/decelerate_quad" - android:valueFrom="1.0" android:valueTo="0.8" - android:valueType="floatType" - android:propertyName="scaleX" - android:duration="300"/> +<set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator - android:interpolator="@interpolator/decelerate_quad" - android:valueFrom="1.0" android:valueTo="0.0" + android:interpolator="@interpolator/decelerate_cubic" + android:valueFrom="1" + android:valueTo="0" android:valueType="floatType" android:propertyName="alpha" android:duration="300"/> diff --git a/core/res/res/animator/fragment_fade_enter.xml b/core/res/res/animator/fragment_fade_enter.xml index 13b15f3..ce8913e 100644 --- a/core/res/res/animator/fragment_fade_enter.xml +++ b/core/res/res/animator/fragment_fade_enter.xml @@ -16,8 +16,7 @@ ** limitations under the License. */ --> -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:zAdjustment="top"> +<set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:interpolator="@interpolator/decelerate_cubic" android:valueFrom="0" diff --git a/core/res/res/animator/fragment_fade_exit.xml b/core/res/res/animator/fragment_fade_exit.xml index 503b7ad..f0fbd15 100644 --- a/core/res/res/animator/fragment_fade_exit.xml +++ b/core/res/res/animator/fragment_fade_exit.xml @@ -16,8 +16,7 @@ ** limitations under the License. */ --> -<set xmlns:android="http://schemas.android.com/apk/res/android" - android:zAdjustment="normal"> +<set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:interpolator="@interpolator/decelerate_cubic" android:valueFrom="1" diff --git a/core/res/res/animator/fragment_open_enter.xml b/core/res/res/animator/fragment_open_enter.xml index 4ae24b9..dccf372 100644 --- a/core/res/res/animator/fragment_open_enter.xml +++ b/core/res/res/animator/fragment_open_enter.xml @@ -13,25 +13,14 @@ ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and -** limitations under the License. +** limitations under the License. */ --> <set xmlns:android="http://schemas.android.com/apk/res/android"> - <objectAnimator - android:interpolator="@interpolator/decelerate_cubic" - android:valueFrom="0.95" android:valueTo="1.0" - android:valueType="floatType" - android:propertyName="scaleY" - android:duration="300"/> - <objectAnimator - android:interpolator="@interpolator/decelerate_cubic" - android:valueFrom="0.95" android:valueTo="1.0" - android:valueType="floatType" - android:propertyName="scaleX" - android:duration="300"/> <objectAnimator android:interpolator="@interpolator/decelerate_cubic" - android:valueFrom="0.0" android:valueTo="1.0" + android:valueFrom="0" + android:valueTo="1" android:valueType="floatType" android:propertyName="alpha" android:duration="300"/> diff --git a/core/res/res/animator/fragment_open_exit.xml b/core/res/res/animator/fragment_open_exit.xml index 1b505fe..ddede70 100644 --- a/core/res/res/animator/fragment_open_exit.xml +++ b/core/res/res/animator/fragment_open_exit.xml @@ -13,13 +13,14 @@ ** distributed under the License is distributed on an "AS IS" BASIS, ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ** See the License for the specific language governing permissions and -** limitations under the License. +** limitations under the License. */ --> <set xmlns:android="http://schemas.android.com/apk/res/android"> - <objectAnimator + <objectAnimator android:interpolator="@interpolator/decelerate_cubic" - android:valueFrom="1.0" android:valueTo="0.0" + android:valueFrom="1" + android:valueTo="0" android:valueType="floatType" android:propertyName="alpha" android:duration="300"/> diff --git a/core/res/res/drawable-hdpi/ic_text_dot.png b/core/res/res/drawable-hdpi/ic_text_dot.png Binary files differdeleted file mode 100644 index fa69c69..0000000 --- a/core/res/res/drawable-hdpi/ic_text_dot.png +++ /dev/null diff --git a/core/res/res/drawable-ldpi/ic_text_dot.png b/core/res/res/drawable-ldpi/ic_text_dot.png Binary files differdeleted file mode 100644 index 4aff20c..0000000 --- a/core/res/res/drawable-ldpi/ic_text_dot.png +++ /dev/null diff --git a/core/res/res/drawable-mdpi/ic_text_dot.png b/core/res/res/drawable-mdpi/ic_text_dot.png Binary files differdeleted file mode 100644 index 2225bd5..0000000 --- a/core/res/res/drawable-mdpi/ic_text_dot.png +++ /dev/null diff --git a/core/res/res/drawable-xhdpi/ic_text_dot.png b/core/res/res/drawable-xhdpi/ic_text_dot.png Binary files differdeleted file mode 100644 index 869dd95..0000000 --- a/core/res/res/drawable-xhdpi/ic_text_dot.png +++ /dev/null diff --git a/core/res/res/drawable-xxhdpi/ic_text_dot.png b/core/res/res/drawable-xxhdpi/ic_text_dot.png Binary files differdeleted file mode 100644 index a74c286..0000000 --- a/core/res/res/drawable-xxhdpi/ic_text_dot.png +++ /dev/null diff --git a/core/res/res/drawable/ic_text_dot.xml b/core/res/res/drawable/ic_text_dot.xml new file mode 100644 index 0000000..f8f3964 --- /dev/null +++ b/core/res/res/drawable/ic_text_dot.xml @@ -0,0 +1,22 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:inset="10dp"> + <shape android:shape="oval"> + <solid android:color="?android:attr/textColorSecondary" /> + <size android:width="4dp" android:height="4dp" /> + </shape> +</inset> diff --git a/core/res/res/drawable/vector_drawable_progress_bar_large.xml b/core/res/res/drawable/vector_drawable_progress_bar_large.xml index 023f5cc..cd678f1 100644 --- a/core/res/res/drawable/vector_drawable_progress_bar_large.xml +++ b/core/res/res/drawable/vector_drawable_progress_bar_large.xml @@ -17,7 +17,8 @@ android:height="76dp" android:width="76dp" android:viewportHeight="48" - android:viewportWidth="48" > + android:viewportWidth="48" + android:tint="?attr/colorControlActivated"> <group android:name="root" @@ -27,7 +28,7 @@ android:name="progressBar" android:fillColor="#00000000" android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38" - android:strokeColor="?attr/colorControlActivated" + android:strokeColor="@color/white" android:strokeLineCap="square" android:strokeLineJoin="miter" android:strokeWidth="4" diff --git a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml index e72097e..7f038f4 100644 --- a/core/res/res/drawable/vector_drawable_progress_bar_medium.xml +++ b/core/res/res/drawable/vector_drawable_progress_bar_medium.xml @@ -17,7 +17,8 @@ android:height="48dp" android:width="48dp" android:viewportHeight="48" - android:viewportWidth="48" > + android:viewportWidth="48" + android:tint="?attr/colorControlActivated"> <group android:name="root" @@ -27,7 +28,7 @@ android:name="progressBar" android:fillColor="#00000000" android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38" - android:strokeColor="?attr/colorControlActivated" + android:strokeColor="@color/white" android:strokeLineCap="square" android:strokeLineJoin="miter" android:strokeWidth="4" diff --git a/core/res/res/drawable/vector_drawable_progress_bar_small.xml b/core/res/res/drawable/vector_drawable_progress_bar_small.xml index 875e7a3..5625788 100644 --- a/core/res/res/drawable/vector_drawable_progress_bar_small.xml +++ b/core/res/res/drawable/vector_drawable_progress_bar_small.xml @@ -17,7 +17,8 @@ android:height="16dp" android:width="16dp" android:viewportHeight="48" - android:viewportWidth="48" > + android:viewportWidth="48" + android:tint="?attr/colorControlActivated"> <group android:name="root" @@ -27,7 +28,7 @@ android:name="progressBar" android:fillColor="#00000000" android:pathData="M0, 0 m 0, -19 a 19,19 0 1,1 0,38 a 19,19 0 1,1 0,-38" - android:strokeColor="?attr/colorControlActivated" + android:strokeColor="@color/white" android:strokeLineCap="square" android:strokeLineJoin="miter" android:strokeWidth="4" diff --git a/core/res/res/layout/simple_account_item.xml b/core/res/res/layout/simple_account_item.xml new file mode 100644 index 0000000..e7b746c --- /dev/null +++ b/core/res/res/layout/simple_account_item.xml @@ -0,0 +1,55 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + 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. +--> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:minHeight="?android:attr/listPreferredItemHeight" + android:gravity="center_vertical" + android:paddingStart="16dip" + android:paddingEnd="?android:attr/scrollbarSize"> + + <ImageView + android:id="@+android:id/icon" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center"/> + <RelativeLayout + android:layout_width="0dip" + android:layout_height="wrap_content" + android:layout_marginStart="10dip" + android:layout_marginEnd="6dip" + android:layout_marginTop="6dip" + android:layout_marginBottom="6dip" + android:layout_weight="1"> + <TextView android:id="@+android:id/title" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:singleLine="true" + android:ellipsize="none" + android:textAppearance="?android:attr/textAppearanceListItem" /> + <TextView android:id="@+android:id/summary" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_below="@android:id/title" + android:layout_alignStart="@android:id/title" + android:singleLine="true" + android:ellipsize="none" + android:textAppearance="?android:attr/textAppearanceListItemSecondary" + android:textColor="?android:attr/textColorSecondary"/> + </RelativeLayout> +</LinearLayout> diff --git a/core/res/res/layout/subscription_item_layout.xml b/core/res/res/layout/subscription_item_layout.xml index 9f8f2b3..aa835f4 100755 --- a/core/res/res/layout/subscription_item_layout.xml +++ b/core/res/res/layout/subscription_item_layout.xml @@ -36,7 +36,7 @@ android:id="@+id/sub_short_number" android:layout_marginBottom="2dip" android:layout_marginEnd="4dip" - android:layout_alignParentEnd="true" + android:layout_alignParentEnd="true" android:layout_alignParentBottom="true" android:textSize="12sp" android:singleLine="true" @@ -54,8 +54,6 @@ android:id="@+id/sub_name" android:singleLine="true" android:ellipsize="none" - android:requiresFadingEdge="horizontal" - android:scrollHorizontally="true" android:textAppearance="?android:attr/textAppearanceMedium"/> <TextView android:layout_width="wrap_content" @@ -65,8 +63,7 @@ android:layout_alignStart="@+id/sub_name" android:singleLine="true" android:ellipsize="none" - android:requiresFadingEdge="horizontal" android:textAppearance="?android:attr/textAppearanceSmall" android:textColor="?android:attr/textColorSecondary"/> </RelativeLayout> -</LinearLayout> +</LinearLayout>
\ No newline at end of file diff --git a/core/res/res/layout/time_header_label.xml b/core/res/res/layout/time_header_label.xml index 5c97040..efb3628 100644 --- a/core/res/res/layout/time_header_label.xml +++ b/core/res/res/layout/time_header_label.xml @@ -20,14 +20,13 @@ android:layout_height="match_parent"> <RelativeLayout android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="center"> + android:layout_height="match_parent"> <TextView android:id="@+id/hours" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toLeftOf="@+id/separator" - android:layout_alignBaseline="@+id/separator" /> + android:layout_centerVertical="true" /> <TextView android:id="@+id/separator" android:layout_width="wrap_content" @@ -41,14 +40,35 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/separator" - android:layout_alignBaseline="@+id/separator" /> - <TextView - android:id="@+id/ampm_label" + android:layout_centerVertical="true" /> + <LinearLayout + android:id="@+id/ampm_layout" + android:layout_alignBaseline="@+id/minutes" + android:layout_toEndOf="@+id/separator" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:paddingLeft="@dimen/timepicker_ampm_left_padding" - android:paddingRight="@dimen/timepicker_ampm_left_padding" - android:layout_toRightOf="@+id/separator" - android:layout_alignBaseline="@+id/separator" /> + android:baselineAlignedChildIndex="1" + android:orientation="vertical"> + <CheckedTextView + android:id="@+id/am_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingStart="@dimen/timepicker_ampm_horizontal_padding" + android:paddingTop="@dimen/timepicker_ampm_vertical_padding" + android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding" + android:paddingBottom="@dimen/timepicker_am_bottom_padding" + android:lines="1" + android:ellipsize="none" /> + <CheckedTextView + android:id="@+id/pm_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingStart="@dimen/timepicker_ampm_horizontal_padding" + android:paddingTop="@dimen/timepicker_pm_top_padding" + android:paddingEnd="@dimen/timepicker_ampm_horizontal_padding" + android:paddingBottom="@dimen/timepicker_ampm_vertical_padding" + android:lines="1" + android:ellipsize="none" /> + </LinearLayout> </RelativeLayout> </FrameLayout> diff --git a/core/res/res/values-mcc310-mnc120/config.xml b/core/res/res/values-mcc310-mnc120/config.xml index 24e55b1..774732d 100644 --- a/core/res/res/values-mcc310-mnc120/config.xml +++ b/core/res/res/values-mcc310-mnc120/config.xml @@ -27,4 +27,8 @@ <!-- Sprint need a 70 ms delay for 3way call --> <integer name="config_cdma_3waycall_flash_delay">70</integer> + + <!-- If this value is true, The mms content-disposition field is supported correctly. + If false, Content-disposition fragments are ignored --> + <bool name="config_mms_content_disposition_support">false</bool> </resources> diff --git a/core/res/res/values-mcc310-mnc160/config.xml b/core/res/res/values-mcc310-mnc160/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc160/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc200/config.xml b/core/res/res/values-mcc310-mnc200/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc200/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc210/config.xml b/core/res/res/values-mcc310-mnc210/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc210/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc220/config.xml b/core/res/res/values-mcc310-mnc220/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc220/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc230/config.xml b/core/res/res/values-mcc310-mnc230/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc230/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc240/config.xml b/core/res/res/values-mcc310-mnc240/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc240/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc250/config.xml b/core/res/res/values-mcc310-mnc250/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc250/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc260/config.xml b/core/res/res/values-mcc310-mnc260/config.xml index 28cd695..6bfc3d1 100644 --- a/core/res/res/values-mcc310-mnc260/config.xml +++ b/core/res/res/values-mcc310-mnc260/config.xml @@ -25,8 +25,8 @@ --> <integer name="config_mobile_mtu">1440</integer> - <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + <!-- Flag specifying whether VoLTE should be available for carrier: independent of carrier provisioning. If false: hard disabled. If true: then depends on carrier provisioning, availability etc --> - <bool name="config_carrier_volte_vt_available">true</bool> + <bool name="config_carrier_volte_available">true</bool> </resources> diff --git a/core/res/res/values-mcc310-mnc270/config.xml b/core/res/res/values-mcc310-mnc270/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc270/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc300/config.xml b/core/res/res/values-mcc310-mnc300/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc300/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc310/config.xml b/core/res/res/values-mcc310-mnc310/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc310/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc490/config.xml b/core/res/res/values-mcc310-mnc490/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc490/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc530/config.xml b/core/res/res/values-mcc310-mnc530/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc530/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc580/config.xml b/core/res/res/values-mcc310-mnc580/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc580/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc590/config.xml b/core/res/res/values-mcc310-mnc590/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc590/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc640/config.xml b/core/res/res/values-mcc310-mnc640/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc640/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc660/config.xml b/core/res/res/values-mcc310-mnc660/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc660/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc310-mnc800/config.xml b/core/res/res/values-mcc310-mnc800/config.xml new file mode 100644 index 0000000..28cd695 --- /dev/null +++ b/core/res/res/values-mcc310-mnc800/config.xml @@ -0,0 +1,32 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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. +** You my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + + <!-- Configure mobile network MTU. Carrier specific value is set here. + --> + <integer name="config_mobile_mtu">1440</integer> + + <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_vt_available">true</bool> +</resources> diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml index c2be340..d0a57b3 100644 --- a/core/res/res/values-mcc311-mnc480/config.xml +++ b/core/res/res/values-mcc311-mnc480/config.xml @@ -38,10 +38,10 @@ be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() --> <bool name="imsServiceAllowTurnOff">false</bool> - <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + <!-- Flag specifying whether VoLTE should be available for carrier: independent of carrier provisioning. If false: hard disabled. If true: then depends on carrier provisioning, availability etc --> - <bool name="config_carrier_volte_vt_available">false</bool> + <bool name="config_carrier_volte_available">true</bool> <bool name="config_auto_attach_data_on_creation">false</bool> <!-- service number convert map in roaming network. --> diff --git a/core/res/res/values-mcc530-mnc05/config.xml b/core/res/res/values-mcc530-mnc05/config.xml new file mode 100644 index 0000000..893afe5 --- /dev/null +++ b/core/res/res/values-mcc530-mnc05/config.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- +/* +** Copyright 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 my obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ +--> + +<!-- These resources are around just to allow their values to be customized + for different hardware and product builds. --> +<resources> + <!-- If this value is true, The mms content-disposition field is supported correctly. + If false, Content-disposition fragments are ignored --> + <bool name="config_mms_content_disposition_support">false</bool> +</resources> diff --git a/core/res/res/values-sw600dp/bools.xml b/core/res/res/values-sw600dp/bools.xml index ddc48c5..00f45c1 100644 --- a/core/res/res/values-sw600dp/bools.xml +++ b/core/res/res/values-sw600dp/bools.xml @@ -19,7 +19,6 @@ <bool name="show_ongoing_ime_switcher">true</bool> <bool name="kg_share_status_area">false</bool> <bool name="kg_sim_puk_account_full_screen">false</bool> - <bool name="kg_show_ime_at_screen_on">false</bool> <!-- No camera for you, tablet user --> <bool name="kg_enable_camera_default_widget">false</bool> <bool name="kg_center_small_widgets_vertically">true</bool> diff --git a/core/res/res/values-sw720dp/dimens_material.xml b/core/res/res/values-sw720dp/dimens_material.xml new file mode 100644 index 0000000..3b97b7a --- /dev/null +++ b/core/res/res/values-sw720dp/dimens_material.xml @@ -0,0 +1,21 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<resources> + + <!-- Preference activity, vertical padding for the header list --> + <dimen name="preference_screen_header_vertical_padding_material">8dp</dimen> + +</resources> diff --git a/core/res/res/values-watch/themes.xml b/core/res/res/values-watch/themes.xml index 9447d9c..756a94b 100644 --- a/core/res/res/values-watch/themes.xml +++ b/core/res/res/values-watch/themes.xml @@ -18,4 +18,6 @@ <style name="Theme.Dialog.AppError" parent="Theme.Micro.Dialog.AppError" /> <style name="Theme.Holo.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> <style name="Theme.Holo.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> + <style name="Theme.Material.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> + <style name="Theme.Material.Light.Dialog.Alert" parent="Theme.Micro.Dialog.Alert" /> </resources> diff --git a/core/res/res/values/arrays.xml b/core/res/res/values/arrays.xml index a8b5d6d..bb9885c 100644 --- a/core/res/res/values/arrays.xml +++ b/core/res/res/values/arrays.xml @@ -298,162 +298,75 @@ <item>@drawable/quickcontact_badge_overlay_pressed_light</item> <!-- Material assets --> - <item>@drawable/ab_share_pack_mtrl_alpha</item> - <item>@drawable/ab_solid_shadow_mtrl_alpha</item> - <item>@drawable/btn_cab_done_mtrl_alpha</item> - <item>@drawable/btn_check_to_off_mtrl_000</item> - <item>@drawable/btn_check_to_off_mtrl_001</item> - <item>@drawable/btn_check_to_off_mtrl_002</item> - <item>@drawable/btn_check_to_off_mtrl_003</item> - <item>@drawable/btn_check_to_off_mtrl_004</item> - <item>@drawable/btn_check_to_off_mtrl_005</item> - <item>@drawable/btn_check_to_off_mtrl_006</item> - <item>@drawable/btn_check_to_off_mtrl_007</item> - <item>@drawable/btn_check_to_off_mtrl_008</item> - <item>@drawable/btn_check_to_off_mtrl_009</item> - <item>@drawable/btn_check_to_off_mtrl_010</item> - <item>@drawable/btn_check_to_off_mtrl_011</item> - <item>@drawable/btn_check_to_off_mtrl_012</item> - <item>@drawable/btn_check_to_off_mtrl_013</item> - <item>@drawable/btn_check_to_off_mtrl_014</item> - <item>@drawable/btn_check_to_off_mtrl_015</item> - <item>@drawable/btn_check_to_on_mtrl_000</item> - <item>@drawable/btn_check_to_on_mtrl_001</item> - <item>@drawable/btn_check_to_on_mtrl_002</item> - <item>@drawable/btn_check_to_on_mtrl_003</item> - <item>@drawable/btn_check_to_on_mtrl_004</item> - <item>@drawable/btn_check_to_on_mtrl_005</item> - <item>@drawable/btn_check_to_on_mtrl_006</item> - <item>@drawable/btn_check_to_on_mtrl_007</item> - <item>@drawable/btn_check_to_on_mtrl_008</item> - <item>@drawable/btn_check_to_on_mtrl_009</item> - <item>@drawable/btn_check_to_on_mtrl_010</item> - <item>@drawable/btn_check_to_on_mtrl_011</item> - <item>@drawable/btn_check_to_on_mtrl_012</item> - <item>@drawable/btn_check_to_on_mtrl_013</item> - <item>@drawable/btn_check_to_on_mtrl_014</item> - <item>@drawable/btn_check_to_on_mtrl_015</item> - <item>@drawable/btn_radio_to_off_mtrl_000</item> - <item>@drawable/btn_radio_to_off_mtrl_001</item> - <item>@drawable/btn_radio_to_off_mtrl_002</item> - <item>@drawable/btn_radio_to_off_mtrl_003</item> - <item>@drawable/btn_radio_to_off_mtrl_004</item> - <item>@drawable/btn_radio_to_off_mtrl_005</item> - <item>@drawable/btn_radio_to_off_mtrl_006</item> - <item>@drawable/btn_radio_to_off_mtrl_007</item> - <item>@drawable/btn_radio_to_off_mtrl_008</item> - <item>@drawable/btn_radio_to_off_mtrl_009</item> - <item>@drawable/btn_radio_to_off_mtrl_010</item> - <item>@drawable/btn_radio_to_off_mtrl_011</item> - <item>@drawable/btn_radio_to_off_mtrl_012</item> - <item>@drawable/btn_radio_to_off_mtrl_013</item> - <item>@drawable/btn_radio_to_off_mtrl_014</item> - <item>@drawable/btn_radio_to_off_mtrl_015</item> - <item>@drawable/btn_radio_to_on_mtrl_000</item> - <item>@drawable/btn_radio_to_on_mtrl_001</item> - <item>@drawable/btn_radio_to_on_mtrl_002</item> - <item>@drawable/btn_radio_to_on_mtrl_003</item> - <item>@drawable/btn_radio_to_on_mtrl_004</item> - <item>@drawable/btn_radio_to_on_mtrl_005</item> - <item>@drawable/btn_radio_to_on_mtrl_006</item> - <item>@drawable/btn_radio_to_on_mtrl_007</item> - <item>@drawable/btn_radio_to_on_mtrl_008</item> - <item>@drawable/btn_radio_to_on_mtrl_009</item> - <item>@drawable/btn_radio_to_on_mtrl_010</item> - <item>@drawable/btn_radio_to_on_mtrl_011</item> - <item>@drawable/btn_radio_to_on_mtrl_012</item> - <item>@drawable/btn_radio_to_on_mtrl_013</item> - <item>@drawable/btn_radio_to_on_mtrl_014</item> - <item>@drawable/btn_radio_to_on_mtrl_015</item> - <item>@drawable/btn_rating_star_off_mtrl_alpha</item> - <item>@drawable/btn_rating_star_on_mtrl_alpha</item> - <item>@drawable/btn_star_mtrl_alpha</item> - <item>@drawable/btn_switch_to_off_mtrl_00001</item> - <item>@drawable/btn_switch_to_off_mtrl_00002</item> - <item>@drawable/btn_switch_to_off_mtrl_00003</item> - <item>@drawable/btn_switch_to_off_mtrl_00004</item> - <item>@drawable/btn_switch_to_off_mtrl_00005</item> - <item>@drawable/btn_switch_to_off_mtrl_00006</item> - <item>@drawable/btn_switch_to_off_mtrl_00007</item> - <item>@drawable/btn_switch_to_off_mtrl_00008</item> - <item>@drawable/btn_switch_to_off_mtrl_00009</item> - <item>@drawable/btn_switch_to_off_mtrl_00010</item> - <item>@drawable/btn_switch_to_off_mtrl_00011</item> - <item>@drawable/btn_switch_to_off_mtrl_00012</item> - <item>@drawable/btn_switch_to_on_mtrl_00001</item> - <item>@drawable/btn_switch_to_on_mtrl_00002</item> - <item>@drawable/btn_switch_to_on_mtrl_00003</item> - <item>@drawable/btn_switch_to_on_mtrl_00004</item> - <item>@drawable/btn_switch_to_on_mtrl_00005</item> - <item>@drawable/btn_switch_to_on_mtrl_00006</item> - <item>@drawable/btn_switch_to_on_mtrl_00007</item> - <item>@drawable/btn_switch_to_on_mtrl_00008</item> - <item>@drawable/btn_switch_to_on_mtrl_00009</item> - <item>@drawable/btn_switch_to_on_mtrl_00010</item> - <item>@drawable/btn_switch_to_on_mtrl_00011</item> - <item>@drawable/btn_switch_to_on_mtrl_00012</item> - <item>@drawable/btn_toggle_indicator_mtrl_alpha</item> - <item>@drawable/expander_close_mtrl_alpha</item> - <item>@drawable/expander_open_mtrl_alpha</item> - <item>@drawable/fastscroll_thumb_mtrl_alpha</item> - <item>@drawable/fastscroll_track_mtrl_alpha</item> + <item>@drawable/ab_share_pack_material</item> + <item>@drawable/ab_solid_shadow_material</item> + <item>@drawable/activated_background_material</item> + <item>@drawable/btn_borderless_material</item> + <item>@drawable/btn_cab_done_material</item> + <item>@drawable/btn_check_material_anim</item> + <item>@drawable/btn_default_material</item> + <item>@drawable/btn_radio_material_anim</item> + <item>@drawable/btn_star_material</item> + <item>@drawable/btn_toggle_material</item> + <item>@drawable/cab_background_bottom_material</item> + <item>@drawable/cab_background_top_material</item> + <item>@drawable/dialog_background_material</item> + <item>@drawable/dialog_background_shadow_material</item> + <item>@drawable/edit_text_material</item> + <item>@drawable/expander_group_material</item> + <item>@drawable/fastscroll_label_left_material</item> + <item>@drawable/fastscroll_label_right_material</item> + <item>@drawable/fastscroll_thumb_material</item> + <item>@drawable/fastscroll_track_material</item> <item>@drawable/ic_ab_back_material</item> - <item>@drawable/ic_cab_done_mtrl_alpha</item> - <item>@drawable/ic_clear_mtrl_alpha</item> - <item>@drawable/ic_commit_search_api_mtrl_alpha</item> + <item>@drawable/ic_clear_material</item> + <item>@drawable/ic_commit_search_api_material</item> <item>@drawable/ic_dialog_alert_material</item> - <item>@drawable/ic_find_next_mtrl_alpha</item> - <item>@drawable/ic_find_previous_mtrl_alpha</item> + <item>@drawable/ic_find_next_material</item> + <item>@drawable/ic_find_previous_material</item> <item>@drawable/ic_go_search_api_material</item> - <item>@drawable/ic_media_route_disabled_mtrl_alpha</item> - <item>@drawable/ic_media_route_off_mtrl_alpha</item> - <item>@drawable/ic_media_route_on_0_mtrl_alpha</item> - <item>@drawable/ic_media_route_on_1_mtrl_alpha</item> - <item>@drawable/ic_media_route_on_2_mtrl_alpha</item> - <item>@drawable/ic_media_route_on_mtrl_alpha</item> + <item>@drawable/ic_media_route_connecting_material</item> + <item>@drawable/ic_media_route_material</item> <item>@drawable/ic_menu_copy_material</item> <item>@drawable/ic_menu_cut_material</item> - <item>@drawable/ic_menu_find_mtrl_alpha</item> + <item>@drawable/ic_menu_find_material</item> <item>@drawable/ic_menu_moreoverflow_material</item> <item>@drawable/ic_menu_paste_material</item> - <item>@drawable/ic_menu_search_mtrl_alpha</item> + <item>@drawable/ic_menu_search_material</item> <item>@drawable/ic_menu_selectall_material</item> <item>@drawable/ic_menu_share_material</item> <item>@drawable/ic_search_api_material</item> <item>@drawable/ic_voice_search_api_material</item> - <item>@drawable/list_divider_mtrl_alpha</item> - <item>@drawable/list_section_divider_mtrl_alpha</item> - <item>@drawable/popup_background_mtrl_mult</item> - <item>@drawable/progress_mtrl_alpha</item> - <item>@drawable/scrollbar_handle_mtrl_alpha</item> - <item>@drawable/scrubber_control_from_pressed_mtrl_000</item> - <item>@drawable/scrubber_control_from_pressed_mtrl_001</item> - <item>@drawable/scrubber_control_from_pressed_mtrl_002</item> - <item>@drawable/scrubber_control_from_pressed_mtrl_003</item> - <item>@drawable/scrubber_control_from_pressed_mtrl_004</item> - <item>@drawable/scrubber_control_from_pressed_mtrl_005</item> - <item>@drawable/scrubber_control_off_pressed_mtrl_alpha</item> - <item>@drawable/scrubber_control_off_mtrl_alpha</item> - <item>@drawable/scrubber_control_on_pressed_mtrl_alpha</item> - <item>@drawable/scrubber_control_on_mtrl_alpha</item> - <item>@drawable/scrubber_control_to_pressed_mtrl_000</item> - <item>@drawable/scrubber_control_to_pressed_mtrl_001</item> - <item>@drawable/scrubber_control_to_pressed_mtrl_002</item> - <item>@drawable/scrubber_control_to_pressed_mtrl_003</item> - <item>@drawable/scrubber_control_to_pressed_mtrl_004</item> - <item>@drawable/scrubber_control_to_pressed_mtrl_005</item> - <item>@drawable/scrubber_primary_mtrl_alpha</item> - <item>@drawable/scrubber_track_mtrl_alpha</item> - <item>@drawable/spinner_mtrl_am_alpha</item> - <item>@drawable/switch_track_mtrl_alpha</item> - <item>@drawable/text_cursor_mtrl_alpha</item> - <item>@drawable/textfield_activated_mtrl_alpha</item> - <item>@drawable/textfield_default_mtrl_alpha</item> - <item>@drawable/textfield_search_activated_mtrl_alpha</item> - <item>@drawable/textfield_search_default_mtrl_alpha</item> - <item>@drawable/text_select_handle_left_mtrl_alpha</item> - <item>@drawable/text_select_handle_middle_mtrl_alpha</item> - <item>@drawable/text_select_handle_right_mtrl_alpha</item> + <item>@drawable/item_background_borderless_material</item> + <item>@drawable/item_background_material</item> + <item>@drawable/list_divider_material</item> + <item>@drawable/list_section_divider_material</item> + <item>@drawable/notification_material_action_background</item> + <item>@drawable/notification_material_media_action_background</item> + <item>@drawable/popup_background_material</item> + <item>@drawable/progress_horizontal_material</item> + <item>@drawable/progress_indeterminate_horizontal_material</item> + <item>@drawable/progress_large_material</item> + <item>@drawable/progress_medium_material</item> + <item>@drawable/progress_small_material</item> + <item>@drawable/ratingbar_full_empty_material</item> + <item>@drawable/ratingbar_full_filled_material</item> + <item>@drawable/ratingbar_full_material</item> + <item>@drawable/scrollbar_handle_material</item> + <item>@drawable/scrubber_control_material_anim</item> + <item>@drawable/scrubber_control_selector_material</item> + <item>@drawable/scrubber_progress_horizontal_material</item> + <item>@drawable/spinner_background_material</item> + <item>@drawable/spinner_textfield_background_material</item> + <item>@drawable/switch_thumb_material_anim</item> + <item>@drawable/switch_track_material</item> + <item>@drawable/tab_indicator_material</item> + <item>@drawable/text_cursor_material</item> + <item>@drawable/textfield_search_material</item> + <item>@drawable/text_select_handle_left_material</item> + <item>@drawable/text_select_handle_middle_material</item> + <item>@drawable/text_select_handle_right_material</item> + <item>@drawable/ic_account_circle</item> </array> <!-- Do not translate. These are all of the color state list resources that should be diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index 251652e..7b4df49 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -2772,25 +2772,32 @@ <attr name="layout_width" /> <attr name="layout_height" /> <!-- Specifies extra space on the left, top, right and bottom - sides of this view. This space is outside this view's bounds. --> + sides of this view. This space is outside this view's bounds. + Margin values should be positive. --> <attr name="layout_margin" format="dimension" /> <!-- Specifies extra space on the left side of this view. - This space is outside this view's bounds. --> + This space is outside this view's bounds. + Margin values should be positive. --> <attr name="layout_marginLeft" format="dimension" /> <!-- Specifies extra space on the top side of this view. - This space is outside this view's bounds. --> + This space is outside this view's bounds. + Margin values should be positive.--> <attr name="layout_marginTop" format="dimension" /> <!-- Specifies extra space on the right side of this view. - This space is outside this view's bounds. --> + This space is outside this view's bounds. + Margin values should be positive.--> <attr name="layout_marginRight" format="dimension" /> <!-- Specifies extra space on the bottom side of this view. - This space is outside this view's bounds. --> + This space is outside this view's bounds. + Margin values should be positive.--> <attr name="layout_marginBottom" format="dimension" /> <!-- Specifies extra space on the start side of this view. - This space is outside this view's bounds. --> + This space is outside this view's bounds. + Margin values should be positive.--> <attr name="layout_marginStart" format="dimension" /> <!-- Specifies extra space on the end side of this view. - This space is outside this view's bounds. --> + This space is outside this view's bounds. + Margin values should be positive.--> <attr name="layout_marginEnd" format="dimension" /> </declare-styleable> @@ -4862,6 +4869,12 @@ <attr name="thickness" format="dimension" /> <!-- Indicates whether the drawable's level affects the way the gradient is drawn. --> <attr name="useLevel" /> + <!-- If set, specifies the color to apply to the drawable as a tint. By default, + no tint is applied. May be a color state list. --> + <attr name="tint" /> + <!-- When a tint color is set, specifies its Porter-Duff blending mode. The + default value is src_in, which treats the drawable as an alpha mask. --> + <attr name="tintMode" /> </declare-styleable> <!-- Used to specify the size of the shape for GradientDrawable. --> @@ -4898,7 +4911,7 @@ <!-- Y coordinate of the origin of the gradient within the shape. --> <attr name="centerY" format="float|fraction" /> <!-- Radius of the gradient, used only with radial gradient. --> - <attr name="gradientRadius" format="float|fraction" /> + <attr name="gradientRadius" format="float|fraction|dimension" /> </declare-styleable> <!-- Used to fill the shape of GradientDrawable with a solid color. --> @@ -5689,6 +5702,17 @@ <attr name="reparent" format="boolean"/> </declare-styleable> + <!-- Use <code>changeBounds</code>as the root tag of the XML resource that + describes a {@link android.transition.ChangeBounds} transition. + The attributes of the {@link android.R.styleable#Transition Transition} + resource are available in addition to the specific attributes of ChangeBounds + described here. --> + <declare-styleable name="ChangeBounds"> + <!-- Resize the view by adjusting the clipBounds rather than changing the + dimensions of the view itself. The default value is false. --> + <attr name="resizeClip" format="boolean"/> + </declare-styleable> + <!-- Use <code>transitionManager</code> as the root tag of the XML resource that describes a {@link android.transition.TransitionManager TransitionManager}. --> diff --git a/core/res/res/values/bools.xml b/core/res/res/values/bools.xml index 18e4f2f..457131a 100644 --- a/core/res/res/values/bools.xml +++ b/core/res/res/values/bools.xml @@ -18,7 +18,6 @@ <bool name="kg_enable_camera_default_widget">true</bool> <bool name="kg_center_small_widgets_vertically">false</bool> <bool name="kg_top_align_page_shrink_on_bouncer_visible">true</bool> - <bool name="kg_show_ime_at_screen_on">true</bool> <bool name="action_bar_embed_tabs">true</bool> <bool name="action_bar_embed_tabs_pre_jb">false</bool> <bool name="split_action_bar_is_narrow">true</bool> diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml index 235bf84..9f83db4 100644 --- a/core/res/res/values/colors.xml +++ b/core/res/res/values/colors.xml @@ -136,6 +136,8 @@ <color name="notification_media_primary_color">@color/primary_text_material_dark</color> <color name="notification_media_secondary_color">@color/secondary_text_material_dark</color> + <color name="notification_progress_background_color">@color/secondary_text_material_light</color> + <!-- Keyguard colors --> <color name="keyguard_avatar_frame_color">#ffffffff</color> <color name="keyguard_avatar_frame_shadow_color">#80000000</color> diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml index 5773b94..46ec838 100644 --- a/core/res/res/values/colors_material.xml +++ b/core/res/res/values/colors_material.xml @@ -22,7 +22,7 @@ <color name="background_floating_material_light">#ffeeeeee</color> <color name="primary_material_dark">#ff212121</color> - <color name="primary_material_light">#ffbdbdbd</color> + <color name="primary_material_light">#ffe0e0e0</color> <color name="primary_dark_material_dark">#ff000000</color> <color name="primary_dark_material_light">#ff757575</color> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index bb263f1..bebab90 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -27,6 +27,7 @@ <item><xliff:g id="id">sync_failing</xliff:g></item> <item><xliff:g id="id">sync_active</xliff:g></item> <item><xliff:g id="id">cast</xliff:g></item> + <item><xliff:g id="id">hotspot</xliff:g></item> <item><xliff:g id="id">location</xliff:g></item> <item><xliff:g id="id">bluetooth</xliff:g></item> <item><xliff:g id="id">nfc</xliff:g></item> @@ -453,6 +454,26 @@ <!-- If this is true, key chords can be used to take a screenshot on the device. --> <bool name="config_enableScreenshotChord">true</bool> + <!-- If this is true, allow wake from theater mode when plugged in or unplugged. --> + <bool name="config_allowTheaterModeWakeFromUnplug">false</bool> + <!-- If this is true, allow wake from theater mode from gesture. --> + <bool name="config_allowTheaterModeWakeFromGesture">false</bool> + <!-- If this is true, allow wake from theater mode from camera lens cover is switched. --> + <bool name="config_allowTheaterModeWakeFromCameraLens">false</bool> + <!-- If this is true, allow wake from theater mode from power key press. --> + <bool name="config_allowTheaterModeWakeFromPowerKey">true</bool> + <!-- If this is true, allow wake from theater mode from regular key press. Setting this value to + true implies config_allowTheaterModeWakeFromPowerKey is also true--> + <bool name="config_allowTheaterModeWakeFromKey">false</bool> + <!-- If this is true, allow wake from theater mode from motion. --> + <bool name="config_allowTheaterModeWakeFromMotion">false</bool> + <!-- If this is true, allow wake from theater mode from lid switch. --> + <bool name="config_allowTheaterModeWakeFromLidSwitch">false</bool> + <!-- If this is true, allow wake from theater mode when docked. --> + <bool name="config_allowTheaterModeWakeFromDock">false</bool> + <!-- If this is true, allow wake from theater mode from window layout flag. --> + <bool name="config_allowTheaterModeWakeFromWindowLayout">false</bool> + <!-- Auto-rotation behavior --> <!-- If true, enables auto-rotation features using the accelerometer. @@ -1023,6 +1044,9 @@ device is data-only. --> <bool name="config_voice_capable">true</bool> + <!-- Flag indicating if the user is notified when the mobile network access is restricted --> + <bool name="config_user_notification_of_restrictied_mobile_access">true</bool> + <!-- Flag indicating whether the current device allows sms service. If true, this means that the device supports both sending and receiving sms via the telephony network. @@ -1764,13 +1788,21 @@ be disabled) but individual Features can be disabled using ImsConfig.setFeatureValue() --> <bool name="imsServiceAllowTurnOff">true</bool> - <!-- Flag specifying whether VoLTE & VT is availasble on device --> - <bool name="config_device_volte_vt_available">false</bool> + <!-- Flag specifying whether VoLTE is available on device --> + <bool name="config_device_volte_available">false</bool> + + <!-- Flag specifying whether VoLTE should be available for carrier: independent of + carrier provisioning. If false: hard disabled. If true: then depends on carrier + provisioning, availability etc --> + <bool name="config_carrier_volte_available">false</bool> + + <!-- Flag specifying whether VT is available on device --> + <bool name="config_device_vt_available">false</bool> - <!-- Flag specifying whether VoLTE & VT should be available for carrier: independent of + <!-- Flag specifying whether VT should be available for carrier: independent of carrier provisioning. If false: hard disabled. If true: then depends on carrier provisioning, availability etc --> - <bool name="config_carrier_volte_vt_available">false</bool> + <bool name="config_carrier_vt_available">false</bool> <bool name="config_networkSamplingWakesDevice">true</bool> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 26d3133..71f66ba 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -367,12 +367,15 @@ <dimen name="timepicker_time_label_size">60sp</dimen> <dimen name="timepicker_extra_time_label_margin">-30dp</dimen> <dimen name="timepicker_ampm_label_size">16sp</dimen> - <dimen name="timepicker_ampm_left_padding">6dip</dimen> - <dimen name="timepicker_separator_padding">4dip</dimen> - <dimen name="timepicker_header_height">96dip</dimen> - <dimen name="timepicker_minimum_margin_sides">48dip</dimen> - <dimen name="timepicker_minimum_margin_top_bottom">24dip</dimen> - <dimen name="timepicker_radial_picker_dimen">270dip</dimen> + <dimen name="timepicker_ampm_horizontal_padding">12dp</dimen> + <dimen name="timepicker_ampm_vertical_padding">16dp</dimen> + <dimen name="timepicker_am_bottom_padding">1dp</dimen> + <dimen name="timepicker_pm_top_padding">2dp</dimen> + <dimen name="timepicker_separator_padding">4dp</dimen> + <dimen name="timepicker_header_height">96dp</dimen> + <dimen name="timepicker_minimum_margin_sides">48dp</dimen> + <dimen name="timepicker_minimum_margin_top_bottom">24dp</dimen> + <dimen name="timepicker_radial_picker_dimen">270dp</dimen> <!-- Used by SimpleMonthView --> <dimen name="datepicker_day_number_size">12sp</dimen> diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml index 450658e..515922d 100644 --- a/core/res/res/values/dimens_material.xml +++ b/core/res/res/values/dimens_material.xml @@ -15,7 +15,7 @@ --> <resources> <!-- Preference activity, vertical padding for the header list --> - <dimen name="preference_screen_header_vertical_padding_material">8dp</dimen> + <dimen name="preference_screen_header_vertical_padding_material">0dp</dimen> <!-- Preference activity side margins --> <dimen name="preference_screen_side_margin_material">0dp</dimen> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 7568252..45208ab 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2589,5 +2589,6 @@ <!-- @hide --> <public-padding type="attr" name="private_resource_pad" end="0x01010500" /> + <public type="attr" name="resizeClip"/> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 9817d57..7c15183 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -1441,9 +1441,8 @@ <string name="permlab_bodySensors">body sensors (like heart rate monitors) </string> <!-- Description of the body sensors permission, listed so the user can decide whether to allow the application to access data from body sensors. [CHAR LIMIT=NONE] --> - <string name="permdesc_bodySensors" product="default">Allows the app to - access data from sensors you use to measure what’s happening inside your - body, such as heart rate.</string> + <string name="permdesc_bodySensors" product="default">Allows the app to access data from sensors + that monitor your physical condition, such as your heart rate.</string> <!-- Title of the read social stream permission, listed so the user can decide whether to allow the application to read information from the user's social stream. [CHAR LIMIT=30] --> <string name="permlab_readSocialStream" product="default">read your social stream</string> @@ -1710,6 +1709,11 @@ various peripherals for the purpose of hardware testing.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_fm">access FM radio</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_fm">Allows the app to access FM radio to listen to programs.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_callPhone">directly call phone numbers</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_callPhone">Allows the app to call phone numbers @@ -2103,6 +2107,16 @@ <string name="permdesc_use_sip">Allows the app to make and receive SIP calls.</string> <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_register_provider">register new telecom connection</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_register_provider">Allows the app to register new telecom connections.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permlab_connection_manager">manage telecom connections</string> + <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> + <string name="permdesc_connection_manager">Allows the app to manage telecom connections.</string> + + <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permlab_bind_incall_service">interact with in-call screen</string> <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. --> <string name="permdesc_bind_incall_service">Allows the app to control when and how the user sees the in-call screen.</string> @@ -2510,19 +2524,6 @@ <!-- Shown when face unlock failed multiple times so we're just using the backup --> <string name="faceunlock_multiple_failures">Maximum Face Unlock attempts exceeded</string> - <!-- When the lock screen is showing and the phone plugged in, and the battery - is not fully charged, show the current charge %. --> - <string name="lockscreen_plugged_in">Charging, <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g></string> - <!-- When the lock screen is showing, the phone is plugged in and the battery is fully - charged, say that it is charged. --> - <string name="lockscreen_charged">Charged</string> - <!-- A short representation of charging information, e.g "34%" --> - <string name="lockscreen_battery_short"><xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g></string> - - <!-- When the lock screen is showing and the battery is low, warn user to plug - in the phone soon. --> - <string name="lockscreen_low_battery">Connect your charger.</string> - <!-- Shown in the lock screen when there is no SIM card. --> <string name="lockscreen_missing_sim_message_short">No SIM card</string> <!-- Shown in the lock screen when there is no SIM card. --> @@ -4864,18 +4865,33 @@ <!-- [CHAR_LIMIT=NONE] Zen mode: Condition summary for built-in downtime condition, if active --> <string name="downtime_condition_summary">Until your downtime ends at <xliff:g id="formattedTime" example="10.00 PM">%1$s</xliff:g></string> - <!-- Zen mode condition: time duration in minutes. [CHAR LIMIT=NONE] --> + <!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] --> + <plurals name="zen_mode_duration_minutes_summary"> + <item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g>)</item> + <item quantity="other">For %1$d minutes (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item> + </plurals> + + <!-- Zen mode condition - summary: time duration in hours. [CHAR LIMIT=NONE] --> + <plurals name="zen_mode_duration_hours_summary"> + <item quantity="one">For one hour (until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g>)</item> + <item quantity="other">For %1$d hours (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item> + </plurals> + + <!-- Zen mode condition - line one: time duration in minutes. [CHAR LIMIT=NONE] --> <plurals name="zen_mode_duration_minutes"> <item quantity="one">For one minute</item> <item quantity="other">For %d minutes</item> </plurals> - <!-- Zen mode condition: time duration in hours. [CHAR LIMIT=NONE] --> + <!-- Zen mode condition - line one: time duration in hours. [CHAR LIMIT=NONE] --> <plurals name="zen_mode_duration_hours"> <item quantity="one">For one hour</item> <item quantity="other">For %d hours</item> </plurals> + <!-- Zen mode condition - line two: ending time. [CHAR LIMIT=NONE] --> + <string name="zen_mode_until">Until <xliff:g id="formattedTime" example="10:00 PM">%1$s</xliff:g></string> + <!-- Zen mode condition: no exit criteria. [CHAR LIMIT=NONE] --> <string name="zen_mode_forever">Indefinitely</string> </resources> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index f9fca00..6e03b3d 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -320,50 +320,48 @@ please see styles_device_defaults.xml. <item name="textColor">?attr/textColorPrimaryDisableOnly</item> </style> - <style name="TextAppearance.Material.Widget.ActionMode"/> - <style name="TextAppearance.Material.Widget.ActionMode.Title" - parent="TextAppearance.Material.Title"> - <item name="textSize">@dimen/text_size_title_material_toolbar</item> - </style> - <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse" - parent="TextAppearance.Material.Title.Inverse"> - <item name="textSize">@dimen/text_size_title_material_toolbar</item> - </style> - <style name="TextAppearance.Material.Widget.ActionMode.Subtitle" - parent="TextAppearance.Material.Subhead"> - <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item> - </style> - <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse" - parent="TextAppearance.Material.Subhead.Inverse"> - <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item> - </style> <style name="TextAppearance.Material.Widget.ActionBar.Title" parent="TextAppearance.Material.Title"> <item name="textSize">@dimen/text_size_title_material_toolbar</item> + <item name="textColor">?attr/textColorPrimary</item> </style> <style name="TextAppearance.Material.Widget.ActionBar.Title.Inverse" parent="TextAppearance.Material.Title.Inverse"> <item name="textSize">@dimen/text_size_title_material_toolbar</item> + <item name="textColor">?attr/textColorPrimaryInverse</item> </style> <style name="TextAppearance.Material.Widget.ActionBar.Subtitle" parent="TextAppearance.Material.Subhead"> <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item> + <item name="textColor">?attr/textColorSecondary</item> </style> <style name="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse" parent="TextAppearance.Material.Subhead.Inverse"> <item name="textSize">@dimen/text_size_subtitle_material_toolbar</item> + <item name="textColor">?attr/textColorSecondaryInverse</item> </style> - <style name="TextAppearance.Material.Widget.ActionBar.Menu" parent="TextAppearance.Material.Menu"> + <style name="TextAppearance.Material.Widget.ActionBar.Menu" + parent="TextAppearance.Material.Menu"> <item name="textColor">?attr/actionMenuTextColor</item> <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item> </style> - - <style name="TextAppearance.Material.Widget.ActionBar.Menu.Inverse" parent="TextAppearance.Material.Menu.Inverse"> + <style name="TextAppearance.Material.Widget.ActionBar.Menu.Inverse" + parent="TextAppearance.Material.Menu.Inverse"> <item name="textColor">?attr/actionMenuTextColor</item> <item name="textAllCaps">@bool/config_actionMenuItemAllCaps</item> </style> + <style name="TextAppearance.Material.Widget.ActionMode"/> + <style name="TextAppearance.Material.Widget.ActionMode.Title" + parent="TextAppearance.Material.Widget.ActionBar.Title" /> + <style name="TextAppearance.Material.Widget.ActionMode.Title.Inverse" + parent="TextAppearance.Material.Widget.ActionBar.Title.Inverse" /> + <style name="TextAppearance.Material.Widget.ActionMode.Subtitle" + parent="TextAppearance.Material.Widget.ActionBar.Subtitle" /> + <style name="TextAppearance.Material.Widget.ActionMode.Subtitle.Inverse" + parent="TextAppearance.Material.Widget.ActionBar.Subtitle.Inverse" /> + <style name="TextAppearance.Material.Widget.Toolbar.Title" parent="TextAppearance.Material.Widget.ActionBar.Title" /> <style name="TextAppearance.Material.Widget.Toolbar.Subtitle" diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 2a9e1d1..d86413f 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -267,6 +267,7 @@ <java-symbol type="bool" name="config_ui_enableFadingMarquee" /> <java-symbol type="bool" name="config_use_strict_phone_number_comparation" /> <java-symbol type="bool" name="config_voice_capable" /> + <java-symbol type="bool" name="config_user_notification_of_restrictied_mobile_access" /> <java-symbol type="bool" name="config_wifiDisplaySupportsProtectedBuffers" /> <java-symbol type="bool" name="preferences_prefer_dual_pane" /> <java-symbol type="bool" name="skip_restoring_network_selection" /> @@ -1570,6 +1571,15 @@ <java-symbol type="bool" name="config_enableNetworkLocationOverlay" /> <java-symbol type="bool" name="config_sf_limitedAlpha" /> <java-symbol type="bool" name="config_unplugTurnsOnScreen" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromUnplug" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromGesture" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromCameraLens" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromPowerKey" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromKey" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromMotion" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromLidSwitch" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromDock" /> + <java-symbol type="bool" name="config_allowTheaterModeWakeFromWindowLayout" /> <java-symbol type="bool" name="config_wifi_background_scan_support" /> <java-symbol type="bool" name="config_wifi_dual_band_support" /> <java-symbol type="bool" name="config_wimaxEnabled" /> @@ -1781,6 +1791,7 @@ <java-symbol type="drawable" name="notification_icon_legacy_bg" /> <java-symbol type="color" name="notification_media_primary_color" /> <java-symbol type="color" name="notification_media_secondary_color" /> + <java-symbol type="color" name="notification_progress_background_color" /> <java-symbol type="id" name="media_actions" /> <!-- From SystemUI --> @@ -1934,7 +1945,9 @@ <java-symbol type="id" name="time_header" /> <java-symbol type="id" name="hours" /> <java-symbol type="id" name="minutes" /> - <java-symbol type="id" name="ampm_label" /> + <java-symbol type="id" name="ampm_layout" /> + <java-symbol type="id" name="am_label" /> + <java-symbol type="id" name="pm_label" /> <java-symbol type="id" name="radial_picker" /> <java-symbol type="id" name="separator" /> <java-symbol type="id" name="date_picker_header" /> @@ -1971,6 +1984,9 @@ <java-symbol type="string" name="zen_mode_forever" /> <java-symbol type="plurals" name="zen_mode_duration_minutes" /> <java-symbol type="plurals" name="zen_mode_duration_hours" /> + <java-symbol type="plurals" name="zen_mode_duration_minutes_summary" /> + <java-symbol type="plurals" name="zen_mode_duration_hours_summary" /> + <java-symbol type="string" name="zen_mode_until" /> <java-symbol type="string" name="item_is_selected" /> <java-symbol type="string" name="day_of_week_label_typeface" /> @@ -2027,8 +2043,10 @@ <java-symbol type="attr" name="preferenceFragmentStyle" /> <java-symbol type="bool" name="skipHoldBeforeMerge" /> <java-symbol type="bool" name="imsServiceAllowTurnOff" /> - <java-symbol type="bool" name="config_device_volte_vt_available" /> - <java-symbol type="bool" name="config_carrier_volte_vt_available" /> + <java-symbol type="bool" name="config_device_volte_available" /> + <java-symbol type="bool" name="config_carrier_volte_available" /> + <java-symbol type="bool" name="config_device_vt_available" /> + <java-symbol type="bool" name="config_carrier_vt_available" /> <java-symbol type="bool" name="useImsAlwaysForEmergencyCall" /> <java-symbol type="attr" name="touchscreenBlocksFocus" /> <java-symbol type="layout" name="resolver_list_with_default" /> @@ -2072,4 +2090,7 @@ <java-symbol type="bool" name="config_switch_phone_on_voice_reg_state_change" /> <java-symbol type="string" name="whichHomeApplicationNamed" /> <java-symbol type="bool" name="config_sms_force_7bit_encoding" /> + + <!-- From MSIM Account --> + <java-symbol type="layout" name="simple_account_item" /> </resources> diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml index b51974e..1864f89 100644 --- a/core/res/res/values/themes_material.xml +++ b/core/res/res/values/themes_material.xml @@ -781,9 +781,6 @@ please see themes_device_defaults.xml. <item name="textCheckMark">@drawable/indicator_check_mark_light</item> <item name="textCheckMarkInverse">@drawable/indicator_check_mark_dark</item> - <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_light</item> - <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_light</item> - <item name="colorControlNormal">?attr/textColorSecondary</item> <item name="colorControlHighlight">@color/ripple_material_light</item> <item name="colorButtonNormal">@color/btn_default_material_light</item> @@ -819,9 +816,6 @@ please see themes_device_defaults.xml. <item name="textCheckMark">@drawable/indicator_check_mark_dark</item> <item name="textCheckMarkInverse">@drawable/indicator_check_mark_light</item> - <item name="fastScrollPreviewBackgroundLeft">@drawable/fastscroll_label_left_holo_dark</item> - <item name="fastScrollPreviewBackgroundRight">@drawable/fastscroll_label_right_holo_dark</item> - <item name="colorControlNormal">?attr/textColorSecondary</item> <item name="colorControlHighlight">@color/ripple_material_dark</item> <item name="colorButtonNormal">@color/btn_default_material_dark</item> diff --git a/core/res/res/values/themes_micro.xml b/core/res/res/values/themes_micro.xml index 7e0467b..f1bc5da 100644 --- a/core/res/res/values/themes_micro.xml +++ b/core/res/res/values/themes_micro.xml @@ -24,6 +24,8 @@ <item name="windowBackground">@color/black</item> <item name="windowContentOverlay">@null</item> <item name="windowIsFloating">false</item> + <!-- We need the windows to be translucent for SwipeToDismiss layout + to work properly. --> <item name="windowIsTranslucent">true</item> <item name="windowSwipeToDismiss">true</item> </style> @@ -38,6 +40,8 @@ <item name="windowBackground">@color/white</item> <item name="windowContentOverlay">@null</item> <item name="windowIsFloating">false</item> + <!-- We need the windows to be translucent for SwipeToDismiss layout + to work properly. --> <item name="windowIsTranslucent">true</item> <item name="windowSwipeToDismiss">true</item> </style> diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java index 80d5668..64fed7f 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestBase.java @@ -49,7 +49,8 @@ import java.util.List; */ public class ConnectivityManagerTestBase extends InstrumentationTestCase { - private static final String PING_IP_ADDR = "8.8.8.8"; + private static final String[] PING_HOST_LIST = { + "www.google.com", "www.yahoo.com", "www.bing.com", "www.facebook.com", "www.ask.com"}; protected static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds protected static final int WIFI_SCAN_TIMEOUT = 50 * 1000; // 50 seconds @@ -281,22 +282,14 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { } /** - * @param pingServerList a list of servers that can be used for ping test, can be null * @return true if the ping test is successful, false otherwise. */ - protected boolean pingTest(String[] pingServerList) { - String[] hostList = {"www.google.com", "www.yahoo.com", - "www.bing.com", "www.facebook.com", "www.ask.com"}; - if (pingServerList != null) { - hostList = pingServerList; - } - + protected boolean pingTest() { long startTime = System.currentTimeMillis(); while ((System.currentTimeMillis() - startTime) < PING_TIMER) { try { // assume the chance that all servers are down is very small - for (int i = 0; i < hostList.length; i++ ) { - String host = hostList[i]; + for (String host : PING_HOST_LIST) { logv("Start ping test, ping " + host); Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host); int status = p.waitFor(); @@ -312,6 +305,7 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { } catch (InterruptedException e) { logv("Ping test Fail: InterruptedException"); } + SystemClock.sleep(SHORT_TIMEOUT); } // ping test timeout return false; @@ -458,14 +452,7 @@ public class ConnectivityManagerTestBase extends InstrumentationTestCase { // use ping request against Google public DNS to verify connectivity protected boolean checkNetworkConnectivity() { assertTrue("no active network connection", waitForActiveNetworkConnection(LONG_TIMEOUT)); - try { - Process proc = Runtime.getRuntime().exec(new String[]{ - "/system/bin/ping", "-W", "30", "-c", "1", PING_IP_ADDR}); - return proc.waitFor() == 0; - } catch (InterruptedException | IOException e) { - Log.e(mLogTag, "Ping failed", e); - } - return false; + return pingTest(); } @Override diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java index d5051df..2d291ff 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/functional/ConnectivityManagerMobileTest.java @@ -72,16 +72,6 @@ public class ConnectivityManagerMobileTest extends ConnectivityManagerTestBase super.tearDown(); } - // help function to verify 3G connection - public void verifyCellularConnection() { - NetworkInfo extraNetInfo = mCm.getActiveNetworkInfo(); - assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE, - extraNetInfo.getType()); - assertTrue("not connected to cellular network", extraNetInfo.isConnected()); - } - - - // Test case 1: Test enabling Wifi without associating with any AP, no broadcast on network // event should be expected. @LargeTest @@ -336,4 +326,12 @@ public class ConnectivityManagerMobileTest extends ConnectivityManagerTestBase assertTrue("wifi state not disabled", waitForWifiState( WifiManager.WIFI_STATE_DISABLED, LONG_TIMEOUT)); } + + // help function to verify 3G connection + private void verifyCellularConnection() { + NetworkInfo extraNetInfo = mCm.getActiveNetworkInfo(); + assertEquals("network type is not MOBILE", ConnectivityManager.TYPE_MOBILE, + extraNetInfo.getType()); + assertTrue("not connected to cellular network", extraNetInfo.isConnected()); + } } diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java index 41f01e6..de934b9 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java @@ -112,7 +112,7 @@ public class WifiApStress extends ConnectivityManagerTestBase { } catch (Exception e) { // ignore } - assertTrue("no uplink data connection after Wi-Fi tethering", pingTest(null)); + assertTrue("no uplink data connection after Wi-Fi tethering", pingTest()); // disable wifi hotspot assertTrue("failed to disable wifi hotspot", mWifiManager.setWifiApEnabled(config, false)); diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java index fbd4669..f3d5c87 100644 --- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java +++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java @@ -216,7 +216,7 @@ public class WifiStressTest extends ConnectivityManagerTestBase { assertTrue("wifi not connected", waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED, WIFI_CONNECTION_TIMEOUT)); // Run ping test to verify the data connection - assertTrue("Wi-Fi is connected, but no data connection.", pingTest(null)); + assertTrue("Wi-Fi is connected, but no data connection.", pingTest()); long i, sum = 0, avgReconnectTime = 0; for (i = 1; i <= mReconnectIterations; i++) { @@ -264,7 +264,7 @@ public class WifiStressTest extends ConnectivityManagerTestBase { } else { assertEquals("mobile not connected", State.CONNECTED, mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState()); - assertTrue("no connectivity over mobile", pingTest(null)); + assertTrue("no connectivity over mobile", pingTest()); } // Turn screen on again @@ -281,7 +281,7 @@ public class WifiStressTest extends ConnectivityManagerTestBase { avgReconnectTime = sum / i; logv("average reconnection time is: " + avgReconnectTime); - assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest(null)); + assertTrue("Reconnect to Wi-Fi network, but no data connection.", pingTest()); } Bundle result = new Bundle(); result.putLong("actual-iterations", i - 1); diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml index b524177..226717e 100644 --- a/core/tests/coretests/AndroidManifest.xml +++ b/core/tests/coretests/AndroidManifest.xml @@ -1252,6 +1252,13 @@ </intent-filter> </activity> + <activity android:name="android.content.res.ResourceCacheActivity"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" /> + </intent-filter> + </activity> + </application> <instrumentation android:name="android.test.InstrumentationTestRunner" diff --git a/core/tests/coretests/res/anim/reset_state_anim.xml b/core/tests/coretests/res/anim/reset_state_anim.xml index 918d0a3..4bbbe62 100644 --- a/core/tests/coretests/res/anim/reset_state_anim.xml +++ b/core/tests/coretests/res/anim/reset_state_anim.xml @@ -1,4 +1,18 @@ <?xml version="1.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. +--> <set xmlns:android="http://schemas.android.com/apk/res/android"> <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/> <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="0" android:valueType="floatType"/> diff --git a/core/tests/coretests/res/anim/test_animator.xml b/core/tests/coretests/res/anim/test_animator.xml new file mode 100644 index 0000000..49afc3f --- /dev/null +++ b/core/tests/coretests/res/anim/test_animator.xml @@ -0,0 +1,22 @@ +<?xml version="1.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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android"> + <!-- if you change this, you should also change AnimatorInflaterTest#testLoadAnimator--> + <objectAnimator android:propertyName="x" android:duration="100" android:valueTo="0" android:valueType="floatType"/> + <objectAnimator android:propertyName="y" android:duration="100" android:valueTo="1" android:valueType="floatType"/> + <objectAnimator android:propertyName="left" android:duration="100" android:valueTo="2" android:valueType="intType"/> +</set>
\ No newline at end of file diff --git a/core/tests/coretests/res/anim/test_state_anim.xml b/core/tests/coretests/res/anim/test_state_anim.xml index 9e08f68..b6a4822 100644 --- a/core/tests/coretests/res/anim/test_state_anim.xml +++ b/core/tests/coretests/res/anim/test_state_anim.xml @@ -1,4 +1,18 @@ <?xml version="1.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. +--> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <set> diff --git a/core/tests/coretests/res/values-land/dimens.xml b/core/tests/coretests/res/values-land/dimens.xml new file mode 100644 index 0000000..1ee9f1d --- /dev/null +++ b/core/tests/coretests/res/values-land/dimens.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<resources> + <dimen name="resource_cache_test_orientation_dependent">3dp</dimen> +</resources>
\ No newline at end of file diff --git a/core/tests/coretests/res/values/dimens.xml b/core/tests/coretests/res/values/dimens.xml new file mode 100644 index 0000000..00fc414 --- /dev/null +++ b/core/tests/coretests/res/values/dimens.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> +<resources> + <dimen name="resource_cache_test_generic">10dp</dimen> + <dimen name="resource_cache_test_orientation_dependent">20dp</dimen> +</resources>
\ No newline at end of file diff --git a/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java new file mode 100644 index 0000000..3c81853 --- /dev/null +++ b/core/tests/coretests/src/android/animation/AnimatorInflaterTest.java @@ -0,0 +1,61 @@ +/* +* 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 android.animation; + +import android.test.ActivityInstrumentationTestCase2; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +import com.android.frameworks.coretests.R; + +public class AnimatorInflaterTest extends ActivityInstrumentationTestCase2<BasicAnimatorActivity> { + Set<Integer> identityHashes = new HashSet<Integer>(); + + public AnimatorInflaterTest() { + super(BasicAnimatorActivity.class); + } + + private void assertUnique(Object object) { + assertUnique(object, ""); + } + + private void assertUnique(Object object, String msg) { + final int code = System.identityHashCode(object); + assertTrue("object should be unique " + msg + ", obj:" + object, identityHashes.add(code)); + + } + + public void testLoadStateListAnimator() { + StateListAnimator sla1 = AnimatorInflater.loadStateListAnimator(getActivity(), + R.anim.test_state_anim); + sla1.setTarget(getActivity().mAnimatingButton); + StateListAnimator sla2 = AnimatorInflater.loadStateListAnimator(getActivity(), + R.anim.test_state_anim); + assertNull(sla2.getTarget()); + for (StateListAnimator sla : new StateListAnimator[]{sla1, sla2}) { + assertUnique(sla); + assertEquals(3, sla.getTuples().size()); + for (StateListAnimator.Tuple tuple : sla.getTuples()) { + assertUnique(tuple); + assertUnique(tuple.getAnimator()); + } + } + } + +} diff --git a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java index 93808d9..6bcf8fc 100644 --- a/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java +++ b/core/tests/coretests/src/android/animation/BasicAnimatorActivity.java @@ -19,11 +19,14 @@ import com.android.frameworks.coretests.R; import android.app.Activity; import android.os.Bundle; +import android.widget.Button; public class BasicAnimatorActivity extends Activity { + public Button mAnimatingButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.animator_basic); + mAnimatingButton = (Button) findViewById(R.id.animatingButton); } } diff --git a/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java new file mode 100644 index 0000000..e9fd5fb --- /dev/null +++ b/core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java @@ -0,0 +1,224 @@ +/* + * 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 android.content.res; + +import android.test.ActivityInstrumentationTestCase2; +import android.util.TypedValue; + +import com.android.frameworks.coretests.R; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class ConfigurationBoundResourceCacheTest + extends ActivityInstrumentationTestCase2<ResourceCacheActivity> { + + ConfigurationBoundResourceCache<Float> mCache; + + Method mCalcConfigChanges; + + public ConfigurationBoundResourceCacheTest() { + super(ResourceCacheActivity.class); + } + + @Override + protected void setUp() throws Exception { + super.setUp(); + mCache = new ConfigurationBoundResourceCache<Float>(getActivity().getResources()); + } + + public void testGetEmpty() { + assertNull(mCache.get(-1, null)); + } + + public void testSetGet() { + mCache.put(1, null, new DummyFloatConstantState(5f)); + assertEquals(5f, mCache.get(1, null)); + assertNotSame(5f, mCache.get(1, null)); + assertEquals(null, mCache.get(1, getActivity().getTheme())); + } + + public void testSetGetThemed() { + mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f)); + assertEquals(null, mCache.get(1, null)); + assertEquals(5f, mCache.get(1, getActivity().getTheme())); + assertNotSame(5f, mCache.get(1, getActivity().getTheme())); + } + + public void testMultiThreadPutGet() { + mCache.put(1, getActivity().getTheme(), new DummyFloatConstantState(5f)); + mCache.put(1, null, new DummyFloatConstantState(10f)); + assertEquals(10f, mCache.get(1, null)); + assertNotSame(10f, mCache.get(1, null)); + assertEquals(5f, mCache.get(1, getActivity().getTheme())); + assertNotSame(5f, mCache.get(1, getActivity().getTheme())); + } + + public void testVoidConfigChange() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + TypedValue staticValue = new TypedValue(); + long key = 3L; + final Resources res = getActivity().getResources(); + res.getValue(R.dimen.resource_cache_test_generic, staticValue, true); + float staticDim = TypedValue.complexToDimension(staticValue.data, res.getDisplayMetrics()); + mCache.put(key, getActivity().getTheme(), + new DummyFloatConstantState(staticDim, staticValue.changingConfigurations)); + final Configuration cfg = res.getConfiguration(); + Configuration newCnf = new Configuration(cfg); + newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ? + Configuration.ORIENTATION_PORTRAIT + : Configuration.ORIENTATION_LANDSCAPE; + int changes = calcConfigChanges(res, newCnf); + assertEquals(staticDim, mCache.get(key, getActivity().getTheme())); + mCache.onConfigurationChange(changes); + assertEquals(staticDim, mCache.get(key, getActivity().getTheme())); + } + + public void testEffectiveConfigChange() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + TypedValue changingValue = new TypedValue(); + long key = 4L; + final Resources res = getActivity().getResources(); + res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValue, true); + float changingDim = TypedValue.complexToDimension(changingValue.data, + res.getDisplayMetrics()); + mCache.put(key, getActivity().getTheme(), + new DummyFloatConstantState(changingDim, changingValue.changingConfigurations)); + + final Configuration cfg = res.getConfiguration(); + Configuration newCnf = new Configuration(cfg); + newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ? + Configuration.ORIENTATION_PORTRAIT + : Configuration.ORIENTATION_LANDSCAPE; + int changes = calcConfigChanges(res, newCnf); + assertEquals(changingDim, mCache.get(key, getActivity().getTheme())); + mCache.onConfigurationChange(changes); + assertNull(mCache.get(key, getActivity().getTheme())); + } + + public void testConfigChangeMultipleResources() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + TypedValue staticValue = new TypedValue(); + TypedValue changingValue = new TypedValue(); + final Resources res = getActivity().getResources(); + res.getValue(R.dimen.resource_cache_test_generic, staticValue, true); + res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValue, true); + float staticDim = TypedValue.complexToDimension(staticValue.data, res.getDisplayMetrics()); + float changingDim = TypedValue.complexToDimension(changingValue.data, + res.getDisplayMetrics()); + mCache.put(R.dimen.resource_cache_test_generic, getActivity().getTheme(), + new DummyFloatConstantState(staticDim, staticValue.changingConfigurations)); + mCache.put(R.dimen.resource_cache_test_orientation_dependent, getActivity().getTheme(), + new DummyFloatConstantState(changingDim, changingValue.changingConfigurations)); + final Configuration cfg = res.getConfiguration(); + Configuration newCnf = new Configuration(cfg); + newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ? + Configuration.ORIENTATION_PORTRAIT + : Configuration.ORIENTATION_LANDSCAPE; + int changes = calcConfigChanges(res, newCnf); + assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, + getActivity().getTheme())); + assertEquals(changingDim, mCache.get(R.dimen.resource_cache_test_orientation_dependent, + getActivity().getTheme())); + mCache.onConfigurationChange(changes); + assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, + getActivity().getTheme())); + assertNull(mCache.get(R.dimen.resource_cache_test_orientation_dependent, + getActivity().getTheme())); + } + + public void testConfigChangeMultipleThemes() + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { + TypedValue[] staticValues = new TypedValue[]{new TypedValue(), new TypedValue()}; + TypedValue[] changingValues = new TypedValue[]{new TypedValue(), new TypedValue()}; + float staticDim = 0; + float changingDim = 0; + final Resources res = getActivity().getResources(); + for (int i = 0; i < 2; i++) { + res.getValue(R.dimen.resource_cache_test_generic, staticValues[i], true); + staticDim = TypedValue + .complexToDimension(staticValues[i].data, res.getDisplayMetrics()); + + res.getValue(R.dimen.resource_cache_test_orientation_dependent, changingValues[i], + true); + changingDim = TypedValue.complexToDimension(changingValues[i].data, + res.getDisplayMetrics()); + final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null; + mCache.put(R.dimen.resource_cache_test_generic, theme, + new DummyFloatConstantState(staticDim, staticValues[i].changingConfigurations)); + mCache.put(R.dimen.resource_cache_test_orientation_dependent, theme, + new DummyFloatConstantState(changingDim, + changingValues[i].changingConfigurations)); + } + final Configuration cfg = res.getConfiguration(); + Configuration newCnf = new Configuration(cfg); + newCnf.orientation = cfg.orientation == Configuration.ORIENTATION_LANDSCAPE ? + Configuration.ORIENTATION_PORTRAIT + : Configuration.ORIENTATION_LANDSCAPE; + int changes = calcConfigChanges(res, newCnf); + for (int i = 0; i < 2; i++) { + final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null; + assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, theme)); + assertEquals(changingDim, + mCache.get(R.dimen.resource_cache_test_orientation_dependent, theme)); + } + mCache.onConfigurationChange(changes); + for (int i = 0; i < 2; i++) { + final Resources.Theme theme = i == 0 ? getActivity().getTheme() : null; + assertEquals(staticDim, mCache.get(R.dimen.resource_cache_test_generic, theme)); + assertNull(mCache.get(R.dimen.resource_cache_test_orientation_dependent, theme)); + } + } + + private int calcConfigChanges(Resources resources, Configuration configuration) + throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + if (mCalcConfigChanges == null) { + mCalcConfigChanges = Resources.class.getDeclaredMethod("calcConfigChanges", + Configuration.class); + mCalcConfigChanges.setAccessible(true); + } + return (Integer) mCalcConfigChanges.invoke(resources, configuration); + + } + + static class DummyFloatConstantState extends + ConstantState<Float> { + + final Float mObj; + + int mChangingConf = 0; + + DummyFloatConstantState(Float obj) { + mObj = obj; + } + + DummyFloatConstantState(Float obj, int changingConf) { + mObj = obj; + mChangingConf = changingConf; + } + + @Override + public int getChangingConfigurations() { + return mChangingConf; + } + + @Override + public Float newInstance() { + return new Float(mObj); + } + } +} diff --git a/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java b/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java new file mode 100644 index 0000000..f37e549 --- /dev/null +++ b/core/tests/coretests/src/android/content/res/ResourceCacheActivity.java @@ -0,0 +1,37 @@ +/* +* 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 android.content.res; + +import android.annotation.Nullable; +import android.app.Activity; +import android.os.Bundle; + +import java.lang.ref.WeakReference; + +public class ResourceCacheActivity extends Activity { + static WeakReference<ResourceCacheActivity> lastCreatedInstance; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + lastCreatedInstance = new WeakReference<ResourceCacheActivity>(this); + } + + public static ResourceCacheActivity getLastCreatedInstance() { + return lastCreatedInstance == null ? null : lastCreatedInstance.get(); + } +} diff --git a/core/tests/coretests/src/android/net/LinkPropertiesTest.java b/core/tests/coretests/src/android/net/LinkPropertiesTest.java index 4015b3d..abfed6e 100644 --- a/core/tests/coretests/src/android/net/LinkPropertiesTest.java +++ b/core/tests/coretests/src/android/net/LinkPropertiesTest.java @@ -31,8 +31,10 @@ public class LinkPropertiesTest extends TestCase { "2001:0db8:85a3:0000:0000:8a2e:0370:7334"); private static InetAddress DNS1 = NetworkUtils.numericToInetAddress("75.208.7.1"); private static InetAddress DNS2 = NetworkUtils.numericToInetAddress("69.78.7.1"); + private static InetAddress DNS6 = NetworkUtils.numericToInetAddress("2001:4860:4860::8888"); private static InetAddress GATEWAY1 = NetworkUtils.numericToInetAddress("75.208.8.1"); private static InetAddress GATEWAY2 = NetworkUtils.numericToInetAddress("69.78.8.1"); + private static InetAddress GATEWAY6 = NetworkUtils.numericToInetAddress("fe80::6:0000:613"); private static String NAME = "qmi0"; private static int MTU = 1500; @@ -338,14 +340,14 @@ public class LinkPropertiesTest extends TestCase { assertFalse("newname".equals(link.getInterfaceName())); } - assertTrue(rmnet0.removeStackedLink(clat4)); + assertTrue(rmnet0.removeStackedLink("clat4")); assertEquals(0, rmnet0.getStackedLinks().size()); assertEquals(1, rmnet0.getAddresses().size()); assertEquals(1, rmnet0.getLinkAddresses().size()); assertEquals(1, rmnet0.getAllAddresses().size()); assertEquals(1, rmnet0.getAllLinkAddresses().size()); - assertFalse(rmnet0.removeStackedLink(clat4)); + assertFalse(rmnet0.removeStackedLink("clat4")); } private LinkAddress getFirstLinkAddress(LinkProperties lp) { @@ -370,7 +372,7 @@ public class LinkPropertiesTest extends TestCase { assertTrue(stacked.hasGlobalIPv6Address()); assertFalse(lp.hasIPv4Address()); assertFalse(lp.hasGlobalIPv6Address()); - lp.removeStackedLink(stacked); + lp.removeStackedLink("stacked"); assertFalse(lp.hasIPv4Address()); assertFalse(lp.hasGlobalIPv6Address()); @@ -453,4 +455,47 @@ public class LinkPropertiesTest extends TestCase { lp2.setLinkAddresses(lp.getLinkAddresses()); assertTrue(lp.equals(lp)); } + + @SmallTest + public void testIsProvisioned() { + LinkProperties lp4 = new LinkProperties(); + assertFalse("v4only:empty", lp4.isProvisioned()); + lp4.addLinkAddress(LINKADDRV4); + assertFalse("v4only:addr-only", lp4.isProvisioned()); + lp4.addDnsServer(DNS1); + assertFalse("v4only:addr+dns", lp4.isProvisioned()); + lp4.addRoute(new RouteInfo(GATEWAY1)); + assertTrue("v4only:addr+dns+route", lp4.isProvisioned()); + + LinkProperties lp6 = new LinkProperties(); + assertFalse("v6only:empty", lp6.isProvisioned()); + lp6.addLinkAddress(LINKADDRV6LINKLOCAL); + assertFalse("v6only:fe80-only", lp6.isProvisioned()); + lp6.addDnsServer(DNS6); + assertFalse("v6only:fe80+dns", lp6.isProvisioned()); + lp6.addRoute(new RouteInfo(GATEWAY6)); + assertFalse("v6only:fe80+dns+route", lp6.isProvisioned()); + lp6.addLinkAddress(LINKADDRV6); + assertTrue("v6only:fe80+global+dns+route", lp6.isProvisioned()); + lp6.removeLinkAddress(LINKADDRV6LINKLOCAL); + assertTrue("v6only:global+dns+route", lp6.isProvisioned()); + + LinkProperties lp46 = new LinkProperties(); + lp46.addLinkAddress(LINKADDRV4); + lp46.addLinkAddress(LINKADDRV6); + lp46.addDnsServer(DNS1); + lp46.addDnsServer(DNS6); + assertFalse("dualstack:missing-routes", lp46.isProvisioned()); + lp46.addRoute(new RouteInfo(GATEWAY1)); + assertTrue("dualstack:v4-provisioned", lp46.isProvisioned()); + lp6.addRoute(new RouteInfo(GATEWAY6)); + assertTrue("dualstack:both-provisioned", lp46.isProvisioned()); + + // A link with an IPv6 address and default route, but IPv4 DNS server. + LinkProperties mixed = new LinkProperties(); + mixed.addLinkAddress(LINKADDRV6); + mixed.addDnsServer(DNS1); + mixed.addRoute(new RouteInfo(GATEWAY6)); + assertFalse("mixed:addr6+route6+dns4", mixed.isProvisioned()); + } } diff --git a/data/etc/platform.xml b/data/etc/platform.xml index d3869b8..9fd8a4a 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -119,6 +119,10 @@ <group gid="audio" /> </permission> + <permission name="android.permission.ACCESS_FM_RADIO" > + <group gid="media" /> + </permission> + <!-- ================================================================== --> <!-- ================================================================== --> <!-- ================================================================== --> diff --git a/docs/html/about/versions/android-5.0.jd b/docs/html/about/versions/android-5.0.jd index f8d8ab6..a438420 100644 --- a/docs/html/about/versions/android-5.0.jd +++ b/docs/html/about/versions/android-5.0.jd @@ -23,6 +23,7 @@ sdk.platform.apiLevel=21 <li><a href="#BehaviorGetRecentTasks">If your app uses getRecentTasks()...</a></li> <li><a href="#64BitSupport">If you are using the Android Native Development Kit (NDK)...</a></li> <li><a href="#BindService">If your app binds to a Service...</a></li> +<li><a href="#BehaviorWebView">If your app uses a WebView...</a></li> </ol> </li> <li><a href="#UI">User Interface</a> @@ -234,8 +235,8 @@ the system can present notifications correctly in vibration.</p> <p>Setting the device to -{@link android.media.AudioManager#RINGER_MODE_SILENT RINGER_MODE_SILENT} now -causes the device to enter the new priority mode. The device leaves priority +{@link android.media.AudioManager#RINGER_MODE_SILENT RINGER_MODE_SILENT} causes +the device to enter the new priority mode. The device leaves priority mode if you set it to {@link android.media.AudioManager#RINGER_MODE_NORMAL RINGER_MODE_NORMAL} or {@link android.media.AudioManager#RINGER_MODE_NORMAL RINGER_MODE_VIBRATE}.</p> @@ -366,6 +367,31 @@ and throws an exception if given an implicit intent. To ensure your app is secure, use an explicit intent when starting or binding your {@link android.app.Service}, and do not declare intent filters for the service.</p> +<h3 id="BehaviorWebView">If your app uses WebView...</h3> + +<p>Android 5.0 changes the default behavior for your app.</p> +<ul> +<li><strong>If your app targets API level 21 or higher:</strong> + <ul> + <li>The system + blocks <a href="https://developer.mozilla.org/en-US/docs/Security/MixedContent" + class="external-link">mixed content</a> and third party cookies by default. To allow mixed + content and third party cookies, use the + {@link android.webkit.WebSettings#setMixedContentMode(int) setMixedContentMode()} +and {@link android.webkit.CookieManager#setAcceptThirdPartyCookies(android.webkit.WebView, boolean) setAcceptThirdPartyCookies()} +methods respectively.</li> + <li>The system now intelligently chooses portions of the HTML + document to draw. This new default behavior helps to reduce memory + footprint and increase performance. If you want to + render the whole document at once, disable this optimization by calling + {@link android.webkit.WebView#enableSlowWholeDocumentDraw()}.</li> + </ul> +</li> +<li><strong>If your app targets API levels lower than 21:</strong> The system + allows mixed content and third party cookies, and always renders the whole + document at once.</li> +</ul> + <h2 id="UI">User Interface</h2> <h3 id="MaterialDesign">Material design support</h3> @@ -470,7 +496,7 @@ request the user’s permission by launching a screen capture dialog using an method.</p> <p>For an example of how to use the new APIs, see the {@code MediaProjectionDemo} -class in the {@code ApiDemos} sample project.</p> +class in the sample project.</p> <h2 id="Notifications">Notifications</h2> diff --git a/docs/html/about/versions/lollipop.jd b/docs/html/about/versions/lollipop.jd index 085dc24..3ee0a86 100644 --- a/docs/html/about/versions/lollipop.jd +++ b/docs/html/about/versions/lollipop.jd @@ -206,15 +206,16 @@ video apps and games to display smooth synchronized content.</p> <p>Android 5.0 also adds support for <strong>multimedia tunneling</strong> to provide the best experience for ultra-high definition (4K) content and the ability to play compressed audio and video data together. </p> -<!-- + <div class="figure" style="width:320px; margin:1em 0 0 20px;padding-left:2em;"> <img style="float:right; margin:0 1em 1em 2em" src="{@docRoot}images/android-5.0/managed_apps_launcher@2x.png" srcset="{@docRoot}images/android-5.0/managed_apps_launcher@2x.png 2x" alt="" width="300" /> -<p class="img-caption">Android Work users have a unified view of their personal and work apps, which are badged for easy identification.</p> +<p class="img-caption">Users have a unified view of their personal and work apps, which are +badged for easy identification.</p> </div> ---> + <h2 id="Work">Android in the workplace</h2> diff --git a/docs/html/auto/overview.jd b/docs/html/auto/overview.jd index cf63b98..ae1efec 100644 --- a/docs/html/auto/overview.jd +++ b/docs/html/auto/overview.jd @@ -207,7 +207,7 @@ playback state through callbacks.</li> <p>The Android Auto app uses a car-specific UI model to display content and user interaction opportunities. Android Auto provides you with a standard UI designed to minimize driver -distraction. You do not have to test a custom UI for for driver distraction, which is a +distraction. You do not have to test a custom UI for driver distraction, which is a lengthy and expensive process involving multiple legislations across the globe and different standards for each vehicle OEM.</p> @@ -217,7 +217,7 @@ media apps. You can customize the UI colors, action icons, background images, an <h3 id="launchapp">Launcher</h3> <p>The launcher shows all the compatible media apps installed on the user’s -Android device and lets users select one of them from an scrollable list:</p> +Android device and lets users select one of them from a scrollable list:</p> <div class="auto-img-container-single"> <div class="auto-img-container"> diff --git a/docs/html/distribute/essentials/essentials_toc.cs b/docs/html/distribute/essentials/essentials_toc.cs index 4e53468..a1c9575 100644 --- a/docs/html/distribute/essentials/essentials_toc.cs +++ b/docs/html/distribute/essentials/essentials_toc.cs @@ -17,6 +17,12 @@ </div> </li> <li class="nav-section"> + <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/quality/wear.html"> + <span class="en">Wear App Quality</span> + </a> + </div> + </li> + <li class="nav-section"> <div class="nav-section empty" style="font-weight:normal"><a href="<?cs var:toroot?>distribute/essentials/optimizing-your-app.html"> <span class="en">Optimize Your App</span> </a> diff --git a/docs/html/distribute/essentials/quality/tv.jd b/docs/html/distribute/essentials/quality/tv.jd index 8e17157..b13307e 100644 --- a/docs/html/distribute/essentials/quality/tv.jd +++ b/docs/html/distribute/essentials/quality/tv.jd @@ -234,7 +234,7 @@ page.image=/distribute/images/gp-tv-quality.png </td> <td> <p style="margin-bottom:.5em;"> - App does not depend on a remote controller having a menu button to access user interface + App does not depend on a remote controller having a Menu button to access user interface controls. (<a href="{@docRoot}training/tv/start/navigation.html#d-pad-navigation">Learn how</a>) </p> @@ -291,8 +291,8 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> </td> <td> <p style="margin-bottom:.5em;"> - App manifest sets an intent type of {@code ACTION_MAIN} with category - {@code CATEGORY_LEANBACK_LAUNCHER}. + App manifest sets an intent type of {@link android.content.Intent#ACTION_MAIN} with category + {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER}. (<a href="{@docRoot}training/tv/start/start.html#tv-activity">Learn how</a>) </p> </td> @@ -321,8 +321,9 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> </td> <td> <p style="margin-bottom:.5em;"> - If the app requires a game controller, the app manifest sets the {@code uses-feature} setting - {@code android.hardware.gamepad} to {@code required="true"}. + If the app uses a game controller as it's primary input method, it declares the appropriate + requirement with the <a href="{@docRoot}guide/topics/manifest/uses-feature-element.html" + >{@code <uses-feature>}</a> manifest tag. (<a href="{@docRoot}training/tv/games/index.html#gamepad">Learn how</a>) </p> </td> @@ -334,9 +335,9 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> </td> <td> <p style="margin-bottom:.5em;"> - If the app provides user instructions for use of game controllers, the instructions - do not include a controller with any branding. - (<a href="{@docRoot}training/tv/games/index.html#generic-controllers">Learn how</a>) + If the app provides visual instructions for using game controllers, the instructions should + be free of branding and show a compatible button layout. + (<a href="{@docRoot}training/tv/games/index.html#ControllerHelp">Learn how</a>) </p> </td> </tr> @@ -351,7 +352,7 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> </td> <td> <p style="margin-bottom:.5em;"> - App enables interaction with any advertising using D-pad controls. + App allows interaction with advertising using D-pad controls. (<a href="{@docRoot}training/tv/start/navigation.html#d-pad-navigation">Learn how</a>) </p> </td> @@ -363,7 +364,7 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> </td> <td> <p style="margin-bottom:.5em;"> - For advertising that uses full-screen, non-video ads, the app allows the user to + For advertising that uses fullscreen, non-video ads, the app allows the user to immediately dismiss the ad with D-pad controls. </p> </td> @@ -375,7 +376,7 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> </td> <td> <p style="margin-bottom:.5em;"> - For advertising that uses clickable, non-full screen, non-video ads, the app does not allow + For advertising that uses clickable, non-fullscreen, non-video ads, the app does not allow ads to link to a web URL. </p> </td> @@ -387,7 +388,7 @@ data-sortorder="-timestamp" data-cardsizes="9x3" data-maxresults="6"> </td> <td> <p style="margin-bottom:.5em;"> - For advertising that uses clickable, non-full screen, non-video ads, the app does not allow + For advertising that uses clickable, non-fullscreen, non-video ads, the app does not allow ads to link to another app that is not available on TV devices. </p> </td> diff --git a/docs/html/distribute/essentials/quality/wear.jd b/docs/html/distribute/essentials/quality/wear.jd new file mode 100644 index 0000000..4125027 --- /dev/null +++ b/docs/html/distribute/essentials/quality/wear.jd @@ -0,0 +1,416 @@ +page.title=Wear App Quality +page.tags="wear","wearables","quality","guidelines" +page.metaDescription=Wearables are smaller devices that are built for glanceability and require unique apps to provide just the right information at the the right time. +page.image=/distribute/images/gp-wear-quality.png +@jd:body + +<div id="qv-wrapper"><div id="qv"> +<h2>Quality Criteria</h2> + <ol> + <li><a href="#ux">Design and Interaction</a></li> + <li><a href="#fn">Functionality</a></li> + <li><a href="#faq">Frequently Asked Questions</a></li> + </ol> + + <h2>You Should Also Read</h2> + <ol> + <li><a href="{@docRoot}distribute/essentials/quality/core.html"> + Core App Quality</a></li> + <li><a href="{@docRoot}distribute/essentials/optimizing-your-app.html"> + Optimize Your App</a></li> + <li><a href="{@docRoot}design/patterns/notifications.html"> + Notifications</a></li> + </ol> +</div> +</div> + +<img src="{@docRoot}distribute/images/gp-wear-quality.png" style="width:480px;"> + +<p> + Android Wear aims to provide users with just the right information at just the right time. Great + Android Wear experiences are launched automatically, glanceable, and require zero or low user + interaction. Designing apps for wearables is substantially different than designing for phones or + tablets. There are different strengths and weaknesses, different use cases, and different + ergonomics to take into consideration. +</p> + +<p> + The first step toward creating a great experience for users on Wear is to read the + <a href="{@docRoot}design/wear/index.html">Android Wear design guidelines</a>, which provides + instructions on how to build the best user experience for Wear apps. You should also review the + <a href="{@docRoot}training/building-wearables.html">Building Apps for Wearables</a> training, to + understand the basic implementation requirements for a Wear app. +</p> + +<p class="caution"> + <strong>Important:</strong> To ensure a great user experience, apps for wearables must meet + specific requirements for usability. Only apps that meet the following quality criteria will + qualify as an Android Wear app on Google Play. Qualifying as a Wear app will make it easier for + Android Wear users to discover your app on Google Play. +</p> + +<p class="note"> + <strong>Note:</strong> You will be able to submit your apps for Android Wear review when the + public release of Android 5.0 launches on November 3. Stay tuned for more information about how to + submit your apps for Android Wear review through the <a href="https://play.google.com/apps/publish/signup/">Google Play Developer Console</a>. +</p> + +<div class="headerLine"> + <h2 id="fn"> + Functionality + </h2> + + +</div> + +<p> + These criteria ensure that your app is configured correctly and provides the expected + functional behavior. +</p> + + +<table> +<tr> + <th style="width:2px;"> + Type + </th> + <th style="width:54px;"> + ID + </th> + <th> + Description + </th> +</tr> + +<tr> + <td rowspan="1" id="general"> + General + </td> + + <td id="WR-GL"> + WR-GL + </td> + <td> + <p style="margin-bottom:.5em;"> + Handheld app includes either notifications with wearable-specific functionality or a wearable + app that runs directly on the Wear device. + (<a href="{@docRoot}training/building-wearables.html">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td rowspan="1" id="packaging"> + Packaging + </td> + + <td id="WR-PK"> + WR-PK + </td> + <td> + <p style="margin-bottom:.5em;"> + Wearable apps that run directly on the device are packaged inside the primary handheld app. + (<a href="{@docRoot}training/wearables/apps/packaging.html">Learn how</a>) + </p> + </td> +</tr> + + +<tr> + <td rowspan="3" id="functional-notifications"> + Notifications + </td> + + <td id="WR-FW"> + WR-FW + </td> + <td> + <p style="margin-bottom:.5em;"> + Notifications with wearable-specific functionality use a {@code RemoteInput} or + {@code WearableExtender}. + (<a href="{@docRoot}training/wearables/notifications/index.html">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-FR"> + WR-FR + </td> + <td> + <p style="margin-bottom:.5em;"> + Notifications for messaging apps allow users to reply via voice input or quick responses. + (<a href="{@docRoot}training/wearables/notifications/voice-input.html">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-FG"> + WR-FG + </td> + <td> + <p style="margin-bottom:.5em;"> + Similar notifications are grouped together in a stack. + (<a href="{@docRoot}training/wearables/notifications/stacks.html">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td rowspan="2" id="gestures"> + Gestures + </td> + + <td id="WR-GP"> + WR-GP + </td> + <td> + <p style="margin-bottom:.5em;"> + Full-screen activities use long press for the sole purpose of prompting to quit. + <br/> + (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-GD"> + WR-GD + </td> + <td> + <p style="margin-bottom:.5em;"> + If the app disables the swipe-to-dismiss gesture in a full-screen activity, it responds to the + long-press-to-dismiss gesture in that activity. + (<a href="{@docRoot}training/wearables/ui/exit.html">Learn how</a>) + </p> + </td> +</tr> + +</table> + + +<h3 class="rel-resources clearfloat">Related resources</h3> + +<div class="resource-widget resource-flow-layout col-13" data-query= +"collection:distribute/essentials/wearqualityguidelines/functionality" +data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6"> +</div> + +<div class="headerLine"> + <h2 id="ux"> + Visual Design and User Interaction + </h2> + + +</div> + +<p> + These criteria ensure that your app follows critical design and interaction patterns to provide a + consistent, intuitive, and enjoyable user experience on wearables. +</p> + +<table> + +<tr> + <th style="width:2px;"> + Type + </th> + <th style="width:54px;"> + ID + </th> + <th> + Description + </th> +</tr> + +<tr> + <td rowspan="3" id="layout"> + Layout + </td> + + <td id="WR-LS"> + WR-LS + </td> + <td> + <p style="margin-bottom:.5em;"> + App user interface is formatted appropriately for square displays. App content fits within + the physical display area and no text or controls are cut off by the screen edges. + <br/> + (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-LR"> + WR-LR + </td> + <td> + <p style="margin-bottom:.5em;"> + App user interface is formatted appropriately for round displays. App content fits within + the physical display area and no text or controls are cut off by the screen edges. + <br/> + (<a href="{@docRoot}training/wearables/ui/layouts.html">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-TC"> + WR-TC + </td> + <td> + <p style="margin-bottom:.5em;"> + App text is large and glanceable with a suggested minimum size of 16sp. + (<a href="{@docRoot}design/wear/style.html#Typography">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td rowspan="1" id="launcher"> + Launcher + </td> + + <td id="WR-LN"> + WR-LN + </td> + <td> + <p style="margin-bottom:.5em;"> + App launcher string is the app name, not a command phrase. + (<a href="{@docRoot}guide/topics/manifest/intent-filter-element.html">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td rowspan="5" id="notifications"> + Notifications + </td> + + <td id="WR-NC"> + WR-NC + </td> + <td> + <p style="margin-bottom:.5em;"> + App displays confirmation animations when appropriate. + (<a href="{@docRoot}design/wear/patterns.html#Countdown">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-NR"> + WR-NR + </td> + <td> + <p style="margin-bottom:.5em;"> + Notification cards have the app icon visible at the top right edge. The one exception is if the + notification card has single-action controls, for example a media playback card. + <br/> + (<a href="{@docRoot}design/wear/style.html#Assets">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-WI"> + WR-WI + </td> + <td> + <p style="margin-bottom:.5em;"> + Notification actions have a white icon, action title, and transparent background. + <br/> + (<a href="{@docRoot}training/wearables/notifications/creating.html#ActionButtons">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-PB"> + WR-PB + </td> + <td> + <p style="margin-bottom:.5em;"> + Notification photo backgrounds are used only to convey information, not to brand a card. + (<a href="{@docRoot}design/wear/style.html#Branding">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td id="WR-PR"> + WR-PR + </td> + <td> + <p style="margin-bottom:.5em;"> + Notification photo backgrounds have a resolution of at least 400x400. + (<a href="{@docRoot}training/wearables/notifications/creating.html#AddWearableFeatures">Learn how</a>) + </p> + </td> +</tr> + +<tr> + <td rowspan="1" id="googleplay"> + Google Play + </td> + + <td id="WR-GS"> + WR-GS + </td> + <td> + <p style="margin-bottom:.5em;"> + App includes at least one Wear screenshot in its Play Store Listing. + (<a href="https://support.google.com/googleplay/android-developer/answer/1078870?hl=en">Learn how</a>) + </p> + </td> +</tr> + +</table> + + +<h3 class="rel-resources clearfloat">Related resources</h3> + +<div class="resource-widget resource-flow-layout col-13" data-query= +"collection:distribute/essentials/wearqualityguidelines/visualdesign" +data-sortorder="-timestamp" data-cardsizes="6x2" data-maxresults="6"> +</div> + +<div class="headerLine"> + <h2 id="faq"> + Frequently Asked Questions + </h2> +</div> + +<p style="margin-top:30px;"> + <strong>After I submit my app for Android Wear review, how will I find out if my app does not meet + all the requirements for Wear?</strong> +</p> +<p> + If your app does not meet the usability requirements described on this page, the Play Store team + will contact you through the email address specified in the <a href= + "https://play.google.com/apps/publish/">Google Play Developer Console</a> account associated with + the app. +</p> +<p class="caution"> + <strong>Caution:</strong> Make sure your app meets the <a href="#fn">functionality + requirements</a>, otherwise your app will not be considered a Wear app and will not be reviewed + for Wear <a href="#ux">design and interaction</a>. +</p> +<p class="note"> + <strong>Note:</strong> You will be able to submit your apps for additional Android Wear review when + the public release of Android 5.0 launches on November 3. +</p> + + +<p style="margin-top:30px;"> + <strong>If my app does not meet the Wear requirements, will my new or updated app still appear on + Google Play for phones and tablets and still be installable on wearables?</strong> +</p> +<p> + Yes. The requirements described above only determine whether your app will be identified as an + Android Wear app on Google Play and easier for Android Wear users to discover. If your app is not + accepted as a Wear app, it will still be available to other device types, such as phones and + tablets, and it will still be installable on wearables. +</p> diff --git a/docs/html/distribute/images/gp-wear-quality.png b/docs/html/distribute/images/gp-wear-quality.png Binary files differnew file mode 100644 index 0000000..a51a32c --- /dev/null +++ b/docs/html/distribute/images/gp-wear-quality.png diff --git a/docs/html/google/play/billing/billing_testing.jd b/docs/html/google/play/billing/billing_testing.jd index 10f5326..36456cc 100644 --- a/docs/html/google/play/billing/billing_testing.jd +++ b/docs/html/google/play/billing/billing_testing.jd @@ -10,7 +10,7 @@ page.tags="inapp, billing, iap" <ol> <li><a href="#testing-purchases">Testing In-app Purchases</a></li> <li><a href="#billing-testing-static">Testing with Static Responses</a></li> - <li><a href="#billing-testing-real">Setting Up for Test Purchases</a></li> + <li><a href="#billing-testing-test">Setting Up for Test Purchases</a></li> <li><a href="#draft_apps">Draft Apps are No Longer Supported</a></li> </ol> <h2>See also</h2> diff --git a/docs/html/guide/components/intents-common.jd b/docs/html/guide/components/intents-common.jd index ac61924..d4b033a 100644 --- a/docs/html/guide/components/intents-common.jd +++ b/docs/html/guide/components/intents-common.jd @@ -80,6 +80,13 @@ page.tags="IntentFilter" <li><a href="#DialPhone">Initiate a phone call</a></li> </ol> </li> + </li> + <li><a href="#Search">Search</a> + <ol> + <li><a href="#SearchOnApp">Search in a specific app</a></li> + <li><a href="#SearchWeb">Perform a web search</a></li> + </ol> + </li> <li><a href="#Settings">Settings</a> <ol> <li><a href="#OpenSettings">Open a specific section of Settings</a></li> @@ -93,7 +100,6 @@ page.tags="IntentFilter" <li><a href="#Browser">Web Browser</a> <ol> <li><a href="#ViewUrl">Load a web URL</a></li> - <li><a href="#SearchWeb">Perform a web search</a></li> </ol> </li> <li><a href="#AdbIntents">Verify Intents with the Android Debug Bridge</a></li> @@ -205,7 +211,8 @@ on this page in response to voice commands. For more information, see <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" + height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -302,7 +309,8 @@ android.provider.AlarmClock#ACTION_SET_ALARM} intent, your app must have the <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -605,7 +613,8 @@ in an extra named <code>"data"</code>.</p> <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -660,7 +669,8 @@ public void capturePhoto() { <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -1351,7 +1361,8 @@ Framework</a> guide.</p> <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -1362,14 +1373,21 @@ Framework</a> guide.</p> </ul> </div> -<p>To track a bike ride, use the <code>"vnd.google.fitness.TRACK"</code> action with the -<code>"vnd.google.fitness.activity/biking"</code> MIME type and set the <code>"actionStatus"</code> -extra to <code>"ActiveActionStatus"</code> when starting and to <code>"CompletedActionStatus"</code> -when stopping.</p> +<p>To track a bike ride, use the +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> +<code>ACTION_TRACK</code></a> action with the <code>"vnd.google.fitness.activity/biking"</code> +MIME type and set the +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS"> +<code>EXTRA_STATUS</code></a> extra to +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE"> +<code>STATUS_ACTIVE</code></a> when starting and to +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED"> +<code>STATUS_COMPLETED</code></a> when stopping.</p> <dl> <dt><b>Action</b></dt> - <dd><code>"vnd.google.fitness.TRACK"</code><dd> + <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> + <code>ACTION_TRACK</code></a><dd> <dt><b>Data URI</b></dt> <dd>None</dd> @@ -1380,9 +1398,12 @@ when stopping.</p> <dt><b>Extras</b></dt> <dd> <dl> - <dt><code>"actionStatus"</code></dt> - <dd>A string with the value <code>"ActiveActionStatus"</code> when starting and - <code>"CompletedActionStatus"</code> when stopping.</dd> + <dt><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS"> + <code>EXTRA_STATUS</code></a></dt> + <dd>A string with the value <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE"> + <code>STATUS_ACTIVE</code></a> when starting and + <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED"> + <code>STATUS_COMPLETED</code></a> when stopping.</dd> </dl> </dd> </dl> @@ -1391,9 +1412,9 @@ when stopping.</p> <p><b>Example intent:</b></p> <pre> public void startBikeRide() { - Intent intent = new Intent("vnd.google.fitness.TRACK") + Intent intent = new Intent(FitnessIntents.ACTION_TRACK) .setType("vnd.google.fitness.activity/biking") - .putExtra("actionStatus", "ActiveActionStatus"); + .putExtra(FitnessIntents.EXTRA_STATUS, FitnessIntents.STATUS_ACTIVE); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } @@ -1422,7 +1443,8 @@ public void startBikeRide() { <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -1433,14 +1455,21 @@ public void startBikeRide() { </ul> </div> -<p>To track a run, use the <code>"vnd.google.fitness.TRACK"</code> action with the -<code>"vnd.google.fitness.activity/running"</code> MIME type and set the <code>"actionStatus"</code> -extra to <code>"ActiveActionStatus"</code> when starting and to <code>"CompletedActionStatus"</code> -when stopping.</p> +<p>To track a run, use the +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> +<code>ACTION_TRACK</code></a> action with the <code>"vnd.google.fitness.activity/running"</code> +MIME type and set the +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS"> +<code>EXTRA_STATUS</code></a> extra to +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE"> +<code>STATUS_ACTIVE</code></a> when starting and to +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED"> +<code>STATUS_COMPLETED</code></a> when stopping.</p> <dl> <dt><b>Action</b></dt> - <dd><code>"vnd.google.fitness.TRACK"</code><dd> + <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> + <code>ACTION_TRACK</code></a><dd> <dt><b>Data URI</b></dt> <dd>None</dd> @@ -1451,9 +1480,12 @@ when stopping.</p> <dt><b>Extras</b></dt> <dd> <dl> - <dt><code>"actionStatus"</code></dt> - <dd>A string with the value <code>"ActiveActionStatus"</code> when starting and - <code>"CompletedActionStatus"</code> when stopping.</dd> + <dt><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS"> + <code>EXTRA_STATUS</code></a></dt> + <dd>A string with the value <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE"> + <code>STATUS_ACTIVE</code></a> when starting and + <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED"> + <code>STATUS_COMPLETED</code></a> when stopping.</dd> </dl> </dd> </dl> @@ -1462,9 +1494,9 @@ when stopping.</p> <p><b>Example intent:</b></p> <pre> public void startRun() { - Intent intent = new Intent("vnd.google.fitness.TRACK") + Intent intent = new Intent(FitnessIntents.ACTION_TRACK) .setType("vnd.google.fitness.activity/running") - .putExtra("actionStatus", "ActiveActionStatus"); + .putExtra(FitnessIntents.EXTRA_STATUS, FitnessIntents.STATUS_ACTIVE); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } @@ -1492,7 +1524,8 @@ public void startRun() { <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -1503,14 +1536,21 @@ public void startRun() { </ul> </div> -<p>To track a workout, use the <code>"vnd.google.fitness.TRACK"</code> action with the -<code>"vnd.google.fitness.activity/other"</code> MIME type and set the <code>"actionStatus"</code> -extra to <code>"ActiveActionStatus"</code> when starting and to <code>"CompletedActionStatus"</code> -when stopping.</p> +<p>To track a workout, use the +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> +<code>ACTION_TRACK</code></a> action with the <code>"vnd.google.fitness.activity/other"</code> +MIME type and set the +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS"> +<code>EXTRA_STATUS</code></a> extra to +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE"> +<code>STATUS_ACTIVE</code></a> when starting and to +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED"> +<code>STATUS_COMPLETED</code></a> when stopping.</p> <dl> <dt><b>Action</b></dt> - <dd><code>"vnd.google.fitness.TRACK"</code><dd> + <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> + <code>ACTION_TRACK</code></a><dd> <dt><b>Data URI</b></dt> <dd>None</dd> @@ -1521,9 +1561,12 @@ when stopping.</p> <dt><b>Extras</b></dt> <dd> <dl> - <dt><code>"actionStatus"</code></dt> - <dd>A string with the value <code>"ActiveActionStatus"</code> when starting and - <code>"CompletedActionStatus"</code> when stopping.</dd> + <dt><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#EXTRA_STATUS"> + <code>EXTRA_STATUS</code></a></dt> + <dd>A string with the value <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_ACTIVE"> + <code>STATUS_ACTIVE</code></a> when starting and + <a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#STATUS_COMPLETED"> + <code>STATUS_COMPLETED</code></a> when stopping.</dd> </dl> </dd> </dl> @@ -1532,9 +1575,9 @@ when stopping.</p> <p><b>Example intent:</b></p> <pre> public void startWorkout() { - Intent intent = new Intent("vnd.google.fitness.TRACK") + Intent intent = new Intent(FitnessIntents.ACTION_TRACK) .setType("vnd.google.fitness.activity/other") - .putExtra("actionStatus", "ActiveActionStatus"); + .putExtra(FitnessIntents.EXTRA_STATUS, FitnessIntents.STATUS_ACTIVE); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); } @@ -1562,7 +1605,8 @@ public void startWorkout() { <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -1572,12 +1616,15 @@ public void startWorkout() { </ul> </div> -<p>To show the user's heart rate, use the <code>"vnd.google.fitness.VIEW"</code> action with the -<code>"vnd.google.fitness.data_type<br/>/com.google.heart_rate.bpm"</code> MIME type.</p> +<p>To show the user's heart rate, use the +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW"> +<code>ACTION_VIEW</code></a> action with the +<code>"vnd.google.fitness.data_type/com.google.heart_rate.bpm"</code> MIME type.</p> <dl> <dt><b>Action</b></dt> - <dd><code>"vnd.google.fitness.VIEW"</code><dd> + <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW"> + <code>ACTION_VIEW</code></a><dd> <dt><b>Data URI</b></dt> <dd>None</dd> @@ -1592,8 +1639,8 @@ public void startWorkout() { <p><b>Example intent:</b></p> <pre> -public void showHR() { - Intent intent = new Intent("vnd.google.fitness.VIEW") +public void showHeartRate() { + Intent intent = new Intent(FitnessIntents.ACTION_VIEW) .setType("vnd.google.fitness.data_type/com.google.heart_rate.bpm"); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); @@ -1623,7 +1670,8 @@ public void showHR() { <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -1633,12 +1681,16 @@ public void showHR() { </ul> </div> -<p>To show the user's step count, use the <code>"vnd.google.fitness.VIEW"</code> action with the -<code>"vnd.google.fitness.data_type<br/>/com.google.step_count.cumulative"</code> MIME type.</p> +<p>To show the user's step count, use the +<a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW"> +<code>ACTION_VIEW</code></a> action with the +<code>"vnd.google.fitness.data_type<br/>/com.google.step_count<br/>.cumulative"</code> MIME +type.</p> <dl> <dt><b>Action</b></dt> - <dd><code>"vnd.google.fitness.VIEW"</code><dd> + <dd><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW"> + <code>ACTION_VIEW</code></a><dd> <dt><b>Data URI</b></dt> <dd>None</dd> @@ -1654,7 +1706,7 @@ public void showHR() { <p><b>Example intent:</b></p> <pre> public void showStepCount() { - Intent intent = new Intent("vnd.google.fitness.VIEW") + Intent intent = new Intent(FitnessIntents.ACTION_VIEW) .setType("vnd.google.fitness.data_type/com.google.step_count.cumulative"); if (intent.resolveActivity(getPackageManager()) != null) { startActivity(intent); @@ -1689,7 +1741,8 @@ public void showStepCount() { <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -1888,7 +1941,8 @@ public void playMedia(Uri file) { <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -2134,7 +2188,8 @@ but the user must press the <em>Call</em> button to begin the phone call.</p> <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -2211,6 +2266,98 @@ public void dialPhoneNumber(String phoneNumber) { +<h2 id="Search">Search</h2> + +<h3 id="SearchOnApp">Search using a specific app</h3> + +<!-- Google Now box --> +<div class="now-box"> + <div class="now-img-cont"> + <a href="#Now"> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30"/></a> + </div> + <p class="now-title">Google Now</p> + <ul> + <li>"search for cat videos on myvideoapp"</li> + </ul> +</div> + +<p>To support search within the context of your app, declare an intent filter in your app with +the <code>SEARCH_ACTION</code> action, as shown in the example intent filter below.</p> + +<dl> +<dt><b>Action</b></dt> +<dd> + <dl> + <dt><code>"com.google.android.gms.actions.SEARCH_ACTION"</code></dt> + <dd>Support search queries from Google Now.</dd> + </dl> +</dd> + +<dt><b>Extras</b></dt> +<dd> + <dl> + <dt><code>{@link android.app.SearchManager#QUERY}</code></dt> + <dd>A string that contains the search query.</dd> + <dl> +</dd> +</dl> + +<p><b>Example intent filter:</b></p> +<pre> +<activity android:name=".SearchActivity"> + <intent-filter> + <action android:name="com.google.android.gms.actions.SEARCH_ACTION"/> + <category android:name="android.intent.category.DEFAULT"/> + </intent-filter> +</activity> +</pre> + + + +<h3 id="SearchWeb">Perform a web search</h3> + +<p>To initiate a web search, use the {@link android.content.Intent#ACTION_WEB_SEARCH} action +and specify the search string in the +{@link android.app.SearchManager#QUERY SearchManager.QUERY} extra.</p> + + +<dl> + <dt><b>Action</b></dt> + <dd>{@link android.content.Intent#ACTION_WEB_SEARCH}</dd> + + <dt><b>Data URI Scheme</b></dt> + <dd>None</dd> + + <dt><b>MIME Type</b></dt> + <dd>None</dd> + + <dt><b>Extras</b></dt> + <dd> + <dl> + <dt>{@link android.app.SearchManager#QUERY SearchManager.QUERY}</dt> + <dd>The search string.</dd> + </dl> + </dd> +</dl> + +<p><b>Example intent:</b></p> +<pre> +public void searchWeb(String query) { + Intent intent = new Intent(Intent.ACTION_SEARCH); + intent.putExtra(SearchManager.QUERY, query); + if (intent.resolveActivity(getPackageManager()) != null) { + startActivity(intent); + } +} +</pre> + + + + + + <h2 id="Settings">Settings</h2> @@ -2379,7 +2526,8 @@ at {@link android.provider.Telephony}.</p> <div class="now-box"> <div class="now-img-cont"> <a href="#Now"> - <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" width="30" height="30" alt=""/> + <img src="{@docRoot}guide/components/images/voice-icon.png" class="now-img" + width="30" height="30" alt=""/> </a> </div> <p class="now-title">Google Now</p> @@ -2447,46 +2595,6 @@ open your Android app instead of your web page.</p> -<h3 id="SearchWeb">Perform a web search</h3> - -<p>To initiate a web search, use the {@link android.content.Intent#ACTION_WEB_SEARCH} action -and specify the search string in the -{@link android.app.SearchManager#QUERY SearchManager.QUERY} extra.</p> - - -<dl> - <dt><b>Action</b></dt> - <dd>{@link android.content.Intent#ACTION_WEB_SEARCH}</dd> - - <dt><b>Data URI Scheme</b></dt> - <dd>None</dd> - - <dt><b>MIME Type</b></dt> - <dd>None</dd> - - <dt><b>Extras</b></dt> - <dd> - <dl> - <dt>{@link android.app.SearchManager#QUERY SearchManager.QUERY}</dt> - <dd>The search string.</dd> - </dl> - </dd> -</dl> - -<p><b>Example intent:</b></p> -<pre> -public void searchWeb(String query) { - Intent intent = new Intent(Intent.ACTION_SEARCH); - intent.putExtra(SearchManager.QUERY, query); - if (intent.resolveActivity(getPackageManager()) != null) { - startActivity(intent); - } -} -</pre> - - - - @@ -2588,7 +2696,8 @@ about declaring each intent filter, click on the action description.</p> <li>"stop cycling"</li> </ul> </td> - <td><code>"vnd.google.fitness.TRACK"</code></td> + <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> + <code>FitnessIntents.ACTION_TRACK</code></a></td> </tr> <tr> <td> @@ -2599,7 +2708,8 @@ about declaring each intent filter, click on the action description.</p> <li>"stop running"</li> </ul> </td> - <td><code>"vnd.google.fitness.TRACK"</code></td> + <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> + <code>FitnessIntents.ACTION_TRACK</code></a></td> </tr> <tr> <td> @@ -2610,7 +2720,8 @@ about declaring each intent filter, click on the action description.</p> <li>"stop workout"</li> </ul> </td> - <td><code>"vnd.google.fitness.TRACK"</code></td> + <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_TRACK"> + <code>FitnessIntents.ACTION_TRACK</code></a></code></td> </tr> <tr> <td> @@ -2620,7 +2731,8 @@ about declaring each intent filter, click on the action description.</p> <li>"what's my bpm"</li> </ul> </td> - <td><code>"vnd.google.fitness.VIEW"</code></td> + <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW"> + <code>FitnessIntents.ACTION_VIEW</code></a></code></td> </tr> <tr> <td> @@ -2630,7 +2742,8 @@ about declaring each intent filter, click on the action description.</p> <li>"what's my step count"</li> </ul> </td> - <td><code>"vnd.google.fitness.VIEW"</code></td> + <td><a href="{@docRoot}reference/com/google/android/gms/fitness/FitnessIntents.html#ACTION_VIEW"> + <code>FitnessIntents.ACTION_VIEW</code></a></td> </tr> <tr> <td style="vertical-align:middle">Local</td> @@ -2673,6 +2786,16 @@ about declaring each intent filter, click on the action description.</p> <td>{@link android.provider.MediaStore#INTENT_ACTION_VIDEO_CAMERA MediaStore<br/>.INTENT_ACTION_VIDEO_CAMERA}</td> </tr> <tr> + <td style="vertical-align:middle">Search</td> + <td> + <p><a href="#SearchOnApp">Search using a specific app</a></p> + <ul class="now-list"> + <li>"search for cat videos <br/>on myvideoapp"</li> + </ul> + </td> + <td><code>"com.google.android.gms.actions<br/>.SEARCH_ACTION"</code></td> +</tr> +<tr> <td style="vertical-align:middle">Web browser</td> <td> <p><a href="#ViewUrl">Open URL</a></p> diff --git a/docs/html/guide/topics/ui/actionbar.jd b/docs/html/guide/topics/ui/actionbar.jd index a61696a..d972c47 100644 --- a/docs/html/guide/topics/ui/actionbar.jd +++ b/docs/html/guide/topics/ui/actionbar.jd @@ -1427,7 +1427,7 @@ href="#ActionView">action views</a>.</dd> <p>Here's an example that defines a custom theme for an activity, {@code CustomActivityTheme}, that includes several styles to customize the action bar.</p> -<p>Notice that there are two version for each action bar style property. The first one +<p>Notice that there are two versions for each action bar style property. The first one includes the {@code android:} prefix on the property name to support API levels 11 and higher that include these properties in the framework. The second version does <em>not</em> include the {@code android:} prefix and is for older versions of the platform, on which diff --git a/docs/html/images/android-5.0/managed_apps_launcher.png b/docs/html/images/android-5.0/managed_apps_launcher.png Binary files differindex 8184556..46e4c74 100644 --- a/docs/html/images/android-5.0/managed_apps_launcher.png +++ b/docs/html/images/android-5.0/managed_apps_launcher.png diff --git a/docs/html/images/android-5.0/managed_apps_launcher@2x.png b/docs/html/images/android-5.0/managed_apps_launcher@2x.png Binary files differindex 66b7be9..d7fdbce 100644 --- a/docs/html/images/android-5.0/managed_apps_launcher@2x.png +++ b/docs/html/images/android-5.0/managed_apps_launcher@2x.png diff --git a/docs/html/images/games/game-controller-buttons.png b/docs/html/images/games/game-controller-buttons.png Binary files differnew file mode 100644 index 0000000..b3e458a --- /dev/null +++ b/docs/html/images/games/game-controller-buttons.png diff --git a/docs/html/images/games/game-controller-buttons_2x.png b/docs/html/images/games/game-controller-buttons_2x.png Binary files differnew file mode 100644 index 0000000..7a0ad0b --- /dev/null +++ b/docs/html/images/games/game-controller-buttons_2x.png diff --git a/docs/html/jd_collections.js b/docs/html/jd_collections.js index c49f8cc..08c0090 100644 --- a/docs/html/jd_collections.js +++ b/docs/html/jd_collections.js @@ -67,9 +67,9 @@ var RESOURCE_COLLECTIONS = { "distribute/essentials/quality/core.html", "distribute/essentials/quality/tablets.html", "distribute/essentials/quality/tv.html", + "distribute/essentials/quality/wear.html", "https://developers.google.com/edu/guidelines", - "distribute/essentials/optimizing-your-app.html", - "distribute/essentials/best-practices/games.html" + "distribute/essentials/optimizing-your-app.html" ] }, "distribute/users": { @@ -332,6 +332,22 @@ var RESOURCE_COLLECTIONS = { "training/tv/games/index.html" ] }, + "distribute/essentials/wearqualityguidelines/visualdesign": { + "title": "", + "resources": [ + "design/wear/index.html", + "training/building-wearables.html", + "training/wearables/ui/index.html" + ] + }, + "distribute/essentials/wearqualityguidelines/functionality": { + "title": "", + "resources": [ + "training/wearables/notifications/index.html", + "training/wearables/apps/index.html", + "training/wearables/notifications/voice-input.html" + ] + }, "distribute/essentials/core/performance": { "title": "", "resources": [ diff --git a/docs/html/samples/new/index.jd b/docs/html/samples/new/index.jd index 523b922..330caa3 100644 --- a/docs/html/samples/new/index.jd +++ b/docs/html/samples/new/index.jd @@ -348,3 +348,18 @@ AppRestrictionEnforcer sample to toggle the restriction. </p> <p><a href="http://github.com/googlesamples/android-AppRestrictionSchema">Get it on GitHub</a></p> + +<h3 id="SpeedTracker">Speed Tracker (Wear)</h3> + +<p> +This sample uses the FusedLocation APIs of Google Play Services on Android Wear +devices that have a hardware GPS built in. In those cases, this sample provides +a simple screen that shows the current speed of the wearable device. User can +set a speed limit and if the speed approaches that limit, it changes the color +to yellow and if it exceeds the limit, it turns red. User can also enable +recording of coordinates and when it pairs back with the phone, this data +is synced with the phone component of the app and user can see a track +made of those coordinates on a map on the phone. +</p> + +<p><a href="http://github.com/googlesamples/android-SpeedTracker">Get it on GitHub</a></p> diff --git a/docs/html/samples/wearable.jd b/docs/html/samples/wearable.jd new file mode 100644 index 0000000..3114374 --- /dev/null +++ b/docs/html/samples/wearable.jd @@ -0,0 +1,11 @@ +page.title=Wearable +@jd:body + + +<div id="samples" class="wearable"> +</div> + + +<script> + $(document).ready(showSamples); +</script> diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd index 3d9ef21..a646795 100644 --- a/docs/html/sdk/index.jd +++ b/docs/html/sdk/index.jd @@ -243,7 +243,7 @@ This is the Android Software Development Kit License Agreement <h1 style="margin-top:0">Get the Android SDK</h1> -<p>The Android SDK provides you the API libraries and developer tools necessary to build, test, +<p>The Android SDK provides the API libraries and developer tools necessary to build, test, and debug apps for Android.</p> <p>Download the ADT Bundle to quickly start developing apps. It includes the essential Android diff --git a/docs/html/sdk/installing/adding-packages.jd b/docs/html/sdk/installing/adding-packages.jd index e6c0118..22d055c 100644 --- a/docs/html/sdk/installing/adding-packages.jd +++ b/docs/html/sdk/installing/adding-packages.jd @@ -1,5 +1,8 @@ page.title=Adding SDK Packages +page.tags=studio, sdk tools, eclipse adt, sdk manager, google play services, support library +helpoutsWidget=true + @jd:body <style> diff --git a/docs/html/sdk/installing/index.jd b/docs/html/sdk/installing/index.jd index ec0e2f8..6a99952 100644 --- a/docs/html/sdk/installing/index.jd +++ b/docs/html/sdk/installing/index.jd @@ -1,5 +1,8 @@ page.title=Installing the Android SDK +page.tags=studio, sdk tools, eclipse adt +helpoutsWidget=true + @jd:body <style> diff --git a/docs/html/support.jd b/docs/html/support.jd index 4271eee..bbed7df 100644 --- a/docs/html/support.jd +++ b/docs/html/support.jd @@ -3,6 +3,7 @@ page.type=about fullpage=1 page.metaDescription=Resources available to help you report and resolve issues while you are developing apps for Android. page.image=/images/android-support-card.png + @jd:body <div class="wrap" style="width:940px;"> @@ -28,13 +29,20 @@ page.image=/images/android-support-card.png <a href="http://webchat.freenode.net/?channels=android">#android</a>, <a href="http://webchat.freenode.net/?channels=android-dev">#android-dev</a> <span style="color:#888">(IRC via irc.freenode.net)</span><br /> </p> +<p><b> +<a target="_blank" +href="https://helpouts.google.com/partner/ask?vertical=programming&tags=android&origin=http:%2F%2Fdeveloper.android.com%2Fsupport.html">Ask a question in Google Helpouts</a> +</b></p> + <h5>Send Feedback</h5> <p> <a href="http://code.google.com/p/android/issues/entry?template=Developer%20Documentation">Report documentation bug</a><br /> <a href="https://code.google.com/p/android/issues/entry?template=User%20bug%20report">Report device bug</a><br /> <a href="https://code.google.com/p/android/issues/entry?template=Developer%20bug%20report">Report platform bug</a><br /> - +</p> + + </div> diff --git a/docs/html/tools/debugging/debugging-memory.jd b/docs/html/tools/debugging/debugging-memory.jd index fccb67e..ae67b3c 100644 --- a/docs/html/tools/debugging/debugging-memory.jd +++ b/docs/html/tools/debugging/debugging-memory.jd @@ -243,7 +243,7 @@ here, as some details of the output differ across platform versions.</p> Other mmap 107 0 8 8 324 68 Unknown 6994(4) 0 252 6992(4) 0 0 TOTAL 24358(1) 4188 9724 17972(2)16388 4260(2)16968 16595 336 - + Objects Views: 426 ViewRootImpl: 3(8) AppContexts: 6(7) Activities: 2(7) @@ -251,7 +251,7 @@ here, as some details of the output differ across platform versions.</p> Local Binders: 64 Proxy Binders: 34 Death Recipients: 0 OpenSSL Sockets: 1 - + SQL MEMORY_USED: 1739 PAGECACHE_OVERFLOW: 1164 MALLOC_SIZE: 62 @@ -374,7 +374,7 @@ all app processes, they don’t matter very much to your own heap analysis.</p> <p>To analyze your heap dump, you can use a standard tool like jhat or the <a href= "http://www.eclipse.org/mat/downloads.php">Eclipse Memory Analyzer Tool</a> (MAT). However, first you'll need to convert the HPROF file from Android's format to the J2SE HPROF format. You can do -this using the <code>hprof-conv</code> tool provided in the <code><sdk>/tools/</code> +this using the <code>hprof-conv</code> tool provided in the <code><sdk>/platform-tools/</code> directory. Simply run the <code>hprof-conv</code> command with two arguments: the original HPROF file and the location to write the converted HPROF file. For example:</p> diff --git a/docs/html/tools/devices/managing-avds.jd b/docs/html/tools/devices/managing-avds.jd index 10633d2..d3bbfdc 100644 --- a/docs/html/tools/devices/managing-avds.jd +++ b/docs/html/tools/devices/managing-avds.jd @@ -31,6 +31,12 @@ parent.link=index.html <p>From the main screen, you can create, delete, repair and start AVDs as well as see the details of each AVD. </p> + + <p class="note"><strong>Note:</strong> The emulator system images include experimental +64-bit system images along with standard 32-bit system images. The 64-bit system images +require the Intel x86 Emulator Accelerator (HAXM) Rev.5 which can be downloaded from the +<a href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a> <em>Extras</em> folder. + </p> <h2 id="createavd">Creating an AVD</h2> diff --git a/docs/html/tools/revisions/build-tools.jd b/docs/html/tools/revisions/build-tools.jd index fe78ce9..6f07755 100644 --- a/docs/html/tools/revisions/build-tools.jd +++ b/docs/html/tools/revisions/build-tools.jd @@ -77,6 +77,28 @@ listing in the Android SDK Manager.</p> <div class="toggle-content opened"> <p><a href="#" onclick="return toggleContent(this)"> <img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img" + alt=""/>Build Tools, Revision 21.0.2</a> <em>(October 2014)</em> + </p> + <div class="toggle-content-toggleme"> + <p>Complete updates for Eclipse ADT to solve instability issues on Windows platforms.</p> + </div> +</div> + + +<div class="toggle-content closed"> + <p><a href="#" onclick="return toggleContent(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" + alt=""/>Build Tools, Revision 21.0.1</a> <em>(October 2014)</em> + </p> + <div class="toggle-content-toggleme"> + <p>Initial updates for Eclipse ADT on Windows. Please use Revision 21.0.2.</p> + </div> +</div> + + +<div class="toggle-content closed"> + <p><a href="#" onclick="return toggleContent(this)"> + <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" alt=""/>Build Tools, Revision 21.0.0</a> <em>(October 2014)</em> </p> <div class="toggle-content-toggleme"> @@ -96,6 +118,7 @@ listing in the Android SDK Manager.</p> </div> </div> + <div class="toggle-content closed"> <p><a href="#" onclick="return toggleContent(this)"> <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img" diff --git a/docs/html/tools/revisions/platforms.jd b/docs/html/tools/revisions/platforms.jd index 3fa1b9b..85b9c5e 100644 --- a/docs/html/tools/revisions/platforms.jd +++ b/docs/html/tools/revisions/platforms.jd @@ -80,6 +80,23 @@ class="toggle-content-img" alt="" />Revision 1</a> <em>(October 2014)</em> <h2 id="4.4">Android 4.4W</h2> +<div class="toggle-content open"> + <p><a href="#" onclick="return toggleContent(this)"> + <img src="{@docRoot}assets/images/triangle-open.png" +class="toggle-content-img" alt="" />Revision 2</a> <em>(October 2014)</em> + </p> + + <div class="toggle-content-toggleme"> + + <p>Added location APIs support for Wear.</p> + + <p>Dependencies:</p> + <ul> + <li>Android SDK Platform-tools r20 or higher is required.</li> + <li>Android SDK Tools 23.0 or higher is required.</li> + </ul> + </div> + <div class="toggle-content closed"> <p><a href="#" onclick="return toggleContent(this)"> <img src="{@docRoot}assets/images/triangle-closed.png" diff --git a/docs/html/tools/sdk/tools-notes.jd b/docs/html/tools/sdk/tools-notes.jd index 20388be..3e3cb4b 100644 --- a/docs/html/tools/sdk/tools-notes.jd +++ b/docs/html/tools/sdk/tools-notes.jd @@ -13,7 +13,7 @@ latest revision of the SDK Tools in the <code><sdk>/tools</code> directory of the SDK Tools, use the <em>Android SDK Manager</em> to get the update, rather than downloading a new SDK starter package. For more information about how to update, see <a -href="{@docRoot}sdk/exploring.html#UpdatingComponents">Exploring the SDK</a>.</p> +href="{@docRoot}tools/help/sdk-manager.html">SDK Manager</a>.</p> <h2 id="notes">Revisions</h2> diff --git a/docs/html/tools/support-library/features.jd b/docs/html/tools/support-library/features.jd index 8311097..44c5045 100644 --- a/docs/html/tools/support-library/features.jd +++ b/docs/html/tools/support-library/features.jd @@ -139,10 +139,10 @@ page.title=Support Library Features <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:support-v4:18.0.+ +com.android.support:support-v4:21.0.+ </pre> -<p>This dependency notation specifies the release version 18.0.0 or higher.</p> +<p>This dependency notation specifies the release version 21.0.0 or higher.</p> <h2 id="v7">v7 Support Libraries</h2> @@ -237,10 +237,10 @@ com.android.support:cardview-v7:21.0.+ <p>The Gradle build script dependency identifier for this library is as follows:</p> <pre> -com.android.support:gridlayout-v7:18.0.+ +com.android.support:gridlayout-v7:21.0.+ </pre> -<p>This dependency notation specifies the release version 18.0.0 or higher.</p> +<p>This dependency notation specifies the release version 21.0.0 or higher.</p> <h3 id="v7-mediarouter">v7 mediarouter library</h3> @@ -271,10 +271,10 @@ both the <code>android-support-v7-mediarouter.jar</code> and <p>If you are using Android Studio, all you need to do is specify the Gradle build script dependency identifier <code>com.android.support:support-v7-mediarouter:<revision></code>, -where "18.0.0" is the minimum revision at which the library is available. For example:</p> +where "<revision>" is the minimum revision at which the library is available. For example:</p> <pre> -com.android.support:mediarouter-v7:18.0.+ +com.android.support:mediarouter-v7:21.0.+ </pre> <p class="caution">The v7 mediarouter library APIs introduced in Support Library diff --git a/docs/html/training/articles/wear-location-detection.jd b/docs/html/training/articles/wear-location-detection.jd new file mode 100644 index 0000000..b0d9755 --- /dev/null +++ b/docs/html/training/articles/wear-location-detection.jd @@ -0,0 +1,375 @@ +page.title=Detecting Location on Android Wear +page.tags="gps" + +page.article=true +@jd:body + +<div id="tb-wrapper"> +<div id="tb"> +<h2>In this document</h2> +<ol class="nolist"> + <li><a href="#Connect">Connect to Google Play Services</a></li> + <li><a href="#Request">Request Location Updates</a></li> + <li><a href="#DetectGPS">Detect On-Board GPS</a></li> + <li><a href="#Disconnection">Handle Disconnection Events</a></li> + <li><a href="#Notify">Handle Location Not Found</a></li> + <li><a href="#Synchronize">Synchronize Data</a></li> +</ol> +<!-- Required platform, tools, add-ons, devices, knowledge, etc. --> +<h2>Dependencies and prerequisites</h2> +<ul> + <li>Android 4.3 (API Level 18) or higher on the handset device</li> + <li><a href="{@docRoot}google/play-services/index.html">Google Play services</a> 6.1 or higher</li> + <li>An Android Wear device</li> +</ul> +<h2>See also</h2> +<ul> + <li><a href="{@docRoot}training/location/index.html">Making Your App Location-Aware + </a></li> +</ul> +</div></div> + +<p>Location awareness on wearable devices enables you to create apps that give users a better +understanding of their geographic position, movement and what's around them. With the small form +factor and glanceable nature of a wearable device, you can build low-friction apps that record and +respond to location data.</p> + +<p>Some wearable devices include a GPS sensor that can retrieve location data without another +tethered device. However, when you request location data in a wearable app, you don't have to worry +about where the location data originates; the system retrieves the location updates using the most +power-efficient method. Your app should be able to handle loss of location data, in case the wear +device loses connection with its paired device and does not have a built-in GPS sensor.</p> + +<p>This document shows you how to check for on-device location sensors, receive location data, and +monitor tethered data connections.</p> + +<p class="note"><b>Note:</b> The article assumes that you know how to use the Google Play services +API to retrieve location data. For more information, see <a href="{@docRoot}training/ +location/index.html">Making Your App Location-Aware</a>.</p> + +<h2 id="Connect">Connect to Google Play Services</h2> + +<p>Location data on wearable devices is obtained though the Google Play services location APIs. You +use the <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html"> +<code>FusedLocationProviderApi</code></a> and its accompanying classes to obtain this data. +To access location services, create an instance of +<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"> +<code>GoogleApiClient</code></a>, which is +the main entry point for any of the Google Play services APIs. +</p> + +<p class="caution"><b>Caution:</b> Do not use the existing <a href="{@docRoot}reference/android/location/package-summary.html">Location</a> +APIs in the Android framework. The best practice for retrieving location updates is through the +Google Play services API as outlined in this article.</p> + +<p>To connect to Google Play services, configure your app to create an instance of +<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"> +<code>GoogleApiClient</code></a>:</p> + +<ol> + <li>Create an activity that specifies an implementation for the interfaces <a +href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html" +>{@code ConnectionCallbacks}</a>, <a href="{@docRoot}reference/com/google/android/gms/common/api/ +GoogleApiClient.OnConnectionFailedListener.html">{@code OnConnectionFailedListener}</a>, and <a +href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html">{@code +LocationListener}</a>.</li> + <li>In your activity's {@link android.app.Activity#onCreate onCreate()} method, create an instance +of <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html"><code> +GoogleApiClient</code></a> and add the Location service. + </li> + <li>To gracefully manage the lifecycle of the connection, call <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#connect()"> + {@code connect()}</a> in the {@link android.app.Activity#onResume onResume()} method and + <a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.html#disconnect()"> + {@code disconnect()}</a> in the {@link android.app.Activity#onPause onPause()} method. + </li> +</ol> + +<p>The following code example shows an implementation of an activity that implements the +<a href="{@docRoot}reference/com/google/android/gms/location/LocationListener.html"> +{@code LocationListener}</a> interface:</p> + +<pre> +public class WearableMainActivity extends Activity implements + GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener, + LocationListener { + + private GoogleApiClient mGoogleApiClient; + ... + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + ... + mGoogleApiClient = new GoogleApiClient.Builder(this) + .addApi(LocationServices.API) + .addApi(Wearable.API) // used for data layer API + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .build(); + } + + @Override + protected void onResume() { + super.onResume(); + mGoogleApiClient.connect(); + ... + } + + @Override + protected void onPause() { + super.onPause(); + ... + mGoogleApiClient.disconnect(); + } +} +</pre> + +<p>For more information on connecting to Google Play services, see <a href="{@docRoot}google/auth +/api-client.html">Accessing Google APIs</a>.</p> + +<h2 id="Request">Request Location Updates</h2> + +<p>After your app has connected to the Google Play services API, it is ready to start receiving +location updates. When the system invokes the +<a href="{@docRoot}reference/com/google/android/gms/common/api/GoogleApiClient.ConnectionCallbacks.html#onConnected(android.os.Bundle)"> +<code>onConnected()</code></a> callback for your client, you build the location data request as +follows:</p> + +<ol> + <li>Create a <a +href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html" +>{@code LocationRequest}</a> object and set any options using methods like <a +href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setPriority(int)" +>{@code setPriority()}</a>. + </li> + <li>Request location updates using <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#requestLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationRequest, com.google.android.gms.location.LocationListener)"> + <code>requestLocationUpdates()</code></a>. + </li> + <li>Remove location updates using <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#removeLocationUpdates(com.google.android.gms.common.api.GoogleApiClient, com.google.android.gms.location.LocationListener)"> + <code>removeLocationUpdates()</code></a> in the {@link android.app.Activity#onPause + onPause()} method. + </li> +</ol> + +<p>The following example shows how to retrieve and remove location updates:</p> + +<pre> +@Override +public void onConnected(Bundle bundle) { + LocationRequest locationRequest = LocationRequest.create() + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY) + .setInterval(UPDATE_INTERVAL_MS) + .setFastestInterval(FASTEST_INTERVAL_MS); + + LocationServices.FusedLocationApi + .requestLocationUpdates(mGoogleApiClient, locationRequest, this) + .setResultCallback(new ResultCallback<Status>() { + + @Override + public void onResult(Status status) { + if (status.getStatus().isSuccess()) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "Successfully requested location updates"); + } + } else { + Log.e(TAG, + "Failed in requesting location updates, " + + "status code: " + + status.getStatusCode() + + ", message: " + + status.getStatusMessage()); + } + } + }); +} + +@Override +protected void onPause() { + super.onPause(); + if (mGoogleApiClient.isConnected()) { + LocationServices.FusedLocationApi + .removeLocationUpdates(mGoogleApiClient, this); + } + mGoogleApiClient.disconnect(); +} + +@Override +public void onConnectionSuspended(int i) { + if (Log.isLoggable(TAG, Log.DEBUG)) { + Log.d(TAG, "connection to location client suspended"); + } +} + +</pre> + +<p>Now that you have enabled location updates, the system calls the {@link android.location.LocationListener#onLocationChanged +onLocationChanged()} method with the updated location at the interval specified in <a +href="{@docRoot}reference/com/google/android/gms/location/LocationRequest.html#setInterval(long)"> +{@code setInterval()}</a> +</p> + +<h2 id="DetectGPS">Detect On-Board GPS</h2> + +<p>Not all wearables have a GPS sensor. If your user goes out for a run and leaves their phone at +home, your wearable app cannot receive location data through a tethered connection. If the +wearable device does not have a sensor, you should detect this situation and warn the user that +location functionality is not available. + +<p>To determine whether your Android Wear device has a built-in GPS sensor, use the +{@link android.content.pm.PackageManager#hasSystemFeature hasSystemFeature()} +method. The following code detects whether the device has built-in GPS when you start an activity: +</p> + +<pre> + +protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.main_activity); + if (!hasGps()) { + Log.d(TAG, "This hardware doesn't have GPS."); + // Fall back to functionality that does not use location or + // warn the user that location function is not available. + } + + ... +} + +private boolean hasGps() { + return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS); +} +</pre> + +<h2 id="Disconnection">Handle Disconnection Events</h2> + +<p>Wearable devices relying on a tethered connection for location data may lose their connections +abruptly. If your wearable app expects a constant stream of data, you must handle the +disconnection based upon where that data is interrupted or unavailable. On a wearable device with no +onboard GPS sensor, loss of location data occurs when the device loses its tethered data connection. +</p> + +<p>In cases where your app depends on a tethered data connection for location data and the wear +device does not have a GPS sensor, you should detect the loss of that connection, warn the user, and +gracefully degrade the functionality of your app.</p> + +<p>To detect the loss of a tethered data connection:</p> + +<ol> + <li>Extend a <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"> + <code>WearableListenerService</code></a> that lets you listen for important data layer events. + </li> + <li>Declare an intent filter in your Android manifest to notify the system about your + <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html"><code> + WearableListenerService</code></a>. + This filter allows the system to bind your service as needed. +<pre> +<service android:name=".NodeListenerService"> + <intent-filter> + <action android:name="com.google.android.gms.wearable.BIND_LISTENER" /> + </intent-filter> +</service> +</pre> + </li> + <li>Implement the <a href="{@docRoot}reference/com/google/android/gms/wearable/WearableListenerService.html#onPeerDisconnected(com.google.android.gms.wearable.Node)"> + <code>onPeerDisconnected()</code></a> method and handle cases of whether or not the device has + built-in + GPS. +<pre> +public class NodeListenerService extends WearableListenerService { + + private static final String TAG = "NodeListenerService"; + + @Override + public void onPeerDisconnected(Node peer) { + Log.d(TAG, "You have been disconnected."); + if(!hasGPS()) { + // Notify user to bring tethered handset + // Fall back to functionality that does not use location + } + } + ... +} +</pre> + </li> +</ol> + +For more information, read the <a href="{@docRoot}training/wearables/data-layer/events.html#Listen"> +Listen for Data Layer Events</a> guide. + +<h2 id="Notify">Handle Location Not Found</h2> + +<p>When the GPS signal is lost, you can still retrieve the last known location using +<a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)"> +<code>getLastLocation()</code></a>. This method can be helpful in situations where you are unable to +get a GPS fix, or when your wearable doesn't have built-in GPS and loses its connection with the +phone.</p> + +<p>The following code uses <a href="{@docRoot}reference/com/google/android/gms/location/FusedLocationProviderApi.html#getLastLocation(com.google.android.gms.common.api.GoogleApiClient)"> +<code>getLastLocation()</code></a> to retrieve the last known location if available: +</p> + +<pre> +Location location = LocationServices.FusedLocationApi + .getLastLocation(mGoogleApiClient); +</pre> + +<h2 id="Synchronize">Synchronize Data</h2> + +<p>If your wearable app records data using the built-in GPS, you may want to synchronize +the location data with the handset. With the {@link android.location.LocationListener}, you +implement the {@link android.location.LocationListener#onLocationChanged onLocationChanged()} +method to detect and record the location as it changes. + +<p>The following code for wearable apps detects when the location changes and uses the data layer +API to store the data for later retrieval by your phone app:</p> + +<pre> +@Override +public void onLocationChanged(Location location) { + ... + addLocationEntry(location.getLatitude(), location.getLongitude()); + +} + +private void addLocationEntry(double latitude, double longitude) { + if (!mSaveGpsLocation || !mGoogleApiClient.isConnected()) { + return; + } + + mCalendar.setTimeInMillis(System.currentTimeMillis()); + + // Set the path of the data map + String path = Constants.PATH + "/" + mCalendar.getTimeInMillis(); + PutDataMapRequest putDataMapRequest = PutDataMapRequest.create(path); + + // Set the location values in the data map + putDataMapRequest.getDataMap() + .putDouble(Constants.KEY_LATITUDE, latitude); + putDataMapRequest.getDataMap() + .putDouble(Constants.KEY_LONGITUDE, longitude); + putDataMapRequest.getDataMap() + .putLong(Constants.KEY_TIME, mCalendar.getTimeInMillis()); + + // Prepare the data map for the request + PutDataRequest request = putDataMapRequest.asPutDataRequest(); + + // Request the system to create the data item + Wearable.DataApi.putDataItem(mGoogleApiClient, request) + .setResultCallback(new ResultCallback<DataApi.DataItemResult>() { + @Override + public void onResult(DataApi.DataItemResult dataItemResult) { + if (!dataItemResult.getStatus().isSuccess()) { + Log.e(TAG, "Failed to set the data, " + + "status: " + dataItemResult.getStatus() + .getStatusCode()); + } + } + }); +} +</pre> + +<p>For more information on how to use the Data Layer API, see the <a href="{@docRoot}training/ +wearables/data-layer/index.html">Sending and Syncing Data</a> +guide.</p> diff --git a/docs/html/training/basics/firstapp/building-ui.jd b/docs/html/training/basics/firstapp/building-ui.jd index 179b3ac..c082642 100644 --- a/docs/html/training/basics/firstapp/building-ui.jd +++ b/docs/html/training/basics/firstapp/building-ui.jd @@ -1,12 +1,8 @@ page.title=Building a Simple User Interface -parent.title=Building Your First App -parent.link=index.html - trainingnavtop=true -previous.title=Running Your App -previous.link=running-app.html -next.title=Starting Another Activity -next.link=starting-activity.html + +page.tags=ui, views, layouts, widgets, string resources +helpoutsWidget=true @jd:body diff --git a/docs/html/training/basics/firstapp/creating-project.jd b/docs/html/training/basics/firstapp/creating-project.jd index c4cb362..418eb68 100644 --- a/docs/html/training/basics/firstapp/creating-project.jd +++ b/docs/html/training/basics/firstapp/creating-project.jd @@ -1,6 +1,7 @@ page.title=Creating an Android Project -parent.title=Building Your First App -parent.link=index.html + +page.tags=eclipse adt, sdk tools, project setup +helpoutsWidget=true trainingnavtop=true next.title=Running Your App diff --git a/docs/html/training/basics/firstapp/index.jd b/docs/html/training/basics/firstapp/index.jd index 1b49096..ac8e64a 100644 --- a/docs/html/training/basics/firstapp/index.jd +++ b/docs/html/training/basics/firstapp/index.jd @@ -3,8 +3,9 @@ page.metaDescription=If you're new to Android app development, this where you sh trainingnavtop=true startpage=true -next.title=Creating an Android Project -next.link=creating-project.html + +page.tags=sdk tools +helpoutsWidget=true @jd:body @@ -47,6 +48,3 @@ not apply to earlier versions.</p> <p>This class uses a tutorial format that incrementally builds a small Android app that teaches you some fundamental concepts about Android development, so it's important that you follow each step.</p> - -<p><strong><a href="creating-project.html">Start the first lesson ›</a></strong></p> - diff --git a/docs/html/training/basics/firstapp/running-app.jd b/docs/html/training/basics/firstapp/running-app.jd index 23cedba..96b7172 100644 --- a/docs/html/training/basics/firstapp/running-app.jd +++ b/docs/html/training/basics/firstapp/running-app.jd @@ -3,10 +3,9 @@ parent.title=Building Your First App parent.link=index.html trainingnavtop=true -previous.title=Creating a Project -previous.link=creating-project.html -next.title=Building a Simple User Interface -next.link=building-ui.html + +page.tags=emulator +helpoutsWidget=true @jd:body diff --git a/docs/html/training/basics/firstapp/starting-activity.jd b/docs/html/training/basics/firstapp/starting-activity.jd index 27d2c10..f9dcba4 100644 --- a/docs/html/training/basics/firstapp/starting-activity.jd +++ b/docs/html/training/basics/firstapp/starting-activity.jd @@ -3,8 +3,9 @@ parent.title=Building Your First App parent.link=index.html trainingnavtop=true -previous.title=Building a Simpler User Interface -previous.link=building-ui.html + +page.tags=input events, intents, activity lifecycle +helpoutsWidget=true @jd:body diff --git a/docs/html/training/material/compatibility.jd b/docs/html/training/material/compatibility.jd index 5e03450..49ef7f7 100644 --- a/docs/html/training/material/compatibility.jd +++ b/docs/html/training/material/compatibility.jd @@ -131,9 +131,9 @@ href="{@docRoot}/sdk/installing/studio-build.html#dependencies">Gradle dependenc <pre> dependencies { - compile 'com.android.support:appcompat-v7:+' - compile 'com.android.support:cardview-v7:+' - compile 'com.android.support:recyclerview-v7:+' + compile 'com.android.support:appcompat-v7:21.0.+' + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' } </pre> diff --git a/docs/html/training/material/drawables.jd b/docs/html/training/material/drawables.jd index 8d7f453..fd21e3d 100644 --- a/docs/html/training/material/drawables.jd +++ b/docs/html/training/material/drawables.jd @@ -73,7 +73,7 @@ app's module:</p> <pre> dependencies { ... - compile 'com.android.support:palette-v7:+' + compile 'com.android.support:palette-v7:21.0.+' } </pre> diff --git a/docs/html/training/material/index.jd b/docs/html/training/material/index.jd index 542a941..4eb7911 100644 --- a/docs/html/training/material/index.jd +++ b/docs/html/training/material/index.jd @@ -1,6 +1,6 @@ page.title=Creating Apps with Material Design page.type=design -page.image=design/material/images/MaterialLight.png +page.image=images/material.png page.metaDescription=Learn how to apply material design to your apps. diff --git a/docs/html/training/material/lists-cards.jd b/docs/html/training/material/lists-cards.jd index eb45f0d..e7bdfe0 100644 --- a/docs/html/training/material/lists-cards.jd +++ b/docs/html/training/material/lists-cards.jd @@ -260,7 +260,7 @@ app's module:</p> <pre> dependencies { ... - compile 'com.android.support:cardview-v7:+' - compile 'com.android.support:recyclerview-v7:+' + compile 'com.android.support:cardview-v7:21.0.+' + compile 'com.android.support:recyclerview-v7:21.0.+' } </pre> diff --git a/docs/html/training/search/index.jd b/docs/html/training/search/index.jd index 612e8e8..66874bb 100644 --- a/docs/html/training/search/index.jd +++ b/docs/html/training/search/index.jd @@ -49,5 +49,5 @@ startpage=true <dt><b><a href="backward-compat.html">Remaining Backward Compatible</a></b></dt> - <dd>Learn how to keep search features backward compatible with older devices by using.</dd> + <dd>Learn how to keep search features backward compatible with older devices.</dd> </dl> diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index 0fee771..9f06666 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -834,6 +834,12 @@ include the action bar on devices running Android 2.1 or higher." </li> </ul> </li> + <li> + <a href="<?cs var:toroot ?>training/articles/wear-location-detection.html" + description= + "How to detect location data on Android Wear devices." + >Detecting Location</a> + </li> </ul> </li> <!-- End Building for wearables --> diff --git a/docs/html/training/tv/games/index.jd b/docs/html/training/tv/games/index.jd index 29b055b..2f510a9 100644 --- a/docs/html/training/tv/games/index.jd +++ b/docs/html/training/tv/games/index.jd @@ -31,7 +31,7 @@ page.article=true </p> -<h3 id="shared-display">Shared display</h3> +<h3 id="shared-display">Consider the shared display</h3> <p> A living-room TV poses design challenges for multiplayer games, in that all players can see @@ -57,7 +57,7 @@ page.article=true </ul> -<h3 id="landscape-display">Landscape display</h3> +<h3 id="landscape-display">Support landscape display</h3> <p> A TV is always sideways: You can’t turn it, and there is no portrait orientation. Always design @@ -69,19 +69,19 @@ page.article=true <p> TVs don't have touch interfaces, so it's even more important to get your controls right and make - sure that players find them intuitive and fun to use. The separation of controller from device - also introduces some other issues to pay attention to, like keeping track of multiple players' + sure players find them intuitive and fun to use. Handling controllers + also introduces some other issues to pay attention to, like keeping track of multiple controllers, and handling disconnects gracefully. </p> -<h3 id="d-pad">D-pad</h3> +<h3 id="d-pad">Support D-pad controls</h3> <p> Plan your control scheme around a directional pad (D-pad) control, since this control set is the default for Android TV devices. The player needs to be able to use a D-Pad in all aspects of the - game–not just controlling core gameplay, but also navigating menus and ads. For this reason, you - should also ensure that your Android TV game does not refer to a touch interface: For example, an - Android TV game should not tell a player to <strong>Tap here to skip</strong>. + game—not just controlling core gameplay, but also navigating menus and ads. For this reason, you + should also ensure that your Android TV game does not refer to a touch interface. For example, an + Android TV game should not tell a player to "<em>Tap</em> here to continue." </p> <p> @@ -91,35 +91,35 @@ page.article=true <ul> <li> - <strong>Communicate Controller Requirements up Front</strong> - Use your Play Store description + <strong>Communicate Controller Requirements up Front</strong>. Use your Google Play description to communicate to the player any expectations about controllers. If a game is better suited to a gamepad with a joystick than one with only a D-pad, make this fact clear. A player who uses - an ill-suited controller for a game is likely to have a subpar experience–and penalize your + an ill-suited controller for a game is likely to have a subpar experience and penalize your game in the ratings. </li> <li> - <strong>Use Consistent Button Mapping</strong> - Intuitive and flexible button mapping is key - to a good user experience. For example, you can adhere to accepted custom by using the A button - to <code>Accept</code>, and the B button to <code>Cancel</code>. You can also offer flexibility - in the form of remappability. For more information on button mapping, see <a href= + <strong>Use Consistent Button Mapping</strong>. Intuitive and flexible button mapping is key + to a good user experience. For example, you should adhere to accepted customs by using the A button + to <em>Accept</em>, and the B button to <em>Cancel</em>. You can also offer flexibility + in the form of remappability. For more information about button mapping, see <a href= "http://developer.android.com/training/game-controllers/controller-input.html">Handling Controller Actions</a>. </li> <li> - <strong>Detect Controller Capabilities and Adjust Accordingly</strong> - Query the controller + <strong>Detect Controller Capabilities and Adjust Accordingly</strong>. Query the controller about its capabilities in order to optimize the match between controller and game. For example, you may intend for a player to steer an object by waving the controller in the air. If a player's controller lacks accelerometer and gyroscope hardware, however, waving will not work. - When, however, your game queries the controller and discovers that motion detection is not - supported, it can switch over to an alternative, available control scheme. For more information - on querying controller capabilities, see <a href= + So, your game should query the controller and if motion detection is not + supported, switch over to an alternative, available control scheme. For more information + about querying controller capabilities, see <a href= "http://developer.android.com/training/game-controllers/compatibility.html">Supporting Controllers Across Android Versions</a>. </li> </ul> -<h3 id="back-button">Back-button behavior</h3> +<h3 id="back-button">Provide appropriate Back-button behavior</h3> <p> The Back button should never act as a toggle. For example, do not use it to both open and close a @@ -139,18 +139,18 @@ page.article=true </p> -<h3 id="multiple-controllers">Handling multiple controllers</h3> +<h3 id="multiple-controllers">Handle multiple controllers</h3> <p> When multiple players are playing a game, each with his or her own controller, it is important to - map each player-controller pair. For information on how to implement controller-number + map each player-controller pair. For information about how to implement controller-number identification, see <a href= "http://developer.android.com/reference/android/view/InputDevice.html#getControllerNumber">Input Devices</a>. </p> -<h3 id="handle-disconnect">Handling disconnects</h3> +<h3 id="handle-disconnect">Handle controller disconnects</h3> <p> When a controller is disconnected in the middle of gameplay, the game should pause, and a dialog @@ -159,7 +159,7 @@ page.article=true <p> The dialog should also offer troubleshooting tips (for example, a pop-up dialog telling the - player to "Check your Bluetooth connection"). For more information on implementing input-device + player to "Check your Bluetooth connection"). For more information about implementing input-device support, see <a href= "http://developer.android.com/training/game-controllers/controller-input.html">Handling Controller Actions</a>. Specific information about Bluetooth connections is at <a href= @@ -167,25 +167,53 @@ page.article=true </p> +<h3 id="ControllerHelp">Show controller instructions</h3> + +<p>If your game provides visual game control instructions, the +controller image should be free of branding and include only <a +href="{@docRoot}training/game-controllers/controller-input.html#button" +>buttons compatible with Android</a>.</p> + +<p>For sample images of an Android-compatible controller, download the +<a href="http://storage.googleapis.com/androiddevelopers/design/android_tv_gamepad_template-2014-10.zip" +>Android TV Gamepad Template (ZIP)</a>. +It includes a white controller on black background and a black controller on white background +(shown in figure 1), as a PNG file and an Adobe® Illustrator® file.</p> + +<img src="{@docRoot}images/games/game-controller-buttons_2x.png" width="700" + srcset="{@docRoot}images/games/game-controller-buttons_2x.png 2x, + {@docRoot}images/games/game-controller-buttons.png 1x" /> +<p class="img-caption"><b>Figure 1.</b> Example controller instructions using the +<a href="http://storage.googleapis.com/androiddevelopers/design/android_tv_gamepad_template-2014-10.zip" +>Android TV Gamepad Template (ZIP)</a>. + + + + <h2 id="manifest">Manifest</h2> +<p>There are a some special things games should include in the Android manifest.</p> + +<h3 id="Launcher">Show your game in the launcher</h3> <p> - The Android TV launcher home screen displays games in a separate row from regular apps. The TV - framework uses the <code>android:isGame</code> manifest attribute to differentiate games from - non-game apps. Set this value to <code>true</code> in your game's app manifest, as shown in the - following code example: + The Android TV launcher home screen displays games in a separate row from regular apps. + To make your game appear in the list of games, add the + <a href="{@docRoot}guide/topics/manifest/meta-data-element.html" + ><code><meta-data></code></a> tag in your app manifest with <code>android:name</code> + set to <code>"isGame"</code> and <code>android:value</code> + set to <code>"true"</code>. For example: </p> <pre class="fragment"> <application> ... - < meta-data android:name="isGame" android:value="true" > + <meta-data android:name="isGame" android:value="true" > ... </application> </pre> -<h3 id="gamepad">Game Controllers</h3> +<h3 id="gamepad">Declare support for game controllers</h3> <p> Games controllers may not be available or active for users of a TV device. In order to properly @@ -215,7 +243,9 @@ page.article=true <h2 id="gpgs">Google Play Game Services</h2> <p> - If your game integrates Google Play Game Services, you should keep in mind a number of + If your game integrates <a + href="https://developers.google.com/games/services/">Google Play Game services</a>, + you should keep in mind a number of considerations pertaining to achievements, sign-in, saving games, and multiplayer play. </p> @@ -224,7 +254,7 @@ page.article=true <p> Your game should include at least five (earnable) achievements. Only a user controlling gameplay - from a supported input device should be able to earn achievements. For more information on + from a supported input device should be able to earn achievements. For more information about achievements and how to implement them, see <a href= "https://developers.google.com/games/services/android/achievements">Achievements in Android</a>. </p> @@ -262,7 +292,7 @@ page.article=true <p> A game offering a multiplayer experience must allow at least two players to enter a room. For - further information on multiplayer games in Android, see the <a href= + further information about multiplayer games in Android, see the <a href= "https://developers.google.com/games/services/android/realtimeMultiplayer">Real-time Multiplayer</a> and <a href="">Turn-based Multiplayer</a> documentation on the Android developer site. diff --git a/docs/html/training/wearables/apps/index.jd b/docs/html/training/wearables/apps/index.jd index 7d961b7..256205b 100644 --- a/docs/html/training/wearables/apps/index.jd +++ b/docs/html/training/wearables/apps/index.jd @@ -1,5 +1,6 @@ page.title=Creating Wearable Apps -page.image=wear/images/notifications.png +page.tags="wear","wearable","app" +page.image=wear/images/01_create.png @jd:body diff --git a/docs/html/training/wearables/notifications/index.jd b/docs/html/training/wearables/notifications/index.jd index 17f3cb3..a7b6733 100644 --- a/docs/html/training/wearables/notifications/index.jd +++ b/docs/html/training/wearables/notifications/index.jd @@ -1,4 +1,6 @@ page.title=Adding Wearable Features to Notifications +page.tags="wear","notifications","wearables" +page.image=wear/images/01_notifications.png @jd:body <div id="tb-wrapper"> diff --git a/docs/html/training/wearables/notifications/stacks.jd b/docs/html/training/wearables/notifications/stacks.jd index e71e74c..9a528a4 100644 --- a/docs/html/training/wearables/notifications/stacks.jd +++ b/docs/html/training/wearables/notifications/stacks.jd @@ -45,7 +45,7 @@ final static String GROUP_KEY_EMAILS = "group_key_emails"; Notification notif = new NotificationCompat.Builder(mContext) .setContentTitle("New mail from " + sender1) .setContentText(subject1) - .setSmallIcon(R.drawable.new_mail); + .setSmallIcon(R.drawable.new_mail) .setGroup(GROUP_KEY_EMAILS) .build(); @@ -65,7 +65,7 @@ instead of as a new card:</p> Notification notif2 = new NotificationCompat.Builder(mContext) .setContentTitle("New mail from " + sender2) .setContentText(subject2) - .setSmallIcon(R.drawable.new_mail); + .setSmallIcon(R.drawable.new_mail) .setGroup(GROUP_KEY_EMAILS) .build(); diff --git a/docs/html/training/wearables/ui/index.jd b/docs/html/training/wearables/ui/index.jd index 8ef6fe7..5d97490 100644 --- a/docs/html/training/wearables/ui/index.jd +++ b/docs/html/training/wearables/ui/index.jd @@ -1,4 +1,5 @@ page.title=Creating Custom UIs for Wear Devices +page.image=wear/images/10_uilib.png @jd:body diff --git a/docs/html/wear/images/01_create.png b/docs/html/wear/images/01_create.png Binary files differnew file mode 100644 index 0000000..5a39dde --- /dev/null +++ b/docs/html/wear/images/01_create.png diff --git a/docs/html/wear/images/02_create.png b/docs/html/wear/images/02_create.png Binary files differnew file mode 100644 index 0000000..e722df1 --- /dev/null +++ b/docs/html/wear/images/02_create.png diff --git a/docs/html/wear/images/10_uilib.png b/docs/html/wear/images/10_uilib.png Binary files differnew file mode 100644 index 0000000..de7be57 --- /dev/null +++ b/docs/html/wear/images/10_uilib.png diff --git a/docs/image_sources/distribute/gp-wear-quality.svg b/docs/image_sources/distribute/gp-wear-quality.svg new file mode 100644 index 0000000..2acf81a --- /dev/null +++ b/docs/image_sources/distribute/gp-wear-quality.svg @@ -0,0 +1,2268 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + version="1.1" + width="2824.887" + height="1419.8136" + id="svg3004" + xml:space="preserve" + inkscape:version="0.48.1 " + sodipodi:docname="wear_app_quality.svg"><sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1280" + inkscape:window-height="1002" + id="namedview125" + showgrid="false" + inkscape:zoom="0.23675905" + inkscape:cx="1735.4152" + inkscape:cy="-51.97425" + inkscape:window-x="1272" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="layer8" + showguides="true" + inkscape:guide-bbox="true" + fit-margin-top="50" + fit-margin-left="200" + fit-margin-right="200" + fit-margin-bottom="200"><sodipodi:guide + orientation="0,1" + position="1543.7834,1150.3523" + id="guide3963" /><sodipodi:guide + orientation="0,1" + position="1978.6428,757.82274" + id="guide9681" /></sodipodi:namedview><metadata + id="metadata3010"><rdf:RDF><cc:Work + rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs + id="defs3008"><clipPath + id="clipPath3020"><path + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + id="path3022" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3044"><path + d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z" + id="path3046" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3060"><path + d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z" + id="path3062" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3086"><path + d="m 1058,722 374,0 0,-374 -374,0 0,374 z" + id="path3088" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3100"><path + d="m 1029,344 432,0 0,-32 -432,0 0,32 z" + id="path3102" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3116"><path + d="m 1029,756 432,0 0,-32 -432,0 0,32 z" + id="path3118" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3060-8"><path + d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z" + id="path3062-8" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3044-8"><path + d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z" + id="path3046-8" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3116-3"><path + d="m 1029,756 432,0 0,-32 -432,0 0,32 z" + id="path3118-0" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3100-0"><path + d="m 1029,344 432,0 0,-32 -432,0 0,32 z" + id="path3102-0" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3086-0"><path + d="m 1058,722 374,0 0,-374 -374,0 0,374 z" + id="path3088-4" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3086-0-0"><path + d="m 1058,722 374,0 0,-374 -374,0 0,374 z" + id="path3088-4-2" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3100-0-7"><path + d="m 1029,344 432,0 0,-32 -432,0 0,32 z" + id="path3102-0-2" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3116-3-2"><path + d="m 1029,756 432,0 0,-32 -432,0 0,32 z" + id="path3118-0-6" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3060-8-2"><path + d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z" + id="path3062-8-4" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3044-8-3"><path + d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z" + id="path3046-8-8" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3086-4"><path + inkscape:connector-curvature="0" + d="m 1058,722 374,0 0,-374 -374,0 0,374 z" + id="path3088-8" /></clipPath><clipPath + id="clipPath3100-8"><path + inkscape:connector-curvature="0" + d="m 1029,344 432,0 0,-32 -432,0 0,32 z" + id="path3102-2" /></clipPath><clipPath + id="clipPath3116-4"><path + inkscape:connector-curvature="0" + d="m 1029,756 432,0 0,-32 -432,0 0,32 z" + id="path3118-5" /></clipPath><clipPath + id="clipPath3044-8-1"><path + inkscape:connector-curvature="0" + d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z" + id="path3046-8-5" /></clipPath><clipPath + id="clipPath3060-8-27"><path + inkscape:connector-curvature="0" + d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z" + id="path3062-8-6" /></clipPath><clipPath + id="clipPath3086-0-0-4"><path + inkscape:connector-curvature="0" + d="m 1058,722 374,0 0,-374 -374,0 0,374 z" + id="path3088-4-2-1" /></clipPath><clipPath + id="clipPath3100-0-7-1"><path + inkscape:connector-curvature="0" + d="m 1029,344 432,0 0,-32 -432,0 0,32 z" + id="path3102-0-2-5" /></clipPath><clipPath + id="clipPath3116-3-2-9"><path + inkscape:connector-curvature="0" + d="m 1029,756 432,0 0,-32 -432,0 0,32 z" + id="path3118-0-6-5" /></clipPath><clipPath + id="clipPath3044-8-3-2"><path + inkscape:connector-curvature="0" + d="m 391.754,758.654 452.495,0 0,-452.496 -452.495,0 0,452.496 z" + id="path3046-8-8-2" /></clipPath><clipPath + id="clipPath3060-8-2-1"><path + inkscape:connector-curvature="0" + d="m 362.683,787.727 510.637,0 0,-510.638 -510.637,0 0,510.638 z" + id="path3062-8-4-5" /></clipPath><clipPath + id="clipPath3942" + clipPathUnits="userSpaceOnUse"><path + id="path3944" + d="m 1337.7,554.569 67.31,0 0,-64.569 -67.31,0 0,64.569 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3912" + clipPathUnits="userSpaceOnUse"><path + id="path3914" + d="m 1404.777,549.002 12,0 0,11.998 -12,0 0,-11.998 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3908" + clipPathUnits="userSpaceOnUse"><path + id="path3910" + d="m 1404.78,561 12,0 0,-12 -12,0 0,12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3886" + clipPathUnits="userSpaceOnUse"><path + id="path3888" + d="m 1363,547.865 32,0 0,12 -32,0 0,-12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3882" + clipPathUnits="userSpaceOnUse"><path + id="path3884" + d="m 1363,559.865 32,0 0,-12.002 -32,0 0,12.002 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3852" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3854" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAAAAACTooUSAAAAAXNCSVQI5gpbmQAAAXhJREFUWIXt2T9v3DAMBfBHWj4Fzh2CXjsEaZd+/+8VZGiN+v4Y1cni6+ADmqUjnQ7kqEE/ULQXPgEAQLBB8S8lAnE3SZCrKFBVVd8+CTMzA5EAaOr7PrmShC211sWABNGUh8fHnNRTtKVcrzMWY4JoPxw/Hw+585sl2cp5/AkzMgm033/59nIcevUCAavz+Cq3Upvce3z5/nzY+T0r7XZ+w/zrpMJ1jvvj89enB0/x94Rpn5PK/VvNw+HpU+78xFZwGnJSAAkQ0a7f5fzgKSLv+k5FgAQAoqJd1zmK6DqVdWppPZK1vES8u93xj/hHhRhiiCGGGGKIIYYYYoghhhhiiCGGGOL/Jt73ciRJuinvr08AQKO11vzCALbWjMa7SFqrt1LgutEtt9qMXHu0pcznCc5b6/NcFgOQQFvKZXzDyXszP17KYkQCrc7jKyb/9GGcqxGJYvXyg9ctEpZLNXDtEWXaJEWqRgggWyZl/IA08EMST2DTVPcPY4fdi0eNNAgAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3840" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3842"><g + id="g3844" + clip-path="url(#clipPath3836)"><g + id="g3846"><g + id="g3848" + transform="matrix(113,0,0,68,1351,505)"><image + id="image3850" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAYAAAC2ydrOAAAABHNCSVQICAgIfAhkiAAAA1NJREFUeJztnc1uozAURj8HjCMCikq7iNJu+v7vVXXRovJn1RDiWUztMQnttIuQmat7pKugAFn4yDZk8V0BwGIGIcTc18wVsXZWFQROJAohvMDwmLke1lovMDx2xO7AyVqtVmcVnmeWw8k6Ho9nFZ6Pw5tWqxXiOIaU0lccxyzyCoQCD4cDhmHwdTgcvEjgQ6IQwgtUSiFNU2w2G2w2GyilvEiWuBzWWi/QGIOu69B1HbTWAOBFWmunEqWUSNMURVHg9vYWRVEgz3MopRBFEe+RC+H2vXEcYYxB0zQoyxKvr68A/iyv7ro43AullMiyDHd3d3h4eMB+v0dRFEjTFFJKv6wyl+d4PGIYBmitUZYlnp6eIIRA3/cwxmAYBozjCCHE5zNxv9/j8fERu90OeZ4jSRJeUhfCLaV936NpGjw/PwMAtNZ4e3tDXdfexdly6vbELMtQFAV2ux3u7++x3W6xXq9Z4kI4ie/v76iqCgBQVRWyLJt9Rpl9OnUPN3meY7vd4ubmZrIvMpcl3A8BoK5rpGk6ERgyeU90MzKKIkgpkSQJlFJQSmG9XrPEhXASAUAphSRJIKVEFEV+BoYe4tMfcCJDoWGxxMvj3hHdmIc+5sb/TKLD2Z4r5vL8ZNz5nYEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEAn2a7uWji02Iuz0/H/kyiC0x1n+M4+gI4kX8JXFSmq9DHnMw4vDEUNwyDz5t24akclbkMYWitMQZ93/vM7zDA3TGZiWGEv9YaTdP4+GKOj16O0/jopmmgtYYx5qwnBvAh8bQHQ9u2KMvSB4jXdc1B7gsyF+ReliXatp2InHSocTedRvgDvwPEuaXC8sz5KMsSWmsMwzCVaK2FEMLf1LYtXl5eYK1F13Xc3OQKfNXcpG1bL9FdOzsTAcAYg6qquM3QlfiqzdDpTPSt98LeGNzw6/p8p+HXrESAW+/9S3y39R43wfwP+FsTzDOJ/gTL++f47K+3XyWNnXDxB1SBAAAAAElFTkSuQmCC" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3836" + clipPathUnits="userSpaceOnUse"><path + id="path3838" + d="m 1351,573 113,0 0,-68 -113,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3832" + clipPathUnits="userSpaceOnUse"><path + id="path3834" + d="m 1351,573 113,0 0,-68 -113,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3824" + clipPathUnits="userSpaceOnUse"><path + id="path3826" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3798" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3800" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAAAAACTooUSAAAAAXNCSVQI5gpbmQAAAZ9JREFUWIXt2U9v1DAQBfA348lmyXa1FdBSgRDf/4tVe4CI7J+oXtvzOKQIOCOnF8/Ft/lpZCeHeQIAgGCF4h9KBFLdJEEuokBVVevOSbi7OwiDiIZN14WqJOE5pZQdMEBtO+yGPmhN0XO8Xmdkp4mEfv/+w/2u13p3SZZ4Hn/AnTRo2B6evjwd3lnFGT3N47PcYipiIrY9PH77+nHotBpIv52PmH+eVGiQsBnuHz5/2m1qii8TprveVJa3av2wP9xt6j0dlojT0JsCMJAk1LptVRH9pgsqAhjoJedC0YqfBxGCytLfCJZcsgM1/3Qi8ru7gnQv7mQ17t9SgEutBEIBYEXvVVy1mtjEJjaxiU1sYhOb2MQmNrGJTWxiE5v4P2XLUXlt9Xd7AwA6vZRSLwxgKcXpfBVJL+kWI0LNjW68peLkMqPnOJ8nbCvuV/1lOs8xO5aNbo6X8YhTzR2y387H8RKzEwZ6msdnTDWzgCV9GOfkhFE8Xb7zuu9D9YTlkhxcZkScelshRUpOCCBqXdfZOkkZ3yANfJPEE1g11f0FocoCRBRb0tkAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3786" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3788"><g + id="g3790" + clip-path="url(#clipPath3782)"><g + id="g3792"><g + id="g3794" + transform="matrix(113,0,0,68,1351,444)"><image + id="image3796" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAYAAAC2ydrOAAAABHNCSVQICAgIfAhkiAAAA59JREFUeJztnclurDoURTdgmkAhSmlLiaL8/49FGSQodFZM5zd4sstUkdsMQnKPzpKsQgVMWDo2ZrCPB0BjBc/z1v5mvhGtV1XBw4lEz/OsQPeY+T601lage2wQ5sDI8n3/bLjnme0wsuZ5PhvueQEcK873fQRBgCiKEIYhwjBEEAQs8htwBY7jiGEY7BjH0YoEnEr0fR9CCCRJgjRNkWUZ0jRFHMdWJEvcDq21FaiUQtd16LoOUkoAsCK11hCmCoMgQBzHyPMcl5eXuLq6wn6/R5ZliOPYSmSRX49Z96ZpglIKTdOgLEu8vb0BOE6v5joBwE6jSZKgKAocDgc8PDzgcDigKApcXFxACMECN2SeZwzDACklyrLE8/MzPM9D3/dQSmEYBkzTBM/zjpVoptKiKHB7e4unpyc8Pj7i+voaaZoiDEO7NjJfi5lK+75H0zR4eXkBAEgp8f7+jrqu7cxoK9FMp1EUIU1T7Pd73Nzc4P7+Hnd3d8iyDFEUscSNMBI/Pj5QVRUAoKoq7HY7xHEMIcTiHeXs7VQIgTiOkaYp8jxHURTY7XZWIk+pX4+7HgJAXdf2JdMIdBHmJncAx7fVMAyRJAlL3BAjEQDiOLZbPneX4HqwEud5xjRNGMcR4zhimiZorRf7R5a4DaaQgiBYPPfPnr9wP+cYiebX3VAC/BluS8yzdsdn+MBxOjX7j2mazvYizM/FrpCn6+LpGsn8XM72DCzv34M3fgRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQQQn53gdKnv42+f/ZlEk/HmJi+aAXAi/xaYsEQzXB9rMoV7oytuGAabN23CU4MgYIkb4IbWKqXQ973N/F4LTVxUohvhL6VE0zQ2vjhJEs473YjT+OimaSClhFJqNcJ0EVprBLZti7IsbYB4XdecPLwha0HuZVmibduFyEWHGnPTaYQ/8H+AOKfxb8+aj7IsIaXEMAxLiSYi2tzUti1eX1+htUbXdcjz3Hap4eThbfhVc5O2ba1Ec+1qJQKAUgpVVa1G+DNfz6/aDJ1Wom2957ZUMM2+wjBcRPizxO34k4ZfqxIBbr33k/jT1nvcBPMf4HdNMM8k2hMs78fx2ae3/wBR6gt9OOvm0AAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3782" + clipPathUnits="userSpaceOnUse"><path + id="path3784" + d="m 1351,512 113,0 0,-68 -113,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3778" + clipPathUnits="userSpaceOnUse"><path + id="path3780" + d="m 1351,512 113,0 0,-68 -113,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3770" + clipPathUnits="userSpaceOnUse"><path + id="path3772" + d="m 1341,490 129,0 0,89 -129,0 0,-89 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3748" + clipPathUnits="userSpaceOnUse"><path + id="path3750" + d="m 1214,628 270,0 0,-182 -270,0 0,182 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3726" + clipPathUnits="userSpaceOnUse"><path + id="path3728" + d="m 652.002,520.002 12,0 0,11.998 -12,0 0,-11.998 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3722" + clipPathUnits="userSpaceOnUse"><path + id="path3724" + d="m 652,532 12.002,0 0,-12 -12.002,0 0,12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3700" + clipPathUnits="userSpaceOnUse"><path + id="path3702" + d="m 592,518.865 32,0 0,12 -32,0 0,-12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3696" + clipPathUnits="userSpaceOnUse"><path + id="path3698" + d="m 592,530.865 32,0 0,-12.002 -32,0 0,12.002 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3688" + clipPathUnits="userSpaceOnUse"><path + id="path3690" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3662" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3664" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAAAAAAc13L4AAAAAXNCSVQI5gpbmQAAAdJJREFUaIHt2rFu2zAUheFDirICJUZQt0OQdun7v1fgwRHqylJMkbyng1S0He5aarj/C/gDLWnhcQAAONSNfxTOwdXkkCBXjIP33vtqp0OIiAiIAMCHtm1DLQ0hJaWlCBjgfOj6x8cu+EoYKXGe5nsuCHC+7U+fT8euqfLckBKnH+8DKQgOvn368u311Le+ggVg/rie27KkUraTef3+cjzU+Z8kzZcu3caP5NZn5un08vX5oRJmmQ73S39o3PY2df3x+VPXVHlmZAlz3wXvHALgnG/aQ9c9VML4GDxIrt8ZOO980zR1MM47lpyLbBjArVXAAIDkkgvBOq/zP5EiRYTEDjDgGnaBAUgCe8FsGUbLMFqG0TKMlmG0DKNlGC3DaBlGyzBahtEyjJZhtAyjZRgtw2gZRsswWobRMoyWYbQMo2UYLcNoGUZru0r+fWX5//v7lwMAUCillCprHpZShMINQ0pJS4yoc+NfYlxSEXI9GclxHq+osxKh3K/jHLMACKDkeBvO+FlnP0NZxvNwi1mIAEqahzdcay2LJM3D2zAnIQKdpNuFU73NVYnj8H5LAq4ng3ituEbLcZrmJIQDXPWdXk4p5Q2zmwXj3radwF5Wr78ATrQFVxEFtwQAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3650" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3652"><g + id="g3654" + clip-path="url(#clipPath3646)"><g + id="g3656"><g + id="g3658" + transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"><image + id="image3660" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAABCJJREFUeJzt3UFvskwYheEDAmNQYkq7MLab/v//1bhQUgqMwjDMt3gzBJTmy7Ol50omNSLdcAcfcEEAwGFBEARLb9Mf4dxiFgjwEEwQBGMs09f0Nzjnxlimr73Iv/BhhGH4tKbbaZ18GMMwPK3p9mi6UxiGiKIIcRyPK4oiRrNy01istTDGwBiDrutgrZ1FEwH/QvCxKKWQpil2ux12ux2UUmM0DGadnHNjLG3bQmuNpmmgtcb9fkff97DWAsA8mDiOkaYp8jzH6+sr8jxHlmVQSmGz2XCmWSE/pwzDgLZt0TQNvr+/cb1eURTFbDsARNPZJY5j7Pd7vL294ePjA6fTCXmeI01TxHE8fjXRujjn0Pc9brcbyrLE+XxGHMew1qLrOhhjYK2Ftfb3M8zpdMLn5yeOxyOyLEOSJPxaWqlhGGCMgdYal8sFSikYY1DXNaqqwu12gzEGQRAszzD7/R55nuN4POL9/R2HwwHb7ZbBrNQwDOi6Dk3TIEkS3O93XC4XpGmKJEnGcQT45SrJD75ZluFwOODl5WU2x9B6+Pmk6zpEUQStNdI0fbrYeQrGvxmGITabDeI4RpIkUEpBKYXtdstgVsgHE4Yh2rad3UbxA+/0Bl70+A98NNN4povBrItzbnbMnXOw1qLv+/FyehiG34Px/BlnadF6DcMwhuL/Tn8q4HUyAZjfj/E38fzr6VcSg6HR48zyOL8ADIYWLIXiMRgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBI5NfHEP/fwyJpHaTH+SkY/yha/9daOy4AfG71yvgHm/s1PfZL4UTTHaeRGGPQdR3atkXbtgCAzWbDYFbGB+OPc9d1MMbM4pmGMzvD+Keit20LrTWqqkJZlgCA7XaLMAwZzMr4k8T9fkdZlqiqClprtG2Lvu8xDMPs89F0Jx9LXdcoigLn8xkA8PPzgyRJGMwK+WPfdR2qqsL5fEZRFKjrehaNP8vMgjHGQGuNoijw9fUFACjLEmmaIo5jhCEvqtZo6dgXRQGtNYwx82CccwiCYNyprmtcLhc459A0DbIsg1JqnF94hlkXP6P4OaaqKhRFgev1irqux2D8ZxfPMADQti3KsoRSClEU8etoxR5HkqZp0DTN4hkmAOCAf5fLYRgiiiLEcTwuH4v/DK2Pj8FHY4wZ1+MMMwsGAMIwfFrT7bRO02ge13T7GIw3nVM4s/w90/suS3d9n4IZNzCUP+23nwf+AzNnFIrywW/wAAAAAElFTkSuQmCC" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3646" + clipPathUnits="userSpaceOnUse"><path + id="path3648" + d="m 558.314,543.945 139.351,0 0,-78.634 -139.351,0 0,78.634 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3642" + clipPathUnits="userSpaceOnUse"><path + id="path3644" + d="m 558.314,543.945 139.351,0 0,-78.633 -139.351,0 0,78.633 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3634" + clipPathUnits="userSpaceOnUse"><path + id="path3636" + d="m 570.26,532 c 0,-30.785 24.955,-55.742 55.74,-55.742 l 0,0 c 30.784,0 55.74,24.957 55.74,55.742 l 0,0 c 0,30.784 -24.956,55.74 -55.74,55.74 l 0,0 c -30.785,0 -55.74,-24.956 -55.74,-55.74" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3610" + clipPathUnits="userSpaceOnUse"><path + id="path3612" + d="m 652.333,574.333 101,0 0,-79.333 -101,0 0,79.333 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3592" + clipPathUnits="userSpaceOnUse"><path + id="path3594" + d="m 730.778,549 12,0 0,-12 -12,0 0,12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3570" + clipPathUnits="userSpaceOnUse"><path + id="path3572" + d="m 679,535.865 32,0 0,12 -32,0 0,-12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3566" + clipPathUnits="userSpaceOnUse"><path + id="path3568" + d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3540" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3542" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg==" + height="1" + width="1" /></mask><mask + id="mask3528" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3530"><g + id="g3532" + clip-path="url(#clipPath3524)"><g + id="g3534"><g + id="g3536" + transform="matrix(93,0,0,68,667,493)"><image + id="image3538" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII=" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3524" + clipPathUnits="userSpaceOnUse"><path + id="path3526" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3520" + clipPathUnits="userSpaceOnUse"><path + id="path3522" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3498" + clipPathUnits="userSpaceOnUse"><path + id="path3500" + d="m 560,628 270,0 0,-182 -270,0 0,182 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3490" + clipPathUnits="userSpaceOnUse"><path + id="path3492" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3476" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3478" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABHcAAAK/CAAAAADGr34kAAAAAXNCSVQI5gpbmQAACLFJREFUeJzt1DEBACAMwDDAv+fhohwkCnp1zwJIndcBwHd8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4DaBSkuBn0AocgUAAAAAElFTkSuQmCC" + height="1" + width="1" /></mask><clipPath + id="clipPath3470" + clipPathUnits="userSpaceOnUse"><path + id="path3472" + d="m 538,215 954,0 0,118 -954,0 0,-118 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3460" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3462" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABHcAAAK/CAAAAADGr34kAAAAAXNCSVQI5gpbmQAACLFJREFUeJzt1DEBACAMwDDAv+fhohwkCnp1zwJIndcBwHd8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4DaBSkuBn0AocgUAAAAAElFTkSuQmCC" + height="1" + width="1" /></mask><clipPath + id="clipPath3454" + clipPathUnits="userSpaceOnUse"><path + id="path3456" + d="m 554,720 958,0 0,204 -958,0 0,-204 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3432" + clipPathUnits="userSpaceOnUse"><path + id="path3434" + d="m 904,587 32,0 0,12 -32,0 0,-12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3428" + clipPathUnits="userSpaceOnUse"><path + id="path3430" + d="m 904,599 32,0 0,-12.002 -32,0 0,12.002 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3420" + clipPathUnits="userSpaceOnUse"><path + id="path3422" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3396" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3398" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAACdCAAAAAAcMECVAAAAAXNCSVQI5gpbmQAAAZdJREFUaIHt27tu20AQheEzy6Vo0BKMKCkMJ03e/70MFzYR3YisljsnBQXETZpg1J0pt/gwGGz7GwAAhtjhX9UMFsmTIFfckFJKKWx7wt3dQWQAKfd9n6N0wpda6+JAhqU8jI+PQ05BuC/lcpmxODMs9eP+6343dCF3J1s5TR9wJ7Mh9dtvP172Y58CbMDrPL3atdRmt81ffj7vNiF3oV9Pb5h/HZNxvfl2//z96SEI/33AYTvkZLffMoy7py9DF4K3guM45AQgA2ap6zfD8BCEY9j0XTIDMgBYstR1XQyOrku2XjivT7ZOAI5PUMz3+8cIFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwv97bkEBSZIR4GcpAwCd3loLaX7YWnM6bzjprV5LQVQhUq61Oblu7kuZTwfEtS2nuSwOIIO+lPP0hmNglTOdy+JEBr3O0ysOoT3RNFcnMs3r+Z2X4BLqXB1cN0c5RDdc1QkD7E71Ge/bzd27+APu1Sr+ATqP3j0zgxPtAAAAAElFTkSuQmCC" + height="1" + width="1" /></mask><mask + id="mask3384" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3386"><g + id="g3388" + clip-path="url(#clipPath3380)"><g + id="g3390"><g + id="g3392" + transform="matrix(92,0,0,157,888,469)"><image + id="image3394" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAACdCAYAAAA5Wx9JAAAABHNCSVQICAgIfAhkiAAABIZJREFUeJzt111rs0gYxvHL92AipbYHIe1Jv//3CjlopMYXMmqcPdgdH03s7lOWvWDh+sPQUDWUX4c7Ew+AxUqe5639Wv1m1q6ywsMduOd5E/b8tfq9rLUT9vy1K3QvHKzv+w9rfl2t52DHcXxY8+vh/CHf9xGGIaIomlYYhkL/h+bYwzCg7/tpDcMwoQN/gXueN2EnSYI0TbHdbrHdbpEkyYQu8PWstRO2MQZN06BpGrRtCwATurV2CR5FEdI0RZ7neHl5QZ7nyLIMSZIgCALN9JXcnL7dbjDGoKoqFEWB8/kM4NeIcfeF89kdRRF2ux1eX1/x/v6Ow+GAPM+RpimiKJpGi1o2jiP6vkfbtiiKAsfjEZ7noes6GGPQ9z1utxs8z/t+hx8OB3x8fGC/3yPLMsRxrLGykhsnXdehqiqcTicAQNu2+Pr6wuVymdweRoqb4bvdDnmeY7/f4+3tDU9PT9hsNgJfyYFfr1eUZQkAKMsSu91u9fNv9ZTiPjizLMPT0xOen58Xc1z9aj6/AeByuSBN0wX2vMU53O30IAgQRRHiOEaSJEiSBJvNRuArOXAASJIEcRwjiiIEQTDt7LlZeP8GDn2OP18CX+bO4M5nbrdm9QDucv+ZtaWW/cRI5zxyAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInF353wVq7utSynzo9gFtrMY7j9PN2u00LADzP++/++v9h1tqF0dxuDT6cPzhH7vseXdfBGANjDAAgCAKB3+XAnVPXdej7foE/h1/s8HEcMQwDjDFo2xZVVaEsSwDAZrOB7/sCv8tt0uv1irIsUVUV2raFMQbDMGAcx8X94fwhh13XNYqiwOl0AgBcLhfEcSzwlZxd13Woqgqn0wlFUaCu6wW62+UL8L7v0bYtiqLA8XgEAJRliTRNEUURfF+HmrXW7IqiQNu26Pt+CW6thed500N1XePz8xPWWjRNgyzLkCTJNL+1w5e5Ge3meFVVKIoC5/MZdV1P4O7e1R0OAMYYlGWJJEkQhqHGyd90P5KbpkHTNKs73ANggT+Pe77vIwxDRFE0LYft7lGPOUyH3vf9tO5n+AIcAHzff1jz62q9Ofr9ml+fwF3zOa2Z/fPm5+61b50P4NMFQf+rvvt6/we8Kp4iURf8WgAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3380" + clipPathUnits="userSpaceOnUse"><path + id="path3382" + d="m 888,626 92,0 0,-157 -92,0 0,157 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3376" + clipPathUnits="userSpaceOnUse"><path + id="path3378" + d="m 888,626 92,0 0,-157 -92,0 0,157 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3354" + clipPathUnits="userSpaceOnUse"><path + id="path3356" + d="m 1116,527 26.006,0 0,3 -26.006,0 0,-3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3350" + clipPathUnits="userSpaceOnUse"><path + id="path3352" + d="m 1116,530 26.01,0 0,-3 -26.01,0 0,3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3328" + clipPathUnits="userSpaceOnUse"><path + id="path3330" + d="m 1057.994,527 11.006,0 0,3 -11.006,0 0,-3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3324" + clipPathUnits="userSpaceOnUse"><path + id="path3326" + d="m 1057.99,530 26,0 0,-3 -26,0 0,3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3302" + clipPathUnits="userSpaceOnUse"><path + id="path3304" + d="m 1000,527 26.006,0 0,3 -26.006,0 0,-3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3298" + clipPathUnits="userSpaceOnUse"><path + id="path3300" + d="m 1000,530 26.01,0 0,-3 -26.01,0 0,3 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3272" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3274" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3260" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3262"><g + id="g3264" + clip-path="url(#clipPath3256)"><g + id="g3266"><g + id="g3268" + transform="matrix(62,0,0,84,1107,495)"><image + id="image3270" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3256" + clipPathUnits="userSpaceOnUse"><path + id="path3258" + d="m 1107,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3252" + clipPathUnits="userSpaceOnUse"><path + id="path3254" + d="m 1107,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3226" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3228" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3214" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3216"><g + id="g3218" + clip-path="url(#clipPath3210)"><g + id="g3220"><g + id="g3222" + transform="matrix(62,0,0,84,1049,495)"><image + id="image3224" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3210" + clipPathUnits="userSpaceOnUse"><path + id="path3212" + d="m 1049,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3206" + clipPathUnits="userSpaceOnUse"><path + id="path3208" + d="m 1049,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3180" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3182" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3168" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3170"><g + id="g3172" + clip-path="url(#clipPath3164)"><g + id="g3174"><g + id="g3176" + transform="matrix(62,0,0,84,991,495)"><image + id="image3178" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3164" + clipPathUnits="userSpaceOnUse"><path + id="path3166" + d="m 991,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3160" + clipPathUnits="userSpaceOnUse"><path + id="path3162" + d="m 991,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3152" + clipPathUnits="userSpaceOnUse"><path + id="path3154" + d="m 897,482 239.999,0 0,135 -239.999,0 0,-135 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3126" + clipPathUnits="userSpaceOnUse"><path + id="path3128" + d="m 887,628 270,0 0,-182 -270,0 0,182 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3118" + clipPathUnits="userSpaceOnUse"><path + id="path3120" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3634-8" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3636-7" + d="m 570.26,532 c 0,-30.785 24.955,-55.742 55.74,-55.742 l 0,0 c 30.784,0 55.74,24.957 55.74,55.742 l 0,0 c 0,30.784 -24.956,55.74 -55.74,55.74 l 0,0 c -30.785,0 -55.74,-24.956 -55.74,-55.74" /></clipPath><clipPath + id="clipPath3642-3" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3644-4" + d="m 558.314,543.945 139.351,0 0,-78.633 -139.351,0 0,78.633 z" /></clipPath><mask + id="mask3650-5" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3652-7"><g + id="g3654-7" + clip-path="url(#clipPath3646-3)"><g + id="g3656-5"><g + id="g3658-1" + transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"><image + id="image3660-3" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAABCJJREFUeJzt3UFvskwYheEDAmNQYkq7MLab/v//1bhQUgqMwjDMt3gzBJTmy7Ol50omNSLdcAcfcEEAwGFBEARLb9Mf4dxiFgjwEEwQBGMs09f0Nzjnxlimr73Iv/BhhGH4tKbbaZ18GMMwPK3p9mi6UxiGiKIIcRyPK4oiRrNy01istTDGwBiDrutgrZ1FEwH/QvCxKKWQpil2ux12ux2UUmM0DGadnHNjLG3bQmuNpmmgtcb9fkff97DWAsA8mDiOkaYp8jzH6+sr8jxHlmVQSmGz2XCmWSE/pwzDgLZt0TQNvr+/cb1eURTFbDsARNPZJY5j7Pd7vL294ePjA6fTCXmeI01TxHE8fjXRujjn0Pc9brcbyrLE+XxGHMew1qLrOhhjYK2Ftfb3M8zpdMLn5yeOxyOyLEOSJPxaWqlhGGCMgdYal8sFSikYY1DXNaqqwu12gzEGQRAszzD7/R55nuN4POL9/R2HwwHb7ZbBrNQwDOi6Dk3TIEkS3O93XC4XpGmKJEnGcQT45SrJD75ZluFwOODl5WU2x9B6+Pmk6zpEUQStNdI0fbrYeQrGvxmGITabDeI4RpIkUEpBKYXtdstgVsgHE4Yh2rad3UbxA+/0Bl70+A98NNN4povBrItzbnbMnXOw1qLv+/FyehiG34Px/BlnadF6DcMwhuL/Tn8q4HUyAZjfj/E38fzr6VcSg6HR48zyOL8ADIYWLIXiMRgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBI5NfHEP/fwyJpHaTH+SkY/yha/9daOy4AfG71yvgHm/s1PfZL4UTTHaeRGGPQdR3atkXbtgCAzWbDYFbGB+OPc9d1MMbM4pmGMzvD+Keit20LrTWqqkJZlgCA7XaLMAwZzMr4k8T9fkdZlqiqClprtG2Lvu8xDMPs89F0Jx9LXdcoigLn8xkA8PPzgyRJGMwK+WPfdR2qqsL5fEZRFKjrehaNP8vMgjHGQGuNoijw9fUFACjLEmmaIo5jhCEvqtZo6dgXRQGtNYwx82CccwiCYNyprmtcLhc459A0DbIsg1JqnF94hlkXP6P4OaaqKhRFgev1irqux2D8ZxfPMADQti3KsoRSClEU8etoxR5HkqZp0DTN4hkmAOCAf5fLYRgiiiLEcTwuH4v/DK2Pj8FHY4wZ1+MMMwsGAMIwfFrT7bRO02ge13T7GIw3nVM4s/w90/suS3d9n4IZNzCUP+23nwf+AzNnFIrywW/wAAAAAElFTkSuQmCC" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3646-3" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3648-7" + d="m 558.314,543.945 139.351,0 0,-78.634 -139.351,0 0,78.634 z" /></clipPath><mask + id="mask3662-9" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3664-6" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAAAAAAc13L4AAAAAXNCSVQI5gpbmQAAAdJJREFUaIHt2rFu2zAUheFDirICJUZQt0OQdun7v1fgwRHqylJMkbyng1S0He5aarj/C/gDLWnhcQAAONSNfxTOwdXkkCBXjIP33vtqp0OIiAiIAMCHtm1DLQ0hJaWlCBjgfOj6x8cu+EoYKXGe5nsuCHC+7U+fT8euqfLckBKnH+8DKQgOvn368u311Le+ggVg/rie27KkUraTef3+cjzU+Z8kzZcu3caP5NZn5un08vX5oRJmmQ73S39o3PY2df3x+VPXVHlmZAlz3wXvHALgnG/aQ9c9VML4GDxIrt8ZOO980zR1MM47lpyLbBjArVXAAIDkkgvBOq/zP5EiRYTEDjDgGnaBAUgCe8FsGUbLMFqG0TKMlmG0DKNlGC3DaBlGyzBahtEyjJZhtAyjZRgtw2gZRsswWobRMoyWYbQMo2UYLcNoGUZru0r+fWX5//v7lwMAUCillCprHpZShMINQ0pJS4yoc+NfYlxSEXI9GclxHq+osxKh3K/jHLMACKDkeBvO+FlnP0NZxvNwi1mIAEqahzdcay2LJM3D2zAnIQKdpNuFU73NVYnj8H5LAq4ng3ituEbLcZrmJIQDXPWdXk4p5Q2zmwXj3radwF5Wr78ATrQFVxEFtwQAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><clipPath + id="clipPath3634-8-0" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3636-7-9" + d="m 570.26,532 c 0,-30.785 24.955,-55.742 55.74,-55.742 l 0,0 c 30.784,0 55.74,24.957 55.74,55.742 l 0,0 c 0,30.784 -24.956,55.74 -55.74,55.74 l 0,0 c -30.785,0 -55.74,-24.956 -55.74,-55.74" /></clipPath><clipPath + id="clipPath3642-3-4" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3644-4-2" + d="m 558.314,543.945 139.351,0 0,-78.633 -139.351,0 0,78.633 z" /></clipPath><mask + id="mask3650-5-0" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3652-7-6"><g + id="g3654-7-6" + clip-path="url(#clipPath3646-3-3)"><g + id="g3656-5-4"><g + id="g3658-1-6" + transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"><image + id="image3660-3-1" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAABCJJREFUeJzt3UFvskwYheEDAmNQYkq7MLab/v//1bhQUgqMwjDMt3gzBJTmy7Ol50omNSLdcAcfcEEAwGFBEARLb9Mf4dxiFgjwEEwQBGMs09f0Nzjnxlimr73Iv/BhhGH4tKbbaZ18GMMwPK3p9mi6UxiGiKIIcRyPK4oiRrNy01istTDGwBiDrutgrZ1FEwH/QvCxKKWQpil2ux12ux2UUmM0DGadnHNjLG3bQmuNpmmgtcb9fkff97DWAsA8mDiOkaYp8jzH6+sr8jxHlmVQSmGz2XCmWSE/pwzDgLZt0TQNvr+/cb1eURTFbDsARNPZJY5j7Pd7vL294ePjA6fTCXmeI01TxHE8fjXRujjn0Pc9brcbyrLE+XxGHMew1qLrOhhjYK2Ftfb3M8zpdMLn5yeOxyOyLEOSJPxaWqlhGGCMgdYal8sFSikYY1DXNaqqwu12gzEGQRAszzD7/R55nuN4POL9/R2HwwHb7ZbBrNQwDOi6Dk3TIEkS3O93XC4XpGmKJEnGcQT45SrJD75ZluFwOODl5WU2x9B6+Pmk6zpEUQStNdI0fbrYeQrGvxmGITabDeI4RpIkUEpBKYXtdstgVsgHE4Yh2rad3UbxA+/0Bl70+A98NNN4povBrItzbnbMnXOw1qLv+/FyehiG34Px/BlnadF6DcMwhuL/Tn8q4HUyAZjfj/E38fzr6VcSg6HR48zyOL8ADIYWLIXiMRgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBI5NfHEP/fwyJpHaTH+SkY/yha/9daOy4AfG71yvgHm/s1PfZL4UTTHaeRGGPQdR3atkXbtgCAzWbDYFbGB+OPc9d1MMbM4pmGMzvD+Keit20LrTWqqkJZlgCA7XaLMAwZzMr4k8T9fkdZlqiqClprtG2Lvu8xDMPs89F0Jx9LXdcoigLn8xkA8PPzgyRJGMwK+WPfdR2qqsL5fEZRFKjrehaNP8vMgjHGQGuNoijw9fUFACjLEmmaIo5jhCEvqtZo6dgXRQGtNYwx82CccwiCYNyprmtcLhc459A0DbIsg1JqnF94hlkXP6P4OaaqKhRFgev1irqux2D8ZxfPMADQti3KsoRSClEU8etoxR5HkqZp0DTN4hkmAOCAf5fLYRgiiiLEcTwuH4v/DK2Pj8FHY4wZ1+MMMwsGAMIwfFrT7bRO02ge13T7GIw3nVM4s/w90/suS3d9n4IZNzCUP+23nwf+AzNnFIrywW/wAAAAAElFTkSuQmCC" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3646-3-3" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3648-7-6" + d="m 558.314,543.945 139.351,0 0,-78.634 -139.351,0 0,78.634 z" /></clipPath><mask + id="mask3662-9-4" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3664-6-5" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAAAAAAc13L4AAAAAXNCSVQI5gpbmQAAAdJJREFUaIHt2rFu2zAUheFDirICJUZQt0OQdun7v1fgwRHqylJMkbyng1S0He5aarj/C/gDLWnhcQAAONSNfxTOwdXkkCBXjIP33vtqp0OIiAiIAMCHtm1DLQ0hJaWlCBjgfOj6x8cu+EoYKXGe5nsuCHC+7U+fT8euqfLckBKnH+8DKQgOvn368u311Le+ggVg/rie27KkUraTef3+cjzU+Z8kzZcu3caP5NZn5un08vX5oRJmmQ73S39o3PY2df3x+VPXVHlmZAlz3wXvHALgnG/aQ9c9VML4GDxIrt8ZOO980zR1MM47lpyLbBjArVXAAIDkkgvBOq/zP5EiRYTEDjDgGnaBAUgCe8FsGUbLMFqG0TKMlmG0DKNlGC3DaBlGyzBahtEyjJZhtAyjZRgtw2gZRsswWobRMoyWYbQMo2UYLcNoGUZru0r+fWX5//v7lwMAUCillCprHpZShMINQ0pJS4yoc+NfYlxSEXI9GclxHq+osxKh3K/jHLMACKDkeBvO+FlnP0NZxvNwi1mIAEqahzdcay2LJM3D2zAnIQKdpNuFU73NVYnj8H5LAq4ng3ituEbLcZrmJIQDXPWdXk4p5Q2zmwXj3radwF5Wr78ATrQFVxEFtwQAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><clipPath + id="clipPath3592-5" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3594-9" + d="m 730.778,549 12,0 0,-12 -12,0 0,12 z" /></clipPath><clipPath + id="clipPath3566-8" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3568-8" + d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath + id="clipPath3570-6" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3572-0" + d="m 679,535.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath + id="clipPath3520-6" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3522-3" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask + id="mask3528-3" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3530-7"><g + id="g3532-3" + clip-path="url(#clipPath3524-5)"><g + id="g3534-0"><g + id="g3536-4" + transform="matrix(93,0,0,68,667,493)"><image + id="image3538-4" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII=" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3524-5" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3526-4" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask + id="mask3540-4" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3542-1" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg==" + height="1" + width="1" /></mask><clipPath + id="clipPath3592-5-6" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3594-9-5" + d="m 730.778,549 12,0 0,-12 -12,0 0,12 z" /></clipPath><clipPath + id="clipPath3566-8-1" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3568-8-2" + d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath + id="clipPath3570-6-5" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3572-0-0" + d="m 679,535.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath + id="clipPath3520-6-0" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3522-3-3" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask + id="mask3528-3-8" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3530-7-0"><g + id="g3532-3-9" + clip-path="url(#clipPath3524-5-5)"><g + id="g3534-0-9"><g + id="g3536-4-3" + transform="matrix(93,0,0,68,667,493)"><image + id="image3538-4-0" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII=" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3524-5-5" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3526-4-5" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask + id="mask3540-4-8" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3542-1-9" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg==" + height="1" + width="1" /></mask><clipPath + id="clipPath3942-2" + clipPathUnits="userSpaceOnUse"><path + id="path3944-1" + d="m 1337.7,554.569 67.31,0 0,-64.569 -67.31,0 0,64.569 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3912-3" + clipPathUnits="userSpaceOnUse"><path + id="path3914-9" + d="m 1404.777,549.002 12,0 0,11.998 -12,0 0,-11.998 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3908-4" + clipPathUnits="userSpaceOnUse"><path + id="path3910-0" + d="m 1404.78,561 12,0 0,-12 -12,0 0,12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3886-1" + clipPathUnits="userSpaceOnUse"><path + id="path3888-7" + d="m 1363,547.865 32,0 0,12 -32,0 0,-12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3882-9" + clipPathUnits="userSpaceOnUse"><path + id="path3884-9" + d="m 1363,559.865 32,0 0,-12.002 -32,0 0,12.002 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3852-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3854-6" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAAAAACTooUSAAAAAXNCSVQI5gpbmQAAAXhJREFUWIXt2T9v3DAMBfBHWj4Fzh2CXjsEaZd+/+8VZGiN+v4Y1cni6+ADmqUjnQ7kqEE/ULQXPgEAQLBB8S8lAnE3SZCrKFBVVd8+CTMzA5EAaOr7PrmShC211sWABNGUh8fHnNRTtKVcrzMWY4JoPxw/Hw+585sl2cp5/AkzMgm033/59nIcevUCAavz+Cq3Upvce3z5/nzY+T0r7XZ+w/zrpMJ1jvvj89enB0/x94Rpn5PK/VvNw+HpU+78xFZwGnJSAAkQ0a7f5fzgKSLv+k5FgAQAoqJd1zmK6DqVdWppPZK1vES8u93xj/hHhRhiiCGGGGKIIYYYYoghhhhiiCGGGOL/Jt73ciRJuinvr08AQKO11vzCALbWjMa7SFqrt1LgutEtt9qMXHu0pcznCc5b6/NcFgOQQFvKZXzDyXszP17KYkQCrc7jKyb/9GGcqxGJYvXyg9ctEpZLNXDtEWXaJEWqRgggWyZl/IA08EMST2DTVPcPY4fdi0eNNAgAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3840-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3842-8"><g + id="g3844-1" + clip-path="url(#clipPath3836-1)"><g + id="g3846-7"><g + id="g3848-5" + transform="matrix(113,0,0,68,1351,505)"><image + id="image3850-5" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAYAAAC2ydrOAAAABHNCSVQICAgIfAhkiAAAA1NJREFUeJztnc1uozAURj8HjCMCikq7iNJu+v7vVXXRovJn1RDiWUztMQnttIuQmat7pKugAFn4yDZk8V0BwGIGIcTc18wVsXZWFQROJAohvMDwmLke1lovMDx2xO7AyVqtVmcVnmeWw8k6Ho9nFZ6Pw5tWqxXiOIaU0lccxyzyCoQCD4cDhmHwdTgcvEjgQ6IQwgtUSiFNU2w2G2w2GyilvEiWuBzWWi/QGIOu69B1HbTWAOBFWmunEqWUSNMURVHg9vYWRVEgz3MopRBFEe+RC+H2vXEcYYxB0zQoyxKvr68A/iyv7ro43AullMiyDHd3d3h4eMB+v0dRFEjTFFJKv6wyl+d4PGIYBmitUZYlnp6eIIRA3/cwxmAYBozjCCHE5zNxv9/j8fERu90OeZ4jSRJeUhfCLaV936NpGjw/PwMAtNZ4e3tDXdfexdly6vbELMtQFAV2ux3u7++x3W6xXq9Z4kI4ie/v76iqCgBQVRWyLJt9Rpl9OnUPN3meY7vd4ubmZrIvMpcl3A8BoK5rpGk6ERgyeU90MzKKIkgpkSQJlFJQSmG9XrPEhXASAUAphSRJIKVEFEV+BoYe4tMfcCJDoWGxxMvj3hHdmIc+5sb/TKLD2Z4r5vL8ZNz5nYEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEALJEAn2a7uWji02Iuz0/H/kyiC0x1n+M4+gI4kX8JXFSmq9DHnMw4vDEUNwyDz5t24akclbkMYWitMQZ93/vM7zDA3TGZiWGEv9YaTdP4+GKOj16O0/jopmmgtYYx5qwnBvAh8bQHQ9u2KMvSB4jXdc1B7gsyF+ReliXatp2InHSocTedRvgDvwPEuaXC8sz5KMsSWmsMwzCVaK2FEMLf1LYtXl5eYK1F13Xc3OQKfNXcpG1bL9FdOzsTAcAYg6qquM3QlfiqzdDpTPSt98LeGNzw6/p8p+HXrESAW+/9S3y39R43wfwP+FsTzDOJ/gTL++f47K+3XyWNnXDxB1SBAAAAAElFTkSuQmCC" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3836-1" + clipPathUnits="userSpaceOnUse"><path + id="path3838-6" + d="m 1351,573 113,0 0,-68 -113,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3832-3" + clipPathUnits="userSpaceOnUse"><path + id="path3834-3" + d="m 1351,573 113,0 0,-68 -113,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3824-4" + clipPathUnits="userSpaceOnUse"><path + id="path3826-5" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3798-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3800-3" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAAAAACTooUSAAAAAXNCSVQI5gpbmQAAAZ9JREFUWIXt2U9v1DAQBfA348lmyXa1FdBSgRDf/4tVe4CI7J+oXtvzOKQIOCOnF8/Ft/lpZCeHeQIAgGCF4h9KBFLdJEEuokBVVevOSbi7OwiDiIZN14WqJOE5pZQdMEBtO+yGPmhN0XO8Xmdkp4mEfv/+w/2u13p3SZZ4Hn/AnTRo2B6evjwd3lnFGT3N47PcYipiIrY9PH77+nHotBpIv52PmH+eVGiQsBnuHz5/2m1qii8TprveVJa3av2wP9xt6j0dlojT0JsCMJAk1LptVRH9pgsqAhjoJedC0YqfBxGCytLfCJZcsgM1/3Qi8ru7gnQv7mQ17t9SgEutBEIBYEXvVVy1mtjEJjaxiU1sYhOb2MQmNrGJTWxiE5v4P2XLUXlt9Xd7AwA6vZRSLwxgKcXpfBVJL+kWI0LNjW68peLkMqPnOJ8nbCvuV/1lOs8xO5aNbo6X8YhTzR2y387H8RKzEwZ6msdnTDWzgCV9GOfkhFE8Xb7zuu9D9YTlkhxcZkScelshRUpOCCBqXdfZOkkZ3yANfJPEE1g11f0FocoCRBRb0tkAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3786-0" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3788-7"><g + id="g3790-3" + clip-path="url(#clipPath3782-0)"><g + id="g3792-9"><g + id="g3794-3" + transform="matrix(113,0,0,68,1351,444)"><image + id="image3796-9" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHEAAABECAYAAAC2ydrOAAAABHNCSVQICAgIfAhkiAAAA59JREFUeJztnclurDoURTdgmkAhSmlLiaL8/49FGSQodFZM5zd4sstUkdsMQnKPzpKsQgVMWDo2ZrCPB0BjBc/z1v5mvhGtV1XBw4lEz/OsQPeY+T601lage2wQ5sDI8n3/bLjnme0wsuZ5PhvueQEcK873fQRBgCiKEIYhwjBEEAQs8htwBY7jiGEY7BjH0YoEnEr0fR9CCCRJgjRNkWUZ0jRFHMdWJEvcDq21FaiUQtd16LoOUkoAsCK11hCmCoMgQBzHyPMcl5eXuLq6wn6/R5ZliOPYSmSRX49Z96ZpglIKTdOgLEu8vb0BOE6v5joBwE6jSZKgKAocDgc8PDzgcDigKApcXFxACMECN2SeZwzDACklyrLE8/MzPM9D3/dQSmEYBkzTBM/zjpVoptKiKHB7e4unpyc8Pj7i+voaaZoiDEO7NjJfi5lK+75H0zR4eXkBAEgp8f7+jrqu7cxoK9FMp1EUIU1T7Pd73Nzc4P7+Hnd3d8iyDFEUscSNMBI/Pj5QVRUAoKoq7HY7xHEMIcTiHeXs7VQIgTiOkaYp8jxHURTY7XZWIk+pX4+7HgJAXdf2JdMIdBHmJncAx7fVMAyRJAlL3BAjEQDiOLZbPneX4HqwEud5xjRNGMcR4zhimiZorRf7R5a4DaaQgiBYPPfPnr9wP+cYiebX3VAC/BluS8yzdsdn+MBxOjX7j2mazvYizM/FrpCn6+LpGsn8XM72DCzv34M3fgRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQRgiQQQn53gdKnv42+f/ZlEk/HmJi+aAXAi/xaYsEQzXB9rMoV7oytuGAabN23CU4MgYIkb4IbWKqXQ973N/F4LTVxUohvhL6VE0zQ2vjhJEs473YjT+OimaSClhFJqNcJ0EVprBLZti7IsbYB4XdecPLwha0HuZVmibduFyEWHGnPTaYQ/8H+AOKfxb8+aj7IsIaXEMAxLiSYi2tzUti1eX1+htUbXdcjz3Hap4eThbfhVc5O2ba1Ec+1qJQKAUgpVVa1G+DNfz6/aDJ1Wom2957ZUMM2+wjBcRPizxO34k4ZfqxIBbr33k/jT1nvcBPMf4HdNMM8k2hMs78fx2ae3/wBR6gt9OOvm0AAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3782-0" + clipPathUnits="userSpaceOnUse"><path + id="path3784-8" + d="m 1351,512 113,0 0,-68 -113,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3778-1" + clipPathUnits="userSpaceOnUse"><path + id="path3780-0" + d="m 1351,512 113,0 0,-68 -113,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3770-5" + clipPathUnits="userSpaceOnUse"><path + id="path3772-0" + d="m 1341,490 129,0 0,89 -129,0 0,-89 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3748-6" + clipPathUnits="userSpaceOnUse"><path + id="path3750-3" + d="m 1214,628 270,0 0,-182 -270,0 0,182 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3726-6" + clipPathUnits="userSpaceOnUse"><path + id="path3728-1" + d="m 652.002,520.002 12,0 0,11.998 -12,0 0,-11.998 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3722-1" + clipPathUnits="userSpaceOnUse"><path + id="path3724-4" + d="m 652,532 12.002,0 0,-12 -12.002,0 0,12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3700-1" + clipPathUnits="userSpaceOnUse"><path + id="path3702-8" + d="m 592,518.865 32,0 0,12 -32,0 0,-12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3696-9" + clipPathUnits="userSpaceOnUse"><path + id="path3698-6" + d="m 592,530.865 32,0 0,-12.002 -32,0 0,12.002 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3688-4" + clipPathUnits="userSpaceOnUse"><path + id="path3690-8" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3662-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3664-9" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAAAAAAc13L4AAAAAXNCSVQI5gpbmQAAAdJJREFUaIHt2rFu2zAUheFDirICJUZQt0OQdun7v1fgwRHqylJMkbyng1S0He5aarj/C/gDLWnhcQAAONSNfxTOwdXkkCBXjIP33vtqp0OIiAiIAMCHtm1DLQ0hJaWlCBjgfOj6x8cu+EoYKXGe5nsuCHC+7U+fT8euqfLckBKnH+8DKQgOvn368u311Le+ggVg/rie27KkUraTef3+cjzU+Z8kzZcu3caP5NZn5un08vX5oRJmmQ73S39o3PY2df3x+VPXVHlmZAlz3wXvHALgnG/aQ9c9VML4GDxIrt8ZOO980zR1MM47lpyLbBjArVXAAIDkkgvBOq/zP5EiRYTEDjDgGnaBAUgCe8FsGUbLMFqG0TKMlmG0DKNlGC3DaBlGyzBahtEyjJZhtAyjZRgtw2gZRsswWobRMoyWYbQMo2UYLcNoGUZru0r+fWX5//v7lwMAUCillCprHpZShMINQ0pJS4yoc+NfYlxSEXI9GclxHq+osxKh3K/jHLMACKDkeBvO+FlnP0NZxvNwi1mIAEqahzdcay2LJM3D2zAnIQKdpNuFU73NVYnj8H5LAq4ng3ituEbLcZrmJIQDXPWdXk4p5Q2zmwXj3radwF5Wr78ATrQFVxEFtwQAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3650-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3652-6"><g + id="g3654-8" + clip-path="url(#clipPath3646-6)"><g + id="g3656-3"><g + id="g3658-9" + transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)"><image + id="image3660-2" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAABCJJREFUeJzt3UFvskwYheEDAmNQYkq7MLab/v//1bhQUgqMwjDMt3gzBJTmy7Ol50omNSLdcAcfcEEAwGFBEARLb9Mf4dxiFgjwEEwQBGMs09f0Nzjnxlimr73Iv/BhhGH4tKbbaZ18GMMwPK3p9mi6UxiGiKIIcRyPK4oiRrNy01istTDGwBiDrutgrZ1FEwH/QvCxKKWQpil2ux12ux2UUmM0DGadnHNjLG3bQmuNpmmgtcb9fkff97DWAsA8mDiOkaYp8jzH6+sr8jxHlmVQSmGz2XCmWSE/pwzDgLZt0TQNvr+/cb1eURTFbDsARNPZJY5j7Pd7vL294ePjA6fTCXmeI01TxHE8fjXRujjn0Pc9brcbyrLE+XxGHMew1qLrOhhjYK2Ftfb3M8zpdMLn5yeOxyOyLEOSJPxaWqlhGGCMgdYal8sFSikYY1DXNaqqwu12gzEGQRAszzD7/R55nuN4POL9/R2HwwHb7ZbBrNQwDOi6Dk3TIEkS3O93XC4XpGmKJEnGcQT45SrJD75ZluFwOODl5WU2x9B6+Pmk6zpEUQStNdI0fbrYeQrGvxmGITabDeI4RpIkUEpBKYXtdstgVsgHE4Yh2rad3UbxA+/0Bl70+A98NNN4povBrItzbnbMnXOw1qLv+/FyehiG34Px/BlnadF6DcMwhuL/Tn8q4HUyAZjfj/E38fzr6VcSg6HR48zyOL8ADIYWLIXiMRgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBIhMGQCIMhEQZDIgyGRBgMiTAYEmEwJMJgSITBkAiDIREGQyIMhkQYDIkwGBJhMCTCYEiEwZAIgyERBkMiDIZEGAyJMBgSYTAkwmBI5NfHEP/fwyJpHaTH+SkY/yha/9daOy4AfG71yvgHm/s1PfZL4UTTHaeRGGPQdR3atkXbtgCAzWbDYFbGB+OPc9d1MMbM4pmGMzvD+Keit20LrTWqqkJZlgCA7XaLMAwZzMr4k8T9fkdZlqiqClprtG2Lvu8xDMPs89F0Jx9LXdcoigLn8xkA8PPzgyRJGMwK+WPfdR2qqsL5fEZRFKjrehaNP8vMgjHGQGuNoijw9fUFACjLEmmaIo5jhCEvqtZo6dgXRQGtNYwx82CccwiCYNyprmtcLhc459A0DbIsg1JqnF94hlkXP6P4OaaqKhRFgev1irqux2D8ZxfPMADQti3KsoRSClEU8etoxR5HkqZp0DTN4hkmAOCAf5fLYRgiiiLEcTwuH4v/DK2Pj8FHY4wZ1+MMMwsGAMIwfFrT7bRO02ge13T7GIw3nVM4s/w90/suS3d9n4IZNzCUP+23nwf+AzNnFIrywW/wAAAAAElFTkSuQmCC" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3646-6" + clipPathUnits="userSpaceOnUse"><path + id="path3648-8" + d="m 558.314,543.945 139.351,0 0,-78.634 -139.351,0 0,78.634 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3642-7" + clipPathUnits="userSpaceOnUse"><path + id="path3644-3" + d="m 558.314,543.945 139.351,0 0,-78.633 -139.351,0 0,78.633 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3634-3" + clipPathUnits="userSpaceOnUse"><path + id="path3636-8" + d="m 570.26,532 c 0,-30.785 24.955,-55.742 55.74,-55.742 l 0,0 c 30.784,0 55.74,24.957 55.74,55.742 l 0,0 c 0,30.784 -24.956,55.74 -55.74,55.74 l 0,0 c -30.785,0 -55.74,-24.956 -55.74,-55.74" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3610-5" + clipPathUnits="userSpaceOnUse"><path + id="path3612-4" + d="m 652.333,574.333 101,0 0,-79.333 -101,0 0,79.333 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3592-6" + clipPathUnits="userSpaceOnUse"><path + id="path3594-98" + d="m 730.778,549 12,0 0,-12 -12,0 0,12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3570-0" + clipPathUnits="userSpaceOnUse"><path + id="path3572-8" + d="m 679,535.865 32,0 0,12 -32,0 0,-12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3566-5" + clipPathUnits="userSpaceOnUse"><path + id="path3568-3" + d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3540-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3542-0" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg==" + height="1" + width="1" /></mask><mask + id="mask3528-8" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3530-9"><g + id="g3532-7" + clip-path="url(#clipPath3524-3)"><g + id="g3534-3"><g + id="g3536-8" + transform="matrix(93,0,0,68,667,493)"><image + id="image3538-8" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII=" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3524-3" + clipPathUnits="userSpaceOnUse"><path + id="path3526-7" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3520-9" + clipPathUnits="userSpaceOnUse"><path + id="path3522-1" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3498-7" + clipPathUnits="userSpaceOnUse"><path + id="path3500-1" + d="m 560,628 270,0 0,-182 -270,0 0,182 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3490-4" + clipPathUnits="userSpaceOnUse"><path + id="path3492-5" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3476-8" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3478-3" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABHcAAAK/CAAAAADGr34kAAAAAXNCSVQI5gpbmQAACLFJREFUeJzt1DEBACAMwDDAv+fhohwkCnp1zwJIndcBwHd8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4DaBSkuBn0AocgUAAAAAElFTkSuQmCC" + height="1" + width="1" /></mask><clipPath + id="clipPath3470-9" + clipPathUnits="userSpaceOnUse"><path + id="path3472-6" + d="m 538,215 954,0 0,118 -954,0 0,-118 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3460-8" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3462-0" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABHcAAAK/CAAAAADGr34kAAAAAXNCSVQI5gpbmQAACLFJREFUeJzt1DEBACAMwDDAv+fhohwkCnp1zwJIndcBwHd8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4Ca7wA13wFqvgPUfAeo+Q5Q8x2g5jtAzXeAmu8ANd8Bar4D1HwHqPkOUPMdoOY7QM13gJrvADXfAWq+A9R8B6j5DlDzHaDmO0DNd4DaBSkuBn0AocgUAAAAAElFTkSuQmCC" + height="1" + width="1" /></mask><clipPath + id="clipPath3454-4" + clipPathUnits="userSpaceOnUse"><path + id="path3456-3" + d="m 554,720 958,0 0,204 -958,0 0,-204 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3432-5" + clipPathUnits="userSpaceOnUse"><path + id="path3434-1" + d="m 904,587 32,0 0,12 -32,0 0,-12 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3428-5" + clipPathUnits="userSpaceOnUse"><path + id="path3430-0" + d="m 904,599 32,0 0,-12.002 -32,0 0,12.002 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3420-8" + clipPathUnits="userSpaceOnUse"><path + id="path3422-5" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3396-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3398-2" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAACdCAAAAAAcMECVAAAAAXNCSVQI5gpbmQAAAZdJREFUaIHt27tu20AQheEzy6Vo0BKMKCkMJ03e/70MFzYR3YisljsnBQXETZpg1J0pt/gwGGz7GwAAhtjhX9UMFsmTIFfckFJKKWx7wt3dQWQAKfd9n6N0wpda6+JAhqU8jI+PQ05BuC/lcpmxODMs9eP+6343dCF3J1s5TR9wJ7Mh9dtvP172Y58CbMDrPL3atdRmt81ffj7vNiF3oV9Pb5h/HZNxvfl2//z96SEI/33AYTvkZLffMoy7py9DF4K3guM45AQgA2ap6zfD8BCEY9j0XTIDMgBYstR1XQyOrku2XjivT7ZOAI5PUMz3+8cIFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwoULFy5cuHDhwv97bkEBSZIR4GcpAwCd3loLaX7YWnM6bzjprV5LQVQhUq61Oblu7kuZTwfEtS2nuSwOIIO+lPP0hmNglTOdy+JEBr3O0ysOoT3RNFcnMs3r+Z2X4BLqXB1cN0c5RDdc1QkD7E71Ge/bzd27+APu1Sr+ATqP3j0zgxPtAAAAAElFTkSuQmCC" + height="1" + width="1" /></mask><mask + id="mask3384-8" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3386-8"><g + id="g3388-5" + clip-path="url(#clipPath3380-6)"><g + id="g3390-8"><g + id="g3392-8" + transform="matrix(92,0,0,157,888,469)"><image + id="image3394-9" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFwAAACdCAYAAAA5Wx9JAAAABHNCSVQICAgIfAhkiAAABIZJREFUeJzt111rs0gYxvHL92AipbYHIe1Jv//3CjlopMYXMmqcPdgdH03s7lOWvWDh+sPQUDWUX4c7Ew+AxUqe5639Wv1m1q6ywsMduOd5E/b8tfq9rLUT9vy1K3QvHKzv+w9rfl2t52DHcXxY8+vh/CHf9xGGIaIomlYYhkL/h+bYwzCg7/tpDcMwoQN/gXueN2EnSYI0TbHdbrHdbpEkyYQu8PWstRO2MQZN06BpGrRtCwATurV2CR5FEdI0RZ7neHl5QZ7nyLIMSZIgCALN9JXcnL7dbjDGoKoqFEWB8/kM4NeIcfeF89kdRRF2ux1eX1/x/v6Ow+GAPM+RpimiKJpGi1o2jiP6vkfbtiiKAsfjEZ7noes6GGPQ9z1utxs8z/t+hx8OB3x8fGC/3yPLMsRxrLGykhsnXdehqiqcTicAQNu2+Pr6wuVymdweRoqb4bvdDnmeY7/f4+3tDU9PT9hsNgJfyYFfr1eUZQkAKMsSu91u9fNv9ZTiPjizLMPT0xOen58Xc1z9aj6/AeByuSBN0wX2vMU53O30IAgQRRHiOEaSJEiSBJvNRuArOXAASJIEcRwjiiIEQTDt7LlZeP8GDn2OP18CX+bO4M5nbrdm9QDucv+ZtaWW/cRI5zxyAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInJ3ByAicncHICJydwcgInF353wVq7utSynzo9gFtrMY7j9PN2u00LADzP++/++v9h1tqF0dxuDT6cPzhH7vseXdfBGANjDAAgCAKB3+XAnVPXdej7foE/h1/s8HEcMQwDjDFo2xZVVaEsSwDAZrOB7/sCv8tt0uv1irIsUVUV2raFMQbDMGAcx8X94fwhh13XNYqiwOl0AgBcLhfEcSzwlZxd13Woqgqn0wlFUaCu6wW62+UL8L7v0bYtiqLA8XgEAJRliTRNEUURfF+HmrXW7IqiQNu26Pt+CW6thed500N1XePz8xPWWjRNgyzLkCTJNL+1w5e5Ge3meFVVKIoC5/MZdV1P4O7e1R0OAMYYlGWJJEkQhqHGyd90P5KbpkHTNKs73ANggT+Pe77vIwxDRFE0LYft7lGPOUyH3vf9tO5n+AIcAHzff1jz62q9Ofr9ml+fwF3zOa2Z/fPm5+61b50P4NMFQf+rvvt6/we8Kp4iURf8WgAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3380-6" + clipPathUnits="userSpaceOnUse"><path + id="path3382-6" + d="m 888,626 92,0 0,-157 -92,0 0,157 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3376-1" + clipPathUnits="userSpaceOnUse"><path + id="path3378-8" + d="m 888,626 92,0 0,-157 -92,0 0,157 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3354-1" + clipPathUnits="userSpaceOnUse"><path + id="path3356-9" + d="m 1116,527 26.006,0 0,3 -26.006,0 0,-3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3350-2" + clipPathUnits="userSpaceOnUse"><path + id="path3352-7" + d="m 1116,530 26.01,0 0,-3 -26.01,0 0,3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3328-2" + clipPathUnits="userSpaceOnUse"><path + id="path3330-1" + d="m 1057.994,527 11.006,0 0,3 -11.006,0 0,-3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3324-6" + clipPathUnits="userSpaceOnUse"><path + id="path3326-2" + d="m 1057.99,530 26,0 0,-3 -26,0 0,3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3302-2" + clipPathUnits="userSpaceOnUse"><path + id="path3304-7" + d="m 1000,527 26.006,0 0,3 -26.006,0 0,-3 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3298-9" + clipPathUnits="userSpaceOnUse"><path + id="path3300-4" + d="m 1000,530 26.01,0 0,-3 -26.01,0 0,3 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3272-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3274-5" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3260-5" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3262-2"><g + id="g3264-6" + clip-path="url(#clipPath3256-0)"><g + id="g3266-6"><g + id="g3268-0" + transform="matrix(62,0,0,84,1107,495)"><image + id="image3270-6" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3256-0" + clipPathUnits="userSpaceOnUse"><path + id="path3258-5" + d="m 1107,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3252-1" + clipPathUnits="userSpaceOnUse"><path + id="path3254-3" + d="m 1107,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3226-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3228-8" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3214-5" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3216-2"><g + id="g3218-9" + clip-path="url(#clipPath3210-9)"><g + id="g3220-8"><g + id="g3222-2" + transform="matrix(62,0,0,84,1049,495)"><image + id="image3224-4" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3210-9" + clipPathUnits="userSpaceOnUse"><path + id="path3212-3" + d="m 1049,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3206-7" + clipPathUnits="userSpaceOnUse"><path + id="path3208-1" + d="m 1049,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><mask + id="mask3180-7" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3182-1" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAAAAAD/xdukAAAAAXNCSVQI5gpbmQAAAZZJREFUWIXt2L1u3DAQBOBZijoZsg9GLikMO03e/72MK85CLvrxUeTuuJCCJB0lA6m4tT4tl6x2BAAAwdbiHycC2fYDEuTCBc455zacgDAzMxAegPN1Xft8T5jGOKuBHuJ8097fN95lc9MwjdMtKTzE1e3p6+nYVJnzkxbGn28dafACVz98+/58amuX2z29X8+1zlF17f784+l4yD29xenSxKF/j7LM/nB6enm8y+bzeLhd2kMl68037fHxS1Nlzm6zn9rGOxF4QMRV9aFp7rK5C96B5PLuECeuqqpcLk6oKamtHJClsjgAWNKkBHMf69/+NFMzErs4uBR2coAksJ+vVXjhhRdeeOGFF1544YUXXvh/5usO+3srzKm/v/UAQKOpamZ0QlU1GldOmsY5BOQu4BrCHNXIpbulMPVX5IYPtNu1n0IyAB60FIbujF+50Qdt7s/dEJIRHrQ4da+45gcvFqfutZuiEZ5icbhw3BL7aOi7tyEauHRHuG4KnVIYxykaIYDsiLxSjDGt/BOB2+fjPmB/2PgBJp8FYb3sImYAAAAASUVORK5CYII=" + height="1" + width="1" /></mask><mask + id="mask3168-6" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3170-1"><g + id="g3172-4" + clip-path="url(#clipPath3164-3)"><g + id="g3174-6"><g + id="g3176-0" + transform="matrix(62,0,0,84,991,495)"><image + id="image3178-0" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAD4AAABUCAYAAADaroR4AAAABHNCSVQICAgIfAhkiAAAA1pJREFUeJztnMtuqzoYRheES0QSRaUdRGknff/3qjJIUCmXYIzhDI6MTC5765wR1F6SFQvHESvmByb+PGDgAZ7nPTq8OIbhoR4eN+Ke543SZn9pDMMwSpt9TaA7WtD3/btmjs8dLdj3/V0zxwNzku/7BEFAGIZjC4JgMfKmtFIKKSVSStq2RSk1kQ/gXyEtHccxSZKw2WzYbDbEcTzKL0FcSwshqOuaqqqo65qmaei6DqUUwFQ8DEOSJCFNU15fX0nTlN1uRxzHrFarWde8ruO+7xFCUFUV39/fXC4XsiybjAMEZm2HYch2u+Xt7Y2Pjw+OxyNpmpIkCWEYjpf8XBmGga7ruF6v5HnO6XQiDEOUUrRti5QSpRRKqecrfjwe+fz85HA4sNvtiKJo9pd73/dIKanrmvP5TBzHSCkpy5KiKLher0gp8TzvcY1vt1vSNOVwOPD+/s5+v2e9Xi9CvG1bqqoiiiKapuF8PpMkCVEUjeUKT+7q+ga32+3Y7/e8vLxM6nyO6Ppt25YgCKjrmiRJ7m7Od+L6oO/7rFYrwjAkiiLiOCaOY9br9SLEfd9HCDF5DOsbm/kiE9z+gJY3/wSzzVncPPdhGFBK0XXd+Bjr+/65uEZfAY/aEuj7fhTWn+Yr7LyfT/8D83mtX2Z037zUf5043Nf0bX3DLxXXPBLW/GrxP+HEbcOJ24YTtw0nbhtO3DacuG04cdtw4rbhxG3DiduGE7cNJ24bTtw2nLhtOHHbcOK24cRtw4nbhhO3DSduG07cNpy4bThx23DituHEbcOJ24YTtw1rxZ/uLf3bTr258V/P905c78s0gyZ0g/kmg+jdw7qZDo/+gMCcaMrqGBEhBEIIgNlvo9ZpIEKISSbE7YZauFlxvfVYR4kURUGe5wCzj0rQi9Y0DXmeUxQFdV0jhKDrujENRBOYk7R0WZZkWcbpdALg5+dn9uEYZlRCURScTieyLKMsy4n8ZOO8nqQTNbIs4+vrC4A8zxcTh/LIIcsy6rpGSjkV1xEDelJZlpzPZ4ZhoKqqxQXg6DovioIsy7hcLpRlOYrr7z5ccQAhBHmeLzLySJdsVVVj5NHtio+xZmYWzG8Iueq6bgy5klLe1fhEHOyJNbM2yO5OfBxYqPAtz15b/wHsvBSUT5t0gwAAAABJRU5ErkJggg==" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3164-3" + clipPathUnits="userSpaceOnUse"><path + id="path3166-1" + d="m 991,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3160-9" + clipPathUnits="userSpaceOnUse"><path + id="path3162-3" + d="m 991,579 62,0 0,-84 -62,0 0,84 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3152-4" + clipPathUnits="userSpaceOnUse"><path + id="path3154-4" + d="m 897,482 239.999,0 0,135 -239.999,0 0,-135 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3126-1" + clipPathUnits="userSpaceOnUse"><path + id="path3128-0" + d="m 887,628 270,0 0,-182 -270,0 0,182 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3118-8" + clipPathUnits="userSpaceOnUse"><path + id="path3120-5" + d="m 0,1080 1920,0 L 1920,0 0,0 0,1080 z" + inkscape:connector-curvature="0" /></clipPath><clipPath + id="clipPath3722-1-6" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3724-4-6" + d="m 652,532 12.002,0 0,-12 -12.002,0 0,12 z" /></clipPath><clipPath + id="clipPath3726-6-9" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3728-1-7" + d="m 652.002,520.002 12,0 0,11.998 -12,0 0,-11.998 z" /></clipPath><clipPath + id="clipPath3696-9-7" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3698-6-3" + d="m 592,530.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath + id="clipPath3700-1-1" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3702-8-2" + d="m 592,518.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath + id="clipPath3696-9-7-9" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3698-6-3-5" + d="m 592,530.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath + id="clipPath3700-1-1-8" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3702-8-2-6" + d="m 592,518.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath + id="clipPath3722-1-6-1" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3724-4-6-5" + d="m 652,532 12.002,0 0,-12 -12.002,0 0,12 z" /></clipPath><clipPath + id="clipPath3726-6-9-4" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3728-1-7-6" + d="m 652.002,520.002 12,0 0,11.998 -12,0 0,-11.998 z" /></clipPath><clipPath + id="clipPath3086-4-0"><path + inkscape:connector-curvature="0" + d="m 1058,722 374,0 0,-374 -374,0 0,374 z" + id="path3088-8-7" /></clipPath><clipPath + id="clipPath3100-8-2"><path + inkscape:connector-curvature="0" + d="m 1029,344 432,0 0,-32 -432,0 0,32 z" + id="path3102-2-9" /></clipPath><clipPath + id="clipPath3116-4-9"><path + inkscape:connector-curvature="0" + d="m 1029,756 432,0 0,-32 -432,0 0,32 z" + id="path3118-5-1" /></clipPath><clipPath + id="clipPath3592-5-68" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3594-9-1" + d="m 730.778,549 12,0 0,-12 -12,0 0,12 z" /></clipPath><clipPath + id="clipPath3566-8-9" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3568-8-22" + d="m 679,547.865 32,0 0,-12.002 -32,0 0,12.002 z" /></clipPath><clipPath + id="clipPath3570-6-4" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3572-0-00" + d="m 679,535.865 32,0 0,12 -32,0 0,-12 z" /></clipPath><clipPath + id="clipPath3520-6-4" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3522-3-32" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask + id="mask3528-3-5" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><g + id="g3530-7-3"><g + id="g3532-3-5" + clip-path="url(#clipPath3524-5-2)"><g + id="g3534-0-0"><g + id="g3536-4-5" + transform="matrix(93,0,0,68,667,493)"><image + id="image3538-4-00" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAA51JREFUeJztnEtv4koQRo/BpokBoThZIJJN/v/vCkoUYuSAbYwfPYu57duOzWPm3lEvpo5UwqLbXhyXihaLzwM0A3ieN/S1cCNaD2oFwOObdM/zWuH2tXAbWutWuH1t45sLI3c0GvXKXheGMXKbpumVvQ6WdPgp3Pd9giBoy/d9EX8FW3hd15RlSVmWnE4n6rruiffhp0wjXClFGIbMZjNmsxlKqVa8SB9Ga90KL4qCLMvIsow0TTkej1RVRV3X7f6O9CAICMOQKIp4eHggiiIWiwVKKcbjscz4AczcbpqG0+lEmqbsdjviOGY0GrXrZo/WGt+e5UEQMJ/PeXx85Pn5mfV6TRRFhGFIEATtmBG6aK2pqorj8UiSJLy/v6OUomkayrK8vdPX6zUvLy+sVisWiwWTyURGzBmapqGqKvI8J45jwjBEa02e5+2IKcvy306H/kyfz+dEUcRqteLp6Ynlcsl0OhXpZzDSsyxjNpvRNA37/Z7tdst2u22nhBnPg6cX82O6WCxYLpfc39935rrQxYyX6XQKwH6/Z7lcMp/PW2/2aO6c003Hj8djgiBgMpmglEIpxXQ6FelnMNIB8jwnDEPu7u5QShEEQe8Q4n9/gBFvvwC7RHofc/42zer7flv2WDH0pBvMxqES+pgmtctuYBs5A/4BrjWoSHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASHeASP8D2GlGQ5zNBrBvvPaQvx07LsouO0LKpifd3mjCwEyBJNYNYaJHTFJdVVVtGZeDEYH22zI3n04niqKgKAoAiR45g5GeZRl5nrefRVFQliV1XXfEdzrdxCKZmLv9fk+SJAASJ3UBO07q8/OTOI5JkoTD4UBRFJ1sRvhHuulwI/xwOBDHMW9vbwB8fX1JcNoFvgenvb6+8vHxQZIk5HneCU1rg9OM9LIsybKMOI7ZbDYAJEkiEYFXGIoI3Gw2xHFMmqYd6QC+1hrP81rph8OB7XaL1po0TSUM8wqXwjB3ux15nlNVVf+H9HunAxRFQZIkEvt6A5diX+2ZbsS3Ud52NqMEHP8atwQc26eXjnSQKO/f5VeivCW0/n/mltD6nvR2QWT/Jy79ZfIDbR7YvKqk0OoAAAAASUVORK5CYII=" + transform="matrix(1,0,0,-1,0,1)" + height="1" + width="1" /></g></g></g></g></mask><clipPath + id="clipPath3524-5-2" + clipPathUnits="userSpaceOnUse"><path + inkscape:connector-curvature="0" + id="path3526-4-1" + d="m 667,561 93,0 0,-68 -93,0 0,68 z" /></clipPath><mask + id="mask3540-4-88" + height="1" + width="1" + y="0" + x="0" + maskUnits="userSpaceOnUse"><image + id="image3542-1-5" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAAAAADGw2ZMAAAAAXNCSVQI5gpbmQAAAZJJREFUWIXt2DFv2zAQhuHvTlTkyDaMuBmCtEv//+9q0KKuAtWWZJnkfR0UAwY69jyVXAhoeEQcyOUVAAAEvos3rAjE0ydBfugCVVV1Oz9hZmYgEABoqOs6ePGE5Rgv2UAEiIamXa+boE665Xkch3PKQIBo3e4/7bdN5TJ70i7De6ckjUGg9eb5y+u+rdUBB5jO/Y/G4s3ZX7++bB98RmNp6lpOwzkal7lv9i+fdysvfVzb8XCoVWS5M0273T01lYvOtMJxt2kqBQIgolX90DQrLx1T+9jUlQgCAIiKVlXlpKOqQwgqsrwmALIsDx2iqioqAHxu4V8/+DjoffTrKnrRi170ohe96EUvetGLXvSiF/3/0bkkvWsnIHn98u+ymRmNV51Gyzn7RD2mHFNKxqUYkpbjZZ7h1WfGaZzmmEkEAJbm8djDr1z96vrTnA0IoKX51H3Hb8fq9u1nP0UjA2hx7N7QuxbDt26IRgSKxdOBg3PtfJ8Sl8nEEXPvXWrnbIQAcqfKTN65kN+97t9sfv6y/QG64fFP78GtbgAAAABJRU5ErkJggg==" + height="1" + width="1" /></mask></defs><g + inkscape:groupmode="layer" + id="layer8" + inkscape:label="Layer5" + transform="translate(436.0495,72.4457)"><g + style="display:inline" + id="g3508-5-64" + transform="matrix(5.09,0,0,-5.09,-201.82504,927.02677)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c -2.209,0 -4,1.791 -4,4 l 0,92 c 0,2.209 1.791,4 4,4 l 92,0 c 2.209,0 4,-1.791 4,-4 L 96,4 C 96,1.791 94.209,0 92,0 L 0,0 z" + style="fill:#4fbdee;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3510-0-3" /></g><g + style="display:inline" + id="g3516-7-0" + transform="matrix(5.09,0,0,-5.09,-3586.6755,3426.2166)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3518-2-5" /><g + id="g3544-9-2"><g + style="opacity:0.119995" + clip-path="url(#clipPath3520-6-4)" + id="g3546-7-5"><g + id="g3548-8-3"><g + id="g3550-3-8" /><g + mask="url(#mask3528-3-5)" + id="g3552-8-72"><g + transform="matrix(93,0,0,68,667,493)" + id="g3554-9-8"><image + width="1" + height="1" + transform="matrix(1,0,0,-1,0,1)" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAAP1JREFUeJzt3DGKhEAARcFWvP+VeyNBxJGFHX3BVmU2BvL4DBP1Muec48KyLFfH/NKHrGOMMbbzgdjfsXe8ir+dX+K7ruKv1cf8N8dRr+cDnmfpL9rHvVr5+yw9sIwxPv+h5BGWHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9JfNOUUvrHe3H/MMS3/RPvD1+MA7LP0lx2Fv50N3737X7aX155fE/5u7n+wfv04ph+lQnM8AAAAASUVORK5CYII=" + mask="url(#mask3540-4-88)" + id="image3556-9-3" /></g></g></g></g></g></g><g + style="display:inline" + id="g3558-6-1" + transform="matrix(5.09,0,0,-5.09,235.91496,860.85677)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,-1.65 -1.35,-3 -3,-3 l -74,0 c -1.649,0 -3,1.35 -3,3 l 0,50 c 0,1.65 1.351,3 3,3 l 74,0 c 1.65,0 3,-1.35 3,-3 L 0,0 z" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3560-5-6" /></g><g + style="display:inline" + id="g3562-4-0" + transform="matrix(5.09,0,0,-5.09,-3586.6755,3426.2166)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3564-6-3" /><g + id="g3574-7-9"><g + style="opacity:0.5" + clip-path="url(#clipPath3566-8-9)" + id="g3576-7-8"><g + id="g3578-2-9"><g + clip-path="url(#clipPath3570-6-4)" + id="g3580-1-9"><path + inkscape:connector-curvature="0" + d="m 710.994,535.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z" + style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3582-0-16" /></g></g></g></g></g><path + inkscape:connector-curvature="0" + d="m 123.93496,748.87677 -254.5,0 0,-25.45 254.5,0 0,25.45 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3584-1-9" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><path + inkscape:connector-curvature="0" + d="m 6.8649591,799.77677 -137.4299991,0 0,-25.45 137.4299991,0 0,25.45 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3586-5-0" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><g + style="display:inline" + id="g3588-5-0" + transform="matrix(5.09,0,0,-5.09,-3586.6755,3426.2166)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3590-3-9" /><g + id="g3596-7-2"><g + style="opacity:0" + clip-path="url(#clipPath3592-5-68)" + id="g3598-6-5"><path + inkscape:connector-curvature="0" + d="m 730.777,537 12,0 0,12 -12,0 0,-12 z" + style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3600-8-1" /></g></g></g><g + style="display:inline" + id="g3602-7-0" + transform="matrix(5.09,0,0,-5.09,188.97176,661.07427)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,0.414 -0.336,0.75 -0.75,0.75 l -2.75,0 -2.5,4 -1,0 1.25,-4 -2.75,0 -0.75,1 -0.75,0 0.5,-1.75 -0.5,-1.75 0.75,0 0.75,1 2.75,0 -1.25,-4 1,0 2.5,4 2.75,0 C -0.336,-0.75 0,-0.414 0,0" + style="fill:#00c853;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3604-3-8" /></g><g + transform="matrix(1.25,0,0,-1.25,-1884.887,1349.9021)" + id="g3012-8" + style="display:inline" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + transform="translate(1677.8121,922.30928)" + id="g3072-5" + style="fill:#333333;fill-opacity:1"><path + inkscape:connector-curvature="0" + d="m 0,0 -285.486,0 -14,-190.491 313.486,0 L 0,0 z" + id="path3074-5" + style="fill:#101010;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="translate(1691.8121,352.84148)" + id="g3076-9" + style="fill:#333333;fill-opacity:1"><path + inkscape:connector-curvature="0" + d="m 0,0 -313.486,0 14,-190.491 286.486,0 L 0,0 z" + id="path3078-3" + style="fill:#101010;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><path + inkscape:connector-curvature="0" + d="m 1721.07,355.32978 -374,0 0,374 374,0 0,-374 z m 3.332,409 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 0,-380 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 l 378.666,0 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 0,380 0,5.333 c 0,14.729 -11.939,26.667 -26.668,26.667" + id="path3080-4" + style="fill:#101010;fill-opacity:1;fill-rule:nonzero;stroke:none" /><g + transform="translate(290.06807,8.3297801)" + id="g3082-3"><g + id="g3084-9" /><g + id="g3090-2"><g + clip-path="url(#clipPath3086-4-0)" + id="g3092-8" + style="opacity:0.10000598"><path + inkscape:connector-curvature="0" + d="m 1432.002,722 -374,0 0,-374 374,0 0,374 z m -3,-371 -368,0 0,368 368,0 0,-368 z" + id="path3094-1" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g><g + transform="translate(290.06807,8.3297801)" + id="g3096-6"><g + id="g3098-6" /><g + id="g3104-5"><g + clip-path="url(#clipPath3100-8-2)" + id="g3106-9" + style="opacity:0.10000598"><g + transform="translate(1434.334,317.334)" + id="g3108-9"><path + inkscape:connector-curvature="0" + d="m 0,0 -378.666,0 c -14.729,0 -26.666,11.938 -26.666,26.666 l 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 L 0,-5.334 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 C 26.668,11.938 14.729,0 0,0" + id="path3110-8" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g + transform="translate(290.06807,8.3297801)" + id="g3112-1"><g + id="g3114-5" /><g + id="g3120-7"><g + clip-path="url(#clipPath3116-4-9)" + id="g3122-5" + style="opacity:0.10000598"><g + transform="translate(1434.334,756)" + id="g3124-1"><path + inkscape:connector-curvature="0" + d="m 0,0 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 c 0,14.728 11.937,26.667 26.666,26.667 L 0,-5.333 c 14.729,0 26.668,-11.939 26.668,-26.667 l 0,5.333 C 26.668,-11.938 14.729,0 0,0" + id="path3126-0" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g></g><g + inkscape:groupmode="layer" + id="layer7" + inkscape:label="Layer4" + style="display:inline" + transform="translate(436.0495,72.4457)"><g + style="display:inline" + id="g3622-5-8" + transform="matrix(5.2235991,0,0,-5.1937884,507.13047,984.15494)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c -32.947,0 -59.75,26.804 -59.75,59.75 0,32.946 26.803,59.75 59.75,59.75 32.945,0 59.75,-26.804 59.75,-59.75 C 59.75,26.804 32.945,0 0,0" + style="fill:#ff4a3c;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3624-3-9" /></g><g + style="display:inline" + id="g3630-4-7" + transform="matrix(5.2235991,0,0,-5.1937884,-2762.8426,3436.9216)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3632-0-4" + clip-path="url(#clipPath3634-8-0)"><g + id="g3638-2-4"><g + id="g3640-4-1" /><g + id="g3666-9-6"><g + style="opacity:0.119995" + clip-path="url(#clipPath3642-3-4)" + id="g3668-8-7"><g + id="g3670-0-5"><g + id="g3672-4-4" /><g + mask="url(#mask3650-5-0)" + id="g3674-2-0"><g + transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)" + id="g3676-6-2"><image + width="1" + height="1" + transform="matrix(1,0,0,-1,0,1)" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAAASdJREFUeJzt1rFuwyAUQFGw/P+/TIfKamQ5be7kRjlnshEDw9WDudZa48Kc82qZD/Eki7GfF4TCGD8dnMPZzxvg0Tmc7c7D8D6OcLbHH/iLCcPL5pxjjjGun8NwwYQhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDIlgSARDIhgSwZAIhkQwJIIhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDIlgSARDIhgSwZAIhkQwJIIhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDMm21rr7DLyJtZYJQ7ON8V0O/OZoxIQh2Y+Po6A5522H4f853z77sw3C+WzPnilfB04mnX6avLgAAAAASUVORK5CYII=" + mask="url(#mask3662-9-4)" + id="image3678-1-3" /></g></g></g></g></g></g><g + id="g3680-5-3" + transform="translate(689.7031,476.2588)"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,-1.642 -1.344,-2.984 -2.986,-2.984 l -121.434,0 c -1.643,0 -2.986,1.342 -2.986,2.984 l 0,60.719 c 0,1.641 1.343,2.985 2.986,2.985 l 121.434,0 C -1.344,63.704 0,62.36 0,60.719 L 0,0 z" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3682-6-2" /></g></g></g><g + id="layer3" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + transform="matrix(1.25,0,0,-1.25,715.58308,453.4259)" + id="g3024-4" + style="fill:#000000;display:inline"><path + inkscape:connector-curvature="0" + d="m 0,0 -12.195,205.05 -307.49,0 L -331.88,0 c 44.595,34.886 102.563,58.974 165.94,58.974 C -102.563,58.974 -44.595,34.886 0,0" + id="path3026-3" + style="fill:#2e2e2e;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,300.90228,894.5124)" + id="g3028-0" + style="fill:#000000;display:inline"><path + inkscape:connector-curvature="0" + d="m 0,0 12.06,-202.039 307.49,0 L 331.609,0 C 287.033,-34.822 229.119,-58.869 165.805,-58.869 102.491,-58.869 44.576,-34.822 0,0" + id="path3030-8" + style="fill:#2e2e2e;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,456.87948,388.9154)" + id="g3032-2" + style="display:inline"><path + inkscape:connector-curvature="0" + d="m 0,0 c 5.706,1.02 11.485,1.83 17.328,2.423 3.895,0.395 7.819,0.694 11.769,0.895 3.95,0.2 7.926,0.301 11.926,0.301 4,0 7.976,-0.101 11.926,-0.301 3.95,-0.201 7.874,-0.5 11.77,-0.895 C 70.561,1.83 76.341,1.02 82.047,0 c 108.425,-19.367 190.726,-114.139 190.726,-228.132 0,-127.991 -103.756,-231.75 -231.75,-231.75 -127.99,0 -231.751,103.759 -231.751,231.75 0,113.993 82.305,208.765 190.728,228.132 m 41.023,26.794 c -140.792,0 -254.926,-114.133 -254.926,-254.926 0,-140.792 114.134,-254.926 254.926,-254.926 140.79,0 254.926,114.134 254.926,254.926 0,140.793 -114.136,254.926 -254.926,254.926" + id="path3034-1" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,508.15818,355.4224)" + id="g3036-8" + style="fill:#000000;display:inline"><path + inkscape:connector-curvature="0" + d="m 0,0 c -140.792,0 -254.926,-114.134 -254.926,-254.926 0,-140.792 114.134,-254.926 254.926,-254.926 140.792,0 254.926,114.134 254.926,254.926 C 254.926,-114.134 140.792,0 0,0 m 231.75,-254.926 c 0,-127.991 -103.758,-231.75 -231.75,-231.75 -127.992,0 -231.75,103.759 -231.75,231.75 0,127.993 103.758,231.751 231.75,231.751 127.992,0 231.75,-103.758 231.75,-231.751" + id="path3038-3" + style="fill:#2c2c2c;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,-264.34372,1339.588)" + id="g3040-9" + style="display:inline"><g + id="g3042-1" /><g + id="g3048-2"><g + clip-path="url(#clipPath3044-8-3-2)" + id="g3050-4" + style="opacity:0.10000598"><g + transform="translate(844.249,532.4062)" + id="g3052-7"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,-124.952 -101.295,-226.248 -226.248,-226.248 -124.952,0 -226.247,101.296 -226.247,226.248 0,124.953 101.295,226.248 226.247,226.248 C -101.295,226.248 0,124.953 0,0" + id="path3054-5" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g + transform="matrix(1.25,0,0,-1.25,-264.34372,1339.588)" + id="g3056-2" + style="display:inline"><g + id="g3058-6" /><g + id="g3064-1"><g + clip-path="url(#clipPath3060-8-2-1)" + id="g3066-2" + style="opacity:0.10000598"><g + transform="translate(618.0015,787.7266)" + id="g3068-5"><path + inkscape:connector-curvature="0" + d="m 0,0 c -34.466,0 -67.903,-6.75 -99.383,-20.065 -30.404,-12.861 -57.707,-31.269 -81.155,-54.716 -23.446,-23.447 -41.856,-50.752 -54.715,-81.156 -13.314,-31.48 -20.066,-64.916 -20.066,-99.383 0,-34.465 6.752,-67.904 20.066,-99.381 12.859,-30.405 31.269,-57.709 54.715,-81.156 23.448,-23.447 50.751,-41.857 81.155,-54.715 31.48,-13.315 64.917,-20.066 99.383,-20.066 34.466,0 67.903,6.751 99.382,20.066 30.405,12.858 57.708,31.268 81.155,54.715 23.447,23.447 41.857,50.751 54.716,81.156 13.314,31.477 20.066,64.916 20.066,99.381 0,34.467 -6.752,67.903 -20.066,99.383 -12.859,30.404 -31.269,57.709 -54.716,81.156 -23.447,23.447 -50.75,41.855 -81.155,54.716 C 67.903,-6.75 34.466,0 0,0 m 0,-3.153 c 139.268,0 252.167,-112.897 252.167,-252.167 0,-139.267 -112.899,-252.166 -252.167,-252.166 -139.268,0 -252.167,112.899 -252.167,252.166 0,139.27 112.899,252.167 252.167,252.167" + id="path3070-2" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g><g + style="display:inline" + id="g3692-7-8" + transform="matrix(5.2956158,0,0,-5.2956158,-2815.7539,3491.418)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3694-5-3" /><g + id="g3704-5-3"><g + clip-path="url(#clipPath3696-9-7-9)" + id="g3706-2-5" + style="opacity:0.5"><g + id="g3708-6-9"><g + clip-path="url(#clipPath3700-1-1-8)" + id="g3710-3-0"><path + d="m 623.994,518.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z" + style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3712-4-5" + inkscape:connector-curvature="0" /></g></g></g></g></g><path + d="m 584.03152,795.94967 -264.78075,0 0,-26.47808 264.78075,0 0,26.47808 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3714-2-5" + inkscape:connector-curvature="0" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><path + d="m 462.23242,848.90583 -142.98165,0 0,-26.47808 142.98165,0 0,26.47808 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3716-3-1" + inkscape:connector-curvature="0" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><g + style="display:inline" + id="g3718-7-1" + transform="matrix(5.2956158,0,0,-5.2956158,-2815.7539,3491.418)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3720-1-0" /><g + id="g3730-8-4"><g + clip-path="url(#clipPath3722-1-6-1)" + id="g3732-8-4" + style="opacity:0"><g + id="g3734-9-2"><g + clip-path="url(#clipPath3726-6-9-4)" + id="g3736-3-3"><path + d="m 664.001,520 -12.001,0 0,12 12.001,0 0,-12 z" + style="fill:#ee2a7b;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3738-7-6" + inkscape:connector-curvature="0" /></g></g></g></g></g><g + style="display:inline" + id="g3740-9-7" + transform="matrix(5.2956158,0,0,-5.2956158,644.93112,705.35546)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + d="m 0,0 4.5,0 0,-4.501 0.501,0 4,9.001 L 0,0.501 0,0 z" + style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3742-8-7" + inkscape:connector-curvature="0" /></g></g><g + inkscape:groupmode="layer" + id="layer6" + inkscape:label="Layer3" + style="display:inline" + transform="translate(436.0495,72.4457)"><g + style="display:inline" + id="g3508-5-6" + transform="matrix(5.09,0,0,-5.09,742.55563,925.70096)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c -2.209,0 -4,1.791 -4,4 l 0,92 c 0,2.209 1.791,4 4,4 l 92,0 c 2.209,0 4,-1.791 4,-4 L 96,4 C 96,1.791 94.209,0 92,0 L 0,0 z" + style="fill:#9d65dc;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3510-0-8" /></g><g + style="display:inline" + id="g3516-7-9" + transform="matrix(5.09,0,0,-5.09,-2642.2948,3424.8908)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3518-2-7" /><g + id="g3544-9-6"><g + style="opacity:0.119995" + clip-path="url(#clipPath3520-6-0)" + id="g3546-7-3"><g + id="g3548-8-7"><g + id="g3550-3-6" /><g + mask="url(#mask3528-3-8)" + id="g3552-8-7"><g + transform="matrix(93,0,0,68,667,493)" + id="g3554-9-9"><image + width="1" + height="1" + transform="matrix(1,0,0,-1,0,1)" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAAP1JREFUeJzt3DGKhEAARcFWvP+VeyNBxJGFHX3BVmU2BvL4DBP1Muec48KyLFfH/NKHrGOMMbbzgdjfsXe8ir+dX+K7ruKv1cf8N8dRr+cDnmfpL9rHvVr5+yw9sIwxPv+h5BGWHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9JfNOUUvrHe3H/MMS3/RPvD1+MA7LP0lx2Fv50N3737X7aX155fE/5u7n+wfv04ph+lQnM8AAAAASUVORK5CYII=" + mask="url(#mask3540-4-8)" + id="image3556-9-8" /></g></g></g></g></g></g><g + style="display:inline" + id="g3558-6-7" + transform="matrix(5.09,0,0,-5.09,1180.2956,859.53096)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,-1.65 -1.35,-3 -3,-3 l -74,0 c -1.649,0 -3,1.35 -3,3 l 0,50 c 0,1.65 1.351,3 3,3 l 74,0 c 1.65,0 3,-1.35 3,-3 L 0,0 z" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3560-5-9" /></g><g + style="display:inline" + id="g3562-4-5" + transform="matrix(5.09,0,0,-5.09,-2642.2948,3424.8908)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3564-6-8" /><g + id="g3574-7-5"><g + style="opacity:0.5" + clip-path="url(#clipPath3566-8-1)" + id="g3576-7-7"><g + id="g3578-2-1"><g + clip-path="url(#clipPath3570-6-5)" + id="g3580-1-1"><path + inkscape:connector-curvature="0" + d="m 710.994,535.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z" + style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3582-0-1" /></g></g></g></g></g><path + inkscape:connector-curvature="0" + d="m 1068.3156,747.55096 -254.49997,0 0,-25.45 254.49997,0 0,25.45 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3584-1-4" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><path + inkscape:connector-curvature="0" + d="m 951.24563,798.45096 -137.43,0 0,-25.45 137.43,0 0,25.45 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3586-5-3" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><g + style="display:inline" + id="g3588-5-2" + transform="matrix(5.09,0,0,-5.09,-2642.2948,3424.8908)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3590-3-5" /><g + id="g3596-7-7"><g + style="opacity:0" + clip-path="url(#clipPath3592-5-6)" + id="g3598-6-3"><path + inkscape:connector-curvature="0" + d="m 730.777,537 12,0 0,12 -12,0 0,-12 z" + style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3600-8-8" /></g></g></g><g + style="display:inline" + id="g3602-7-1" + transform="matrix(5.09,0,0,-5.09,1133.3524,659.74846)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,0.414 -0.336,0.75 -0.75,0.75 l -2.75,0 -2.5,4 -1,0 1.25,-4 -2.75,0 -0.75,1 -0.75,0 0.5,-1.75 -0.5,-1.75 0.75,0 0.75,1 2.75,0 -1.25,-4 1,0 2.5,4 2.75,0 C -0.336,-0.75 0,-0.414 0,0" + style="fill:#00c853;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3604-3-1" /></g><g + id="layer2" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + transform="matrix(1.25,0,0,-1.25,1156.7381,197.1134)" + id="g3072-2" + style="fill:#4d4d4d;display:inline"><path + inkscape:connector-curvature="0" + d="m 0,0 -285.486,0 -14,-190.491 313.486,0 L 0,0 z" + id="path3074-4" + style="fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,1174.2381,908.94815)" + id="g3076-2" + style="fill:#333333;display:inline"><path + inkscape:connector-curvature="0" + d="m 0,0 -313.486,0 14,-190.491 286.486,0 L 0,0 z" + id="path3078-2" + style="fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><path + inkscape:connector-curvature="0" + d="m 1210.8105,905.83777 -467.50004,0 0,-467.5 467.50004,0 0,467.5 z m 4.165,-511.25 -473.33254,0 c -18.41125,0 -33.3325,14.92251 -33.3325,33.33376 l 0,6.66624 0,475 0,6.66751 c 0,18.40874 14.92125,33.33249 33.3325,33.33249 l 473.33254,0 c 18.4112,0 33.335,-14.92375 33.335,-33.33249 l 0,-6.66751 0,-475 0,-6.66624 c 0,-18.41125 -14.9238,-33.33376 -33.335,-33.33376" + id="path3080-8" + style="fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" /><g + transform="matrix(1.25,0,0,-1.25,-577.94194,1339.5878)" + id="g3082-6" + style="display:inline"><g + id="g3084-6" /><g + id="g3090-6"><g + clip-path="url(#clipPath3086-0-0-4)" + id="g3092-6" + style="opacity:0.10000598"><path + inkscape:connector-curvature="0" + d="m 1432.002,722 -374,0 0,-374 374,0 0,374 z m -3,-371 -368,0 0,368 368,0 0,-368 z" + id="path3094-4" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g><g + transform="matrix(1.25,0,0,-1.25,-577.94194,1339.5878)" + id="g3096-1" + style="display:inline"><g + id="g3098-7" /><g + id="g3104-3"><g + clip-path="url(#clipPath3100-0-7-1)" + id="g3106-8" + style="opacity:0.10000598"><g + transform="translate(1434.334,317.334)" + id="g3108-5"><path + inkscape:connector-curvature="0" + d="m 0,0 -378.666,0 c -14.729,0 -26.666,11.938 -26.666,26.666 l 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 L 0,-5.334 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 C 26.668,11.938 14.729,0 0,0" + id="path3110-7" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g + transform="matrix(1.25,0,0,-1.25,-577.94194,1339.5878)" + id="g3112-0" + style="display:inline"><g + id="g3114-4" /><g + id="g3120-4"><g + clip-path="url(#clipPath3116-3-2-9)" + id="g3122-9" + style="opacity:0.10000598"><g + transform="translate(1434.334,756)" + id="g3124-5"><path + inkscape:connector-curvature="0" + d="m 0,0 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 c 0,14.728 11.937,26.667 26.666,26.667 L 0,-5.333 c 14.729,0 26.668,-11.939 26.668,-26.667 l 0,5.333 C 26.668,-11.938 14.729,0 0,0" + id="path3126-3" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g></g><g + inkscape:groupmode="layer" + id="layer5" + inkscape:label="Layer2" + style="display:inline" + transform="translate(436.0495,72.4457)"><g + style="display:inline" + id="g3622-5" + transform="matrix(5.2235991,0,0,-5.1937884,1450.0328,987.05631)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c -32.947,0 -59.75,26.804 -59.75,59.75 0,32.946 26.803,59.75 59.75,59.75 32.945,0 59.75,-26.804 59.75,-59.75 C 59.75,26.804 32.945,0 0,0" + style="fill:#0bda2f;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3624-3" /></g><g + style="display:inline" + id="g3630-4" + transform="matrix(5.2235991,0,0,-5.1937884,-1819.9402,3439.8229)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3632-0" + clip-path="url(#clipPath3634-8)"><g + id="g3638-2"><g + id="g3640-4" /><g + id="g3666-9"><g + style="opacity:0.119995" + clip-path="url(#clipPath3642-3)" + id="g3668-8"><g + id="g3670-0"><g + id="g3672-4" /><g + mask="url(#mask3650-5)" + id="g3674-2"><g + transform="matrix(139.35082,0,0,78.633677,558.31445,465.31115)" + id="g3676-6"><image + width="1" + height="1" + transform="matrix(1,0,0,-1,0,1)" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIwAAABPCAYAAAA5vC0kAAAABHNCSVQICAgIfAhkiAAAASdJREFUeJzt1rFuwyAUQFGw/P+/TIfKamQ5be7kRjlnshEDw9WDudZa48Kc82qZD/Eki7GfF4TCGD8dnMPZzxvg0Tmc7c7D8D6OcLbHH/iLCcPL5pxjjjGun8NwwYQhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDIlgSARDIhgSwZAIhkQwJIIhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDIlgSARDIhgSwZAIhkQwJIIhEQyJYEgEQyIYEsGQCIZEMCSCIREMiWBIBEMiGBLBkAiGRDAkgiERDMm21rr7DLyJtZYJQ7ON8V0O/OZoxIQh2Y+Po6A5522H4f853z77sw3C+WzPnilfB04mnX6avLgAAAAASUVORK5CYII=" + mask="url(#mask3662-9)" + id="image3678-1" /></g></g></g></g></g></g><g + id="g3680-5" + transform="translate(689.7031,476.2588)"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,-1.642 -1.344,-2.984 -2.986,-2.984 l -121.434,0 c -1.643,0 -2.986,1.342 -2.986,2.984 l 0,60.719 c 0,1.641 1.343,2.985 2.986,2.985 l 121.434,0 C -1.344,63.704 0,62.36 0,60.719 L 0,0 z" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3682-6" /></g></g></g><g + transform="translate(2e-5,-3e-5)" + id="layer1" + style="display:inline" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + transform="matrix(1.25,0,0,-1.25,1656.802,453.73263)" + id="g3024" + style="fill:#000000"><path + inkscape:connector-curvature="0" + d="m 0,0 -12.195,205.05 -307.49,0 L -331.88,0 c 44.595,34.886 102.563,58.974 165.94,58.974 C -102.563,58.974 -44.595,34.886 0,0" + id="path3026" + style="fill:#606060;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,1242.1212,894.81914)" + id="g3028" + style="fill:#000000"><path + inkscape:connector-curvature="0" + d="m 0,0 12.06,-202.039 307.49,0 L 331.609,0 C 287.033,-34.822 229.119,-58.869 165.805,-58.869 102.491,-58.869 44.576,-34.822 0,0" + id="path3030" + style="fill:#606060;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,1398.0984,389.22214)" + id="g3032"><path + inkscape:connector-curvature="0" + d="m 0,0 c 5.706,1.02 11.485,1.83 17.328,2.423 3.895,0.395 7.819,0.694 11.769,0.895 3.95,0.2 7.926,0.301 11.926,0.301 4,0 7.976,-0.101 11.926,-0.301 3.95,-0.201 7.874,-0.5 11.77,-0.895 C 70.561,1.83 76.341,1.02 82.047,0 c 108.425,-19.367 190.726,-114.139 190.726,-228.132 0,-127.991 -103.756,-231.75 -231.75,-231.75 -127.99,0 -231.751,103.759 -231.751,231.75 0,113.993 82.305,208.765 190.728,228.132 m 41.023,26.794 c -140.792,0 -254.926,-114.133 -254.926,-254.926 0,-140.792 114.134,-254.926 254.926,-254.926 140.79,0 254.926,114.134 254.926,254.926 0,140.793 -114.136,254.926 -254.926,254.926" + id="path3034" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,1449.3771,355.72914)" + id="g3036" + style="fill:#000000"><path + inkscape:connector-curvature="0" + d="m 0,0 c -140.792,0 -254.926,-114.134 -254.926,-254.926 0,-140.792 114.134,-254.926 254.926,-254.926 140.792,0 254.926,114.134 254.926,254.926 C 254.926,-114.134 140.792,0 0,0 m 231.75,-254.926 c 0,-127.991 -103.758,-231.75 -231.75,-231.75 -127.992,0 -231.75,103.759 -231.75,231.75 0,127.993 103.758,231.751 231.75,231.751 127.992,0 231.75,-103.758 231.75,-231.751" + id="path3038" + style="fill:#606060;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="matrix(1.25,0,0,-1.25,676.87523,1339.8947)" + id="g3040"><g + id="g3042" /><g + id="g3048"><g + clip-path="url(#clipPath3044-8-1)" + id="g3050" + style="opacity:0.10000598"><g + transform="translate(844.249,532.4062)" + id="g3052"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,-124.952 -101.295,-226.248 -226.248,-226.248 -124.952,0 -226.247,101.296 -226.247,226.248 0,124.953 101.295,226.248 226.247,226.248 C -101.295,226.248 0,124.953 0,0" + id="path3054" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g + transform="matrix(1.25,0,0,-1.25,676.87523,1339.8947)" + id="g3056"><g + id="g3058" /><g + id="g3064"><g + clip-path="url(#clipPath3060-8-27)" + id="g3066" + style="opacity:0.10000598"><g + transform="translate(618.0015,787.7266)" + id="g3068"><path + inkscape:connector-curvature="0" + d="m 0,0 c -34.466,0 -67.903,-6.75 -99.383,-20.065 -30.404,-12.861 -57.707,-31.269 -81.155,-54.716 -23.446,-23.447 -41.856,-50.752 -54.715,-81.156 -13.314,-31.48 -20.066,-64.916 -20.066,-99.383 0,-34.465 6.752,-67.904 20.066,-99.381 12.859,-30.405 31.269,-57.709 54.715,-81.156 23.448,-23.447 50.751,-41.857 81.155,-54.715 31.48,-13.315 64.917,-20.066 99.383,-20.066 34.466,0 67.903,6.751 99.382,20.066 30.405,12.858 57.708,31.268 81.155,54.715 23.447,23.447 41.857,50.751 54.716,81.156 13.314,31.477 20.066,64.916 20.066,99.381 0,34.467 -6.752,67.903 -20.066,99.383 -12.859,30.404 -31.269,57.709 -54.716,81.156 -23.447,23.447 -50.75,41.855 -81.155,54.716 C 67.903,-6.75 34.466,0 0,0 m 0,-3.153 c 139.268,0 252.167,-112.897 252.167,-252.167 0,-139.267 -112.899,-252.166 -252.167,-252.166 -139.268,0 -252.167,112.899 -252.167,252.166 0,139.27 112.899,252.167 252.167,252.167" + id="path3070" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g><g + style="display:inline" + id="g3692-7" + transform="matrix(5.2956158,0,0,-5.2956158,-1870.725,3488.2105)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3694-5" /><g + id="g3704-5"><g + clip-path="url(#clipPath3696-9-7)" + id="g3706-2" + style="opacity:0.5"><g + id="g3708-6"><g + clip-path="url(#clipPath3700-1-1)" + id="g3710-3"><path + d="m 623.994,518.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z" + style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3712-4" + inkscape:connector-curvature="0" /></g></g></g></g></g><path + d="m 1529.0604,792.7421 -264.7808,0 0,-26.47808 264.7808,0 0,26.47808 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3714-2" + inkscape:connector-curvature="0" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><path + d="m 1407.2613,845.69826 -142.9817,0 0,-26.47808 142.9817,0 0,26.47808 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3716-3" + inkscape:connector-curvature="0" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><g + style="display:inline" + id="g3718-7" + transform="matrix(5.2956158,0,0,-5.2956158,-1870.725,3488.2105)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3720-1" /><g + id="g3730-8"><g + clip-path="url(#clipPath3722-1-6)" + id="g3732-8" + style="opacity:0"><g + id="g3734-9"><g + clip-path="url(#clipPath3726-6-9)" + id="g3736-3"><path + d="m 664.001,520 -12.001,0 0,12 12.001,0 0,-12 z" + style="fill:#ee2a7b;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3738-7" + inkscape:connector-curvature="0" /></g></g></g></g></g><g + style="display:inline" + id="g3740-9" + transform="matrix(5.2956158,0,0,-5.2956158,1589.96,702.14789)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + d="m 0,0 4.5,0 0,-4.501 0.501,0 4,9.001 L 0,0.501 0,0 z" + style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3742-8" + inkscape:connector-curvature="0" /></g></g><g + inkscape:groupmode="layer" + id="layer4" + inkscape:label="Layer1" + style="display:inline" + transform="translate(436.0495,72.4457)"><g + style="display:inline" + id="g3508-5" + transform="matrix(5.09,0,0,-5.09,1683.0619,927.12472)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c -2.209,0 -4,1.791 -4,4 l 0,92 c 0,2.209 1.791,4 4,4 l 92,0 c 2.209,0 4,-1.791 4,-4 L 96,4 C 96,1.791 94.209,0 92,0 L 0,0 z" + style="fill:#ffed0d;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3510-0" /></g><g + style="display:inline" + id="g3516-7" + transform="matrix(5.09,0,0,-5.09,-1701.7885,3426.3146)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3518-2" /><g + id="g3544-9"><g + style="opacity:0.119995" + clip-path="url(#clipPath3520-6)" + id="g3546-7"><g + id="g3548-8"><g + id="g3550-3" /><g + mask="url(#mask3528-3)" + id="g3552-8"><g + transform="matrix(93,0,0,68,667,493)" + id="g3554-9"><image + width="1" + height="1" + transform="matrix(1,0,0,-1,0,1)" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAF0AAABECAYAAADjqDmQAAAABHNCSVQICAgIfAhkiAAAAP1JREFUeJzt3DGKhEAARcFWvP+VeyNBxJGFHX3BVmU2BvL4DBP1Muec48KyLFfH/NKHrGOMMbbzgdjfsXe8ir+dX+K7ruKv1cf8N8dRr+cDnmfpL9rHvVr5+yw9sIwxPv+h5BGWHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9IDoAdEDogdED4geED0gekD0gOgB0QOiB0QPiB4QPSB6QPSA6AHRA6IHRA+IHhA9IHpA9JfNOUUvrHe3H/MMS3/RPvD1+MA7LP0lx2Fv50N3737X7aX155fE/5u7n+wfv04ph+lQnM8AAAAASUVORK5CYII=" + mask="url(#mask3540-4)" + id="image3556-9" /></g></g></g></g></g></g><g + style="display:inline" + id="g3558-6" + transform="matrix(5.09,0,0,-5.09,2120.8019,860.95472)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,-1.65 -1.35,-3 -3,-3 l -74,0 c -1.649,0 -3,1.35 -3,3 l 0,50 c 0,1.65 1.351,3 3,3 l 74,0 c 1.65,0 3,-1.35 3,-3 L 0,0 z" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3560-5" /></g><g + style="display:inline" + id="g3562-4" + transform="matrix(5.09,0,0,-5.09,-1701.7885,3426.3146)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3564-6" /><g + id="g3574-7"><g + style="opacity:0.5" + clip-path="url(#clipPath3566-8)" + id="g3576-7"><g + id="g3578-2"><g + clip-path="url(#clipPath3570-6)" + id="g3580-1"><path + inkscape:connector-curvature="0" + d="m 710.994,535.863 -31.988,0 0,12.002 31.988,0 0,-12.002 z" + style="fill:#6d6e71;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3582-0" /></g></g></g></g></g><path + inkscape:connector-curvature="0" + d="m 2008.8219,748.97472 -254.5,0 0,-25.45 254.5,0 0,25.45 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3584-1" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><path + inkscape:connector-curvature="0" + d="m 1891.7519,799.87472 -137.43,0 0,-25.45 137.43,0 0,25.45 z" + style="fill:#d1d2d3;fill-opacity:1;fill-rule:nonzero;stroke:none;display:inline" + id="path3586-5" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" /><g + style="display:inline" + id="g3588-5" + transform="matrix(5.09,0,0,-5.09,-1701.7885,3426.3146)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><g + id="g3590-3" /><g + id="g3596-7"><g + style="opacity:0" + clip-path="url(#clipPath3592-5)" + id="g3598-6"><path + inkscape:connector-curvature="0" + d="m 730.777,537 12,0 0,12 -12,0 0,-12 z" + style="fill:#03a9f4;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3600-8" /></g></g></g><g + style="display:inline" + id="g3602-7" + transform="matrix(5.09,0,0,-5.09,2073.8587,661.17222)" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999"><path + inkscape:connector-curvature="0" + d="m 0,0 c 0,0.414 -0.336,0.75 -0.75,0.75 l -2.75,0 -2.5,4 -1,0 1.25,-4 -2.75,0 -0.75,1 -0.75,0 0.5,-1.75 -0.5,-1.75 0.75,0 0.75,1 2.75,0 -1.25,-4 1,0 2.5,4 2.75,0 C -0.336,-0.75 0,-0.414 0,0" + style="fill:#00c853;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3604-3" /></g><g + transform="matrix(1.25,0,0,-1.25,0,1350)" + id="g3012" + style="display:inline" + inkscape:export-xdpi="18.559999" + inkscape:export-ydpi="18.559999" + inkscape:export-filename="C:\Users\Joe Fernandez\Downloads\Android Wear Artwork\g3014.png"><g + transform="translate(1677.8121,922.30928)" + id="g3072" + style="fill:#333333;fill-opacity:1"><path + inkscape:connector-curvature="0" + d="m 0,0 -285.486,0 -14,-190.491 313.486,0 L 0,0 z" + id="path3074" + style="fill:#747474;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><g + transform="translate(1691.8121,352.84148)" + id="g3076" + style="fill:#333333;fill-opacity:1"><path + inkscape:connector-curvature="0" + d="m 0,0 -313.486,0 14,-190.491 286.486,0 L 0,0 z" + id="path3078" + style="fill:#747474;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g><path + inkscape:connector-curvature="0" + d="m 1721.07,355.32978 -374,0 0,374 374,0 0,-374 z m 3.332,409 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 0,-380 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 l 378.666,0 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 0,380 0,5.333 c 0,14.729 -11.939,26.667 -26.668,26.667" + id="path3080" + style="fill:#747474;fill-opacity:1;fill-rule:nonzero;stroke:none" /><g + transform="translate(290.06807,8.3297801)" + id="g3082"><g + id="g3084" /><g + id="g3090"><g + clip-path="url(#clipPath3086-4)" + id="g3092" + style="opacity:0.10000598"><path + inkscape:connector-curvature="0" + d="m 1432.002,722 -374,0 0,-374 374,0 0,374 z m -3,-371 -368,0 0,368 368,0 0,-368 z" + id="path3094" + style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g><g + transform="translate(290.06807,8.3297801)" + id="g3096"><g + id="g3098" /><g + id="g3104"><g + clip-path="url(#clipPath3100-8)" + id="g3106" + style="opacity:0.10000598"><g + transform="translate(1434.334,317.334)" + id="g3108"><path + inkscape:connector-curvature="0" + d="m 0,0 -378.666,0 c -14.729,0 -26.666,11.938 -26.666,26.666 l 0,-5.334 c 0,-14.727 11.937,-26.666 26.666,-26.666 L 0,-5.334 c 14.729,0 26.668,11.939 26.668,26.666 l 0,5.334 C 26.668,11.938 14.729,0 0,0" + id="path3110" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g><g + transform="translate(290.06807,8.3297801)" + id="g3112"><g + id="g3114" /><g + id="g3120"><g + clip-path="url(#clipPath3116-4)" + id="g3122" + style="opacity:0.10000598"><g + transform="translate(1434.334,756)" + id="g3124"><path + inkscape:connector-curvature="0" + d="m 0,0 -378.666,0 c -14.729,0 -26.666,-11.938 -26.666,-26.667 l 0,-5.333 c 0,14.728 11.937,26.667 26.666,26.667 L 0,-5.333 c 14.729,0 26.668,-11.939 26.668,-26.667 l 0,5.333 C 26.668,-11.938 14.729,0 0,0" + id="path3126" + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none" /></g></g></g></g></g><g + id="g3744" + transform="matrix(1.25,0,0,-1.25,-298.02174,762.5543)"><g + id="g3746" /><g + id="g3752"><g + clip-path="url(#clipPath3748-6)" + id="g3754" + style="opacity:0"><path + d="m 1484,446 -270,0 0,182 270,0 0,-182 z" + style="fill:#ec008c;fill-opacity:1;fill-rule:nonzero;stroke:none" + id="path3756" + inkscape:connector-curvature="0" /></g></g></g><g + id="g3758" + transform="matrix(1.25,0,0,-1.25,1378.2283,155.0543)" /><g + id="g3762" + transform="matrix(1.25,0,0,-1.25,1539.4783,28.8043)" /></g></svg>
\ No newline at end of file diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java index 9fb3fb4..c2e93a7 100644 --- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java @@ -313,6 +313,26 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } } + @Override + public void applyTheme(Theme t) { + super.applyTheme(t); + + final AnimatedRotateState state = mState; + if (state == null) { + return; + } + + if (state.mDrawable != null) { + state.mDrawable.applyTheme(t); + } + } + + @Override + public boolean canApplyTheme() { + final AnimatedRotateState state = mState; + return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme(); + } + public void setFramesCount(int framesCount) { mState.mFramesCount = framesCount; mIncrement = 360.0f / mState.mFramesCount; @@ -331,6 +351,15 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mState.mDrawable.clearMutated(); + mMutated = false; + } + final static class AnimatedRotateState extends Drawable.ConstantState { Drawable mDrawable; diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java index cb09bbf..849faec 100644 --- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java @@ -139,27 +139,15 @@ public class AnimatedStateListDrawable extends StateListDrawable { @Override protected boolean onStateChange(int[] stateSet) { - final int keyframeIndex = mState.indexOfKeyframe(stateSet); - if (keyframeIndex == getCurrentIndex()) { - // Propagate state change to current keyframe. - final Drawable current = getCurrent(); - if (current != null) { - return current.setState(stateSet); - } - return false; - } - - // Attempt to find a valid transition to the keyframe. - if (selectTransition(keyframeIndex)) { - return true; - } - - // No valid transition, attempt to jump directly to the keyframe. - if (selectDrawable(keyframeIndex)) { - return true; - } - - return super.onStateChange(stateSet); + // If we're not already at the target index, either attempt to find a + // valid transition to it or jump directly there. + final int targetIndex = mState.indexOfKeyframe(stateSet); + final boolean changedIndex = targetIndex != getCurrentIndex() + && (selectTransition(targetIndex) || selectDrawable(targetIndex)); + + // Always call super.onStateChanged() to propagate the state change to + // the current drawable. + return super.onStateChange(stateSet) || changedIndex; } private boolean selectTransition(int toIndex) { @@ -507,6 +495,14 @@ public class AnimatedStateListDrawable extends StateListDrawable { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + static class AnimatedStateListState extends StateListState { private static final int REVERSE_SHIFT = 32; private static final int REVERSE_MASK = 0x1; diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index ad0b415..a904067 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -16,7 +16,6 @@ package android.graphics.drawable; import android.animation.Animator; import android.animation.AnimatorInflater; -import android.animation.ValueAnimator; import android.annotation.NonNull; import android.content.res.ColorStateList; import android.content.res.Resources; @@ -137,15 +136,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { private boolean mMutated; public AnimatedVectorDrawable() { - mAnimatedVectorState = new AnimatedVectorDrawableState(null); + this(null, null); } - private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res, - Theme theme) { - mAnimatedVectorState = new AnimatedVectorDrawableState(state); - if (theme != null && canApplyTheme()) { - applyTheme(theme); - } + private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res) { + mAnimatedVectorState = new AnimatedVectorDrawableState(state, mCallback, res); } @Override @@ -157,6 +152,15 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mAnimatedVectorState.mVectorDrawable.clearMutated(); + mMutated = false; + } + @Override public ConstantState getConstantState() { mAnimatedVectorState.mChangingConfigurations = getChangingConfigurations(); @@ -281,7 +285,11 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { VectorDrawable vectorDrawable = (VectorDrawable) res.getDrawable( drawableRes, theme).mutate(); vectorDrawable.setAllowCaching(false); + vectorDrawable.setCallback(mCallback); pathErrorScale = vectorDrawable.getPixelSize(); + if (mAnimatedVectorState.mVectorDrawable != null) { + mAnimatedVectorState.mVectorDrawable.setCallback(null); + } mAnimatedVectorState.mVectorDrawable = vectorDrawable; } a.recycle(); @@ -329,14 +337,22 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { ArrayList<Animator> mAnimators; ArrayMap<Animator, String> mTargetNameMap; - public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) { + public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy, + Callback owner, Resources res) { if (copy != null) { mChangingConfigurations = copy.mChangingConfigurations; if (copy.mVectorDrawable != null) { - mVectorDrawable = (VectorDrawable) copy.mVectorDrawable.getConstantState().newDrawable(); - mVectorDrawable.mutate(); - mVectorDrawable.setAllowCaching(false); + final ConstantState cs = copy.mVectorDrawable.getConstantState(); + if (res != null) { + mVectorDrawable = (VectorDrawable) cs.newDrawable(res); + } else { + mVectorDrawable = (VectorDrawable) cs.newDrawable(); + } + mVectorDrawable = (VectorDrawable) mVectorDrawable.mutate(); + mVectorDrawable.setCallback(owner); + mVectorDrawable.setLayoutDirection(copy.mVectorDrawable.getLayoutDirection()); mVectorDrawable.setBounds(copy.mVectorDrawable.getBounds()); + mVectorDrawable.setAllowCaching(false); } if (copy.mAnimators != null) { final int numAnimators = copy.mAnimators.size(); @@ -359,17 +375,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { @Override public Drawable newDrawable() { - return new AnimatedVectorDrawable(this, null, null); + return new AnimatedVectorDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { - return new AnimatedVectorDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new AnimatedVectorDrawable(this, res, theme); + return new AnimatedVectorDrawable(this, res); } @Override @@ -473,4 +484,21 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { } return true; } + + private final Callback mCallback = new Callback() { + @Override + public void invalidateDrawable(Drawable who) { + invalidateSelf(); + } + + @Override + public void scheduleDrawable(Drawable who, Runnable what, long when) { + scheduleSelf(what, when); + } + + @Override + public void unscheduleDrawable(Drawable who, Runnable what) { + unscheduleSelf(what); + } + }; } diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java index 9a9fd82..c730a20 100644 --- a/graphics/java/android/graphics/drawable/AnimationDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java @@ -347,6 +347,14 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + private final static class AnimationState extends DrawableContainerState { private int[] mDurations; private boolean mOneShot; diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index cf6be48..79ac651 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -132,7 +132,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(Bitmap bitmap) { - this(new BitmapState(bitmap), null, null); + this(new BitmapState(bitmap), null); } /** @@ -140,7 +140,7 @@ public class BitmapDrawable extends Drawable { * the display metrics of the resources. */ public BitmapDrawable(Resources res, Bitmap bitmap) { - this(new BitmapState(bitmap), res, null); + this(new BitmapState(bitmap), res); mBitmapState.mTargetDensity = mTargetDensity; } @@ -151,7 +151,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(String filepath) { - this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null); + this(new BitmapState(BitmapFactory.decodeFile(filepath)), null); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath); } @@ -162,7 +162,7 @@ public class BitmapDrawable extends Drawable { */ @SuppressWarnings("unused") public BitmapDrawable(Resources res, String filepath) { - this(new BitmapState(BitmapFactory.decodeFile(filepath)), null, null); + this(new BitmapState(BitmapFactory.decodeFile(filepath)), null); mBitmapState.mTargetDensity = mTargetDensity; if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + filepath); @@ -176,7 +176,7 @@ public class BitmapDrawable extends Drawable { */ @Deprecated public BitmapDrawable(java.io.InputStream is) { - this(new BitmapState(BitmapFactory.decodeStream(is)), null, null); + this(new BitmapState(BitmapFactory.decodeStream(is)), null); if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is); } @@ -187,7 +187,7 @@ public class BitmapDrawable extends Drawable { */ @SuppressWarnings("unused") public BitmapDrawable(Resources res, java.io.InputStream is) { - this(new BitmapState(BitmapFactory.decodeStream(is)), null, null); + this(new BitmapState(BitmapFactory.decodeStream(is)), null); mBitmapState.mTargetDensity = mTargetDensity; if (mBitmapState.mBitmap == null) { android.util.Log.w("BitmapDrawable", "BitmapDrawable cannot decode " + is); @@ -684,6 +684,14 @@ public class BitmapDrawable extends Drawable { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + @Override protected boolean onStateChange(int[] stateSet) { final BitmapState state = mBitmapState; @@ -911,17 +919,12 @@ public class BitmapDrawable extends Drawable { @Override public Drawable newDrawable() { - return new BitmapDrawable(this, null, null); + return new BitmapDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { - return new BitmapDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new BitmapDrawable(this, res, theme); + return new BitmapDrawable(this, res); } @Override @@ -934,16 +937,10 @@ public class BitmapDrawable extends Drawable { * The one constructor to rule them all. This is called by all public * constructors to set the state and initialize local properties. */ - private BitmapDrawable(BitmapState state, Resources res, Theme theme) { - if (theme != null && state.canApplyTheme()) { - // If we need to apply a theme, implicitly mutate. - mBitmapState = new BitmapState(state); - applyTheme(theme); - } else { - mBitmapState = state; - } + private BitmapDrawable(BitmapState state, Resources res) { + mBitmapState = state; - initializeWithState(state, res); + initializeWithState(mBitmapState, res); } /** diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index 40711cf..669cef2 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -55,6 +55,8 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { public static final int HORIZONTAL = 1; public static final int VERTICAL = 2; + private boolean mMutated; + ClipDrawable() { this(null, null); } @@ -112,6 +114,26 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { dr.setCallback(this); } + @Override + public void applyTheme(Theme t) { + super.applyTheme(t); + + final ClipState state = mClipState; + if (state == null) { + return; + } + + if (state.mDrawable != null) { + state.mDrawable.applyTheme(t); + } + } + + @Override + public boolean canApplyTheme() { + final ClipState state = mClipState; + return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme(); + } + // overrides from Drawable.Callback @Override @@ -268,6 +290,24 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { super.setLayoutDirection(layoutDirection); } + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mClipState.mDrawable.mutate(); + mMutated = true; + } + return this; + } + + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mClipState.mDrawable.clearMutated(); + mMutated = false; + } + final static class ClipState extends ConstantState { Drawable mDrawable; int mChangingConfigurations; diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index 1253c46..0f0c844 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -88,6 +88,14 @@ public class ColorDrawable extends Drawable { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + @Override public void draw(Canvas canvas) { final ColorFilter colorFilter = mPaint.getColorFilter(); @@ -291,17 +299,12 @@ public class ColorDrawable extends Drawable { @Override public Drawable newDrawable() { - return new ColorDrawable(this, null, null); + return new ColorDrawable(this); } @Override public Drawable newDrawable(Resources res) { - return new ColorDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new ColorDrawable(this, res, theme); + return new ColorDrawable(this); } @Override @@ -310,14 +313,8 @@ public class ColorDrawable extends Drawable { } } - private ColorDrawable(ColorState state, Resources res, Theme theme) { - if (theme != null && state.canApplyTheme()) { - mColorState = new ColorState(state); - applyTheme(theme); - } else { - mColorState = state; - } - + private ColorDrawable(ColorState state) { + mColorState = state; mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 9ae788c..1fac5b6 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -917,6 +917,20 @@ public abstract class Drawable { } /** + * Clears the mutated state, allowing this drawable to be cached and + * mutated again. + * <p> + * This is hidden because only framework drawables can be cached, so + * custom drawables don't need to support constant state, mutate(), or + * clearMutated(). + * + * @hide + */ + public void clearMutated() { + // Default implementation is no-op. + } + + /** * Create a drawable from an inputstream */ public static Drawable createFromStream(InputStream is, String srcName) { @@ -1044,54 +1058,72 @@ public abstract class Drawable { final Drawable drawable; final String name = parser.getName(); - if (name.equals("selector")) { - drawable = new StateListDrawable(); - } else if (name.equals("animated-selector")) { - drawable = new AnimatedStateListDrawable(); - } else if (name.equals("level-list")) { - drawable = new LevelListDrawable(); - } else if (name.equals("layer-list")) { - drawable = new LayerDrawable(); - } else if (name.equals("transition")) { - drawable = new TransitionDrawable(); - } else if (name.equals("ripple")) { - drawable = new RippleDrawable(); - } else if (name.equals("color")) { - drawable = new ColorDrawable(); - } else if (name.equals("shape")) { - drawable = new GradientDrawable(); - } else if (name.equals("vector")) { - drawable = new VectorDrawable(); - } else if (name.equals("animated-vector")) { - drawable = new AnimatedVectorDrawable(); - } else if (name.equals("scale")) { - drawable = new ScaleDrawable(); - } else if (name.equals("clip")) { - drawable = new ClipDrawable(); - } else if (name.equals("rotate")) { - drawable = new RotateDrawable(); - } else if (name.equals("animated-rotate")) { - drawable = new AnimatedRotateDrawable(); - } else if (name.equals("animation-list")) { - drawable = new AnimationDrawable(); - } else if (name.equals("inset")) { - drawable = new InsetDrawable(); - } else if (name.equals("bitmap")) { - //noinspection deprecation - drawable = new BitmapDrawable(r); - if (r != null) { - ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); - } - } else if (name.equals("nine-patch")) { - drawable = new NinePatchDrawable(); - if (r != null) { - ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); - } - } else { - throw new XmlPullParserException(parser.getPositionDescription() + - ": invalid drawable tag " + name); - } + switch (name) { + case "selector": + drawable = new StateListDrawable(); + break; + case "animated-selector": + drawable = new AnimatedStateListDrawable(); + break; + case "level-list": + drawable = new LevelListDrawable(); + break; + case "layer-list": + drawable = new LayerDrawable(); + break; + case "transition": + drawable = new TransitionDrawable(); + break; + case "ripple": + drawable = new RippleDrawable(); + break; + case "color": + drawable = new ColorDrawable(); + break; + case "shape": + drawable = new GradientDrawable(); + break; + case "vector": + drawable = new VectorDrawable(); + break; + case "animated-vector": + drawable = new AnimatedVectorDrawable(); + break; + case "scale": + drawable = new ScaleDrawable(); + break; + case "clip": + drawable = new ClipDrawable(); + break; + case "rotate": + drawable = new RotateDrawable(); + break; + case "animated-rotate": + drawable = new AnimatedRotateDrawable(); + break; + case "animation-list": + drawable = new AnimationDrawable(); + break; + case "inset": + drawable = new InsetDrawable(); + break; + case "bitmap": + drawable = new BitmapDrawable(r); + if (r != null) { + ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); + } + break; + case "nine-patch": + drawable = new NinePatchDrawable(); + if (r != null) { + ((NinePatchDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); + } + break; + default: + throw new XmlPullParserException(parser.getPositionDescription() + + ": invalid drawable tag " + name); + } drawable.inflate(r, parser, attrs, theme); return drawable; } @@ -1202,7 +1234,7 @@ public abstract class Drawable { * implemented for drawables that can have a theme applied. */ public Drawable newDrawable(Resources res, Theme theme) { - return newDrawable(); + return newDrawable(null); } /** diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 4a719fe..a903288 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -574,6 +574,15 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mDrawableContainerState.clearMutated(); + mMutated = false; + } + + /** * A ConstantState that can contain several {@link Drawable}s. * * This class was made public to enable testing, and its visibility may change in a future @@ -583,8 +592,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { final DrawableContainer mOwner; final Resources mRes; - Theme mTheme; - SparseArray<ConstantStateFuture> mDrawableFutures; int mChangingConfigurations; @@ -792,17 +799,17 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } final void applyTheme(Theme theme) { - // No need to call createAllFutures, since future drawables will - // apply the theme when they are prepared. - final int N = mNumChildren; - final Drawable[] drawables = mDrawables; - for (int i = 0; i < N; i++) { - if (drawables[i] != null) { - drawables[i].applyTheme(theme); + if (theme != null) { + createAllFutures(); + + final int N = mNumChildren; + final Drawable[] drawables = mDrawables; + for (int i = 0; i < N; i++) { + if (drawables[i] != null && drawables[i].canApplyTheme()) { + drawables[i].applyTheme(theme); + } } } - - mTheme = theme; } @Override @@ -840,6 +847,18 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mMutated = true; } + final void clearMutated() { + final int N = mNumChildren; + final Drawable[] drawables = mDrawables; + for (int i = 0; i < N; i++) { + if (drawables[i] != null) { + drawables[i].clearMutated(); + } + } + + mMutated = false; + } + /** * A boolean value indicating whether to use the maximum padding value * of all frames in the set (false), or to use the padding value of the @@ -1047,10 +1066,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { final Drawable result; if (state.mRes == null) { result = mConstantState.newDrawable(); - } else if (state.mTheme == null) { - result = mConstantState.newDrawable(state.mRes); } else { - result = mConstantState.newDrawable(state.mRes, state.mTheme); + result = mConstantState.newDrawable(state.mRes); } result.setLayoutDirection(state.mLayoutDirection); result.setCallback(state.mOwner); diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 3092f96..2071cf7 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -29,6 +29,8 @@ import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Path; import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; import android.graphics.RadialGradient; import android.graphics.Rect; import android.graphics.RectF; @@ -134,6 +136,7 @@ public class GradientDrawable extends Drawable { private Rect mPadding; private Paint mStrokePaint; // optional, set by the caller private ColorFilter mColorFilter; // optional, set by the caller + private PorterDuffColorFilter mTintFilter; private int mAlpha = 0xFF; // modified by the caller private final Path mPath = new Path(); @@ -171,7 +174,7 @@ public class GradientDrawable extends Drawable { } public GradientDrawable() { - this(new GradientState(Orientation.TOP_BOTTOM, null), null); + this(new GradientState(Orientation.TOP_BOTTOM, null)); } /** @@ -179,7 +182,7 @@ public class GradientDrawable extends Drawable { * of colors for the gradient. */ public GradientDrawable(Orientation orientation, int[] colors) { - this(new GradientState(orientation, colors), null); + this(new GradientState(orientation, colors)); } @Override @@ -523,13 +526,15 @@ public class GradientDrawable extends Drawable { mStrokePaint.getStrokeWidth() > 0; final boolean haveFill = currFillAlpha > 0; final GradientState st = mGradientState; + final ColorFilter colorFilter = mColorFilter != null ? mColorFilter : mTintFilter; + /* we need a layer iff we're drawing both a fill and stroke, and the stroke is non-opaque, and our shapetype actually supports fill+stroke. Otherwise we can just draw the stroke (if any) on top of the fill (if any) without worrying about blending artifacts. */ - final boolean useLayer = haveStroke && haveFill && st.mShape != LINE && - currStrokeAlpha < 255 && (mAlpha < 255 || mColorFilter != null); + final boolean useLayer = haveStroke && haveFill && st.mShape != LINE && + currStrokeAlpha < 255 && (mAlpha < 255 || colorFilter != null); /* Drawing with a layer is slower than direct drawing, but it allows us to apply paint effects like alpha and colorfilter to @@ -544,7 +549,7 @@ public class GradientDrawable extends Drawable { } mLayerPaint.setDither(st.mDither); mLayerPaint.setAlpha(mAlpha); - mLayerPaint.setColorFilter(mColorFilter); + mLayerPaint.setColorFilter(colorFilter); float rad = mStrokePaint.getStrokeWidth(); canvas.saveLayer(mRect.left - rad, mRect.top - rad, @@ -561,14 +566,14 @@ public class GradientDrawable extends Drawable { */ mFillPaint.setAlpha(currFillAlpha); mFillPaint.setDither(st.mDither); - mFillPaint.setColorFilter(mColorFilter); - if (mColorFilter != null && st.mColorStateList == null) { + mFillPaint.setColorFilter(colorFilter); + if (colorFilter != null && st.mColorStateList == null) { mFillPaint.setColor(mAlpha << 24); } if (haveStroke) { mStrokePaint.setAlpha(currStrokeAlpha); mStrokePaint.setDither(st.mDither); - mStrokePaint.setColorFilter(mColorFilter); + mStrokePaint.setColorFilter(colorFilter); } } @@ -593,7 +598,7 @@ public class GradientDrawable extends Drawable { canvas.drawRoundRect(mRect, rad, rad, mStrokePaint); } } else { - if (mFillPaint.getColor() != 0 || mColorFilter != null || + if (mFillPaint.getColor() != 0 || colorFilter != null || mFillPaint.getShader() != null) { canvas.drawRect(mRect, mFillPaint); } @@ -768,6 +773,11 @@ public class GradientDrawable extends Drawable { } } + if (s.mTint != null && s.mTintMode != null) { + mTintFilter = updateTintFilter(mTintFilter, s.mTint, s.mTintMode); + invalidateSelf = true; + } + if (invalidateSelf) { invalidateSelf(); return true; @@ -781,7 +791,8 @@ public class GradientDrawable extends Drawable { final GradientState s = mGradientState; return super.isStateful() || (s.mColorStateList != null && s.mColorStateList.isStateful()) - || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful()); + || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful()) + || (s.mTint != null && s.mTint.isStateful()); } @Override @@ -824,6 +835,20 @@ public class GradientDrawable extends Drawable { } @Override + public void setTintList(ColorStateList tint) { + mGradientState.mTint = tint; + mTintFilter = updateTintFilter(mTintFilter, tint, mGradientState.mTintMode); + invalidateSelf(); + } + + @Override + public void setTintMode(PorterDuff.Mode tintMode) { + mGradientState.mTintMode = tintMode; + mTintFilter = updateTintFilter(mTintFilter, mGradientState.mTint, tintMode); + invalidateSelf(); + } + + @Override public int getOpacity() { return (mAlpha == 255 && mGradientState.mOpaqueOverBounds && isOpaqueForState()) ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT; @@ -997,13 +1022,16 @@ public class GradientDrawable extends Drawable { super.applyTheme(t); final GradientState state = mGradientState; - if (state == null || state.mThemeAttrs == null) { + if (state == null) { return; } - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.GradientDrawable); - updateStateFromTypedArray(a); - a.recycle(); + if (state.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes( + state.mThemeAttrs, R.styleable.GradientDrawable); + updateStateFromTypedArray(a); + a.recycle(); + } applyThemeChildElements(t); @@ -1045,15 +1073,23 @@ public class GradientDrawable extends Drawable { state.mUseLevelForShape = a.getBoolean( R.styleable.GradientDrawable_useLevel, state.mUseLevelForShape); } + + final int tintMode = a.getInt(R.styleable.GradientDrawable_tintMode, -1); + if (tintMode != -1) { + state.mTintMode = Drawable.parseTintMode(tintMode, PorterDuff.Mode.SRC_IN); + } + + final ColorStateList tint = a.getColorStateList(R.styleable.GradientDrawable_tint); + if (tint != null) { + state.mTint = tint; + } + + mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } @Override public boolean canApplyTheme() { - final GradientState st = mGradientState; - return st != null && (st.mThemeAttrs != null || st.mAttrSize != null - || st.mAttrGradient != null || st.mAttrSolid != null - || st.mAttrStroke != null || st.mAttrCorners != null - || st.mAttrPadding != null); + return super.canApplyTheme() || mGradientState != null && mGradientState.canApplyTheme(); } private void applyThemeChildElements(Theme t) { @@ -1359,9 +1395,12 @@ public class GradientDrawable extends Drawable { } else { radiusType = RADIUS_TYPE_FRACTION; } - } else { + } else if (tv.type == TypedValue.TYPE_DIMENSION) { radius = tv.getDimension(r.getDisplayMetrics()); radiusType = RADIUS_TYPE_PIXELS; + } else { + radius = tv.getFloat(); + radiusType = RADIUS_TYPE_PIXELS; } st.mGradientRadius = radius; @@ -1479,6 +1518,14 @@ public class GradientDrawable extends Drawable { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + final static class GradientState extends ConstantState { public int mChangingConfigurations; public int mShape = RECTANGLE; @@ -1505,14 +1552,18 @@ public class GradientDrawable extends Drawable { public int mThickness = -1; public boolean mDither = false; - private float mCenterX = 0.5f; - private float mCenterY = 0.5f; - private float mGradientRadius = 0.5f; - private int mGradientRadiusType = RADIUS_TYPE_PIXELS; - private boolean mUseLevel; - private boolean mUseLevelForShape; - private boolean mOpaqueOverBounds; - private boolean mOpaqueOverShape; + float mCenterX = 0.5f; + float mCenterY = 0.5f; + float mGradientRadius = 0.5f; + int mGradientRadiusType = RADIUS_TYPE_PIXELS; + boolean mUseLevel = false; + boolean mUseLevelForShape = true; + + boolean mOpaqueOverBounds; + boolean mOpaqueOverShape; + + ColorStateList mTint = null; + PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE; int[] mThemeAttrs; int[] mAttrSize; @@ -1566,6 +1617,8 @@ public class GradientDrawable extends Drawable { mUseLevelForShape = state.mUseLevelForShape; mOpaqueOverBounds = state.mOpaqueOverBounds; mOpaqueOverShape = state.mOpaqueOverShape; + mTint = state.mTint; + mTintMode = state.mTintMode; mThemeAttrs = state.mThemeAttrs; mAttrSize = state.mAttrSize; mAttrGradient = state.mAttrGradient; @@ -1577,22 +1630,19 @@ public class GradientDrawable extends Drawable { @Override public boolean canApplyTheme() { - return mThemeAttrs != null; + return mThemeAttrs != null || mAttrSize != null || mAttrGradient != null + || mAttrSolid != null || mAttrStroke != null || mAttrCorners != null + || mAttrPadding != null; } @Override public Drawable newDrawable() { - return new GradientDrawable(this, null); + return new GradientDrawable(this); } @Override public Drawable newDrawable(Resources res) { - return new GradientDrawable(this, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new GradientDrawable(this, theme); + return new GradientDrawable(this); } @Override @@ -1696,18 +1746,11 @@ public class GradientDrawable extends Drawable { * The resulting drawable is guaranteed to have a new constant state. * * @param state Constant state from which the drawable inherits - * @param theme Theme to apply to the drawable */ - private GradientDrawable(GradientState state, Theme theme) { - if (theme != null && state.canApplyTheme()) { - // If we need to apply a theme, implicitly mutate. - mGradientState = new GradientState(state); - applyTheme(theme); - } else { - mGradientState = state; - } + private GradientDrawable(GradientState state) { + mGradientState = state; - initializeWithState(state); + initializeWithState(mGradientState); mGradientIsDirty = true; mMutated = false; diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 961d160..f1800e5 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -170,24 +170,30 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { super.applyTheme(t); final InsetState state = mInsetState; - if (state == null || state.mThemeAttrs == null) { + if (state == null) { return; } - final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.InsetDrawable); - try { - updateStateFromTypedArray(a); - verifyRequiredAttributes(a); - } catch (XmlPullParserException e) { - throw new RuntimeException(e); - } finally { - a.recycle(); + if (state.mThemeAttrs != null) { + final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.InsetDrawable); + try { + updateStateFromTypedArray(a); + verifyRequiredAttributes(a); + } catch (XmlPullParserException e) { + throw new RuntimeException(e); + } finally { + a.recycle(); + } + } + + if (state.mDrawable != null && state.mDrawable.canApplyTheme()) { + state.mDrawable.applyTheme(t); } } @Override public boolean canApplyTheme() { - return mInsetState != null && mInsetState.mThemeAttrs != null; + return super.canApplyTheme() || mInsetState != null && mInsetState.canApplyTheme(); } @Override @@ -339,12 +345,14 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { @Override public int getIntrinsicWidth() { - return mInsetState.mDrawable.getIntrinsicWidth(); + return mInsetState.mDrawable.getIntrinsicWidth() + + mInsetState.mInsetLeft + mInsetState.mInsetRight; } @Override public int getIntrinsicHeight() { - return mInsetState.mDrawable.getIntrinsicHeight(); + return mInsetState.mDrawable.getIntrinsicHeight() + + mInsetState.mInsetTop + mInsetState.mInsetBottom; } @Override @@ -371,6 +379,15 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { } /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mInsetState.mDrawable.clearMutated(); + mMutated = false; + } + + /** * Returns the drawable wrapped by this InsetDrawable. May be null. */ public Drawable getDrawable() { @@ -427,6 +444,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback { return mChangingConfigurations; } + @Override + public boolean canApplyTheme() { + return super.canApplyTheme() || mThemeAttrs != null + || mDrawable != null && mDrawable.canApplyTheme(); + } + boolean canConstantState() { if (!mCheckedConstantState) { mCanConstantState = mDrawable.getConstantState() != null; diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 001ed88..5107e10 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -100,10 +100,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @param state The constant drawable state. */ LayerDrawable(Drawable[] layers, LayerState state) { - this(state, null, null); - int length = layers.length; - ChildDrawable[] r = new ChildDrawable[length]; + this(state, null); + final int length = layers.length; + final ChildDrawable[] r = new ChildDrawable[length]; for (int i = 0; i < length; i++) { r[i] = new ChildDrawable(); r[i].mDrawable = layers[i]; @@ -117,18 +117,14 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } LayerDrawable() { - this((LayerState) null, null, null); + this((LayerState) null, null); } - LayerDrawable(LayerState state, Resources res, Theme theme) { - final LayerState as = createConstantState(state, res); - mLayerState = as; - if (as.mNum > 0) { + LayerDrawable(LayerState state, Resources res) { + mLayerState = createConstantState(state, res); + if (mLayerState.mNum > 0) { ensurePadding(); } - if (theme != null && canApplyTheme()) { - applyTheme(theme); - } } LayerState createConstantState(LayerState state, Resources res) { @@ -256,8 +252,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { a.recycle(); } - final ChildDrawable[] array = mLayerState.mChildren; - final int N = mLayerState.mNum; + final ChildDrawable[] array = state.mChildren; + final int N = state.mNum; for (int i = 0; i < N; i++) { final ChildDrawable layer = array[i]; if (layer.mThemeAttrs != null) { @@ -279,25 +275,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public boolean canApplyTheme() { - final LayerState state = mLayerState; - if (state == null) { - return false; - } - - if (state.mThemeAttrs != null) { - return true; - } - - final ChildDrawable[] array = state.mChildren; - final int N = state.mNum; - for (int i = 0; i < N; i++) { - final ChildDrawable layer = array[i]; - if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) { - return true; - } - } - - return false; + return super.canApplyTheme() || mLayerState != null && mLayerState.canApplyTheme(); } /** @@ -940,6 +918,19 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + final ChildDrawable[] array = mLayerState.mChildren; + final int N = mLayerState.mNum; + for (int i = 0; i < N; i++) { + array[i].mDrawable.clearMutated(); + } + mMutated = false; + } + /** @hide */ @Override public void setLayoutDirection(int layoutDirection) { @@ -1029,22 +1020,30 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public boolean canApplyTheme() { - return mThemeAttrs != null; + if (mThemeAttrs != null) { + return true; + } + + final ChildDrawable[] array = mChildren; + final int N = mNum; + for (int i = 0; i < N; i++) { + final ChildDrawable layer = array[i]; + if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) { + return true; + } + } + + return false; } @Override public Drawable newDrawable() { - return new LayerDrawable(this, null, null); + return new LayerDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { - return new LayerDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new LayerDrawable(this, res, theme); + return new LayerDrawable(this, res); } @Override diff --git a/graphics/java/android/graphics/drawable/LevelListDrawable.java b/graphics/java/android/graphics/drawable/LevelListDrawable.java index bc1c61d..9e918f6 100644 --- a/graphics/java/android/graphics/drawable/LevelListDrawable.java +++ b/graphics/java/android/graphics/drawable/LevelListDrawable.java @@ -153,6 +153,14 @@ public class LevelListDrawable extends DrawableContainer { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + private final static class LevelListState extends DrawableContainerState { private int[] mLows; private int[] mHighs; diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 6c62ccf..d821224 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -90,7 +90,7 @@ public class NinePatchDrawable extends Drawable { */ @Deprecated public NinePatchDrawable(Bitmap bitmap, byte[] chunk, Rect padding, String srcName) { - this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null, null); + this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), null); } /** @@ -99,7 +99,7 @@ public class NinePatchDrawable extends Drawable { */ public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk, Rect padding, String srcName) { - this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res, null); + this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding), res); mNinePatchState.mTargetDensity = mTargetDensity; } @@ -112,7 +112,7 @@ public class NinePatchDrawable extends Drawable { public NinePatchDrawable(Resources res, Bitmap bitmap, byte[] chunk, Rect padding, Rect opticalInsets, String srcName) { this(new NinePatchState(new NinePatch(bitmap, chunk, srcName), padding, opticalInsets), - res, null); + res); mNinePatchState.mTargetDensity = mTargetDensity; } @@ -123,7 +123,7 @@ public class NinePatchDrawable extends Drawable { */ @Deprecated public NinePatchDrawable(NinePatch patch) { - this(new NinePatchState(patch, new Rect()), null, null); + this(new NinePatchState(patch, new Rect()), null); } /** @@ -131,7 +131,7 @@ public class NinePatchDrawable extends Drawable { * based on the display metrics of the resources. */ public NinePatchDrawable(Resources res, NinePatch patch) { - this(new NinePatchState(patch, new Rect()), res, null); + this(new NinePatchState(patch, new Rect()), res); mNinePatchState.mTargetDensity = mTargetDensity; } @@ -563,6 +563,14 @@ public class NinePatchDrawable extends Drawable { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + @Override protected boolean onStateChange(int[] stateSet) { final NinePatchState state = mNinePatchState; @@ -646,17 +654,12 @@ public class NinePatchDrawable extends Drawable { @Override public Drawable newDrawable() { - return new NinePatchDrawable(this, null, null); + return new NinePatchDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { - return new NinePatchDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new NinePatchDrawable(this, res, theme); + return new NinePatchDrawable(this, res); } @Override @@ -669,16 +672,10 @@ public class NinePatchDrawable extends Drawable { * The one constructor to rule them all. This is called by all public * constructors to set the state and initialize local properties. */ - private NinePatchDrawable(NinePatchState state, Resources res, Theme theme) { - if (theme != null && state.canApplyTheme()) { - // If we need to apply a theme, implicitly mutate. - mNinePatchState = new NinePatchState(state); - applyTheme(theme); - } else { - mNinePatchState = state; - } + private NinePatchDrawable(NinePatchState state, Resources res) { + mNinePatchState = state; - initializeWithState(state, res); + initializeWithState(mNinePatchState, res); } /** diff --git a/graphics/java/android/graphics/drawable/RippleBackground.java b/graphics/java/android/graphics/drawable/RippleBackground.java index faa89bf..21d865f 100644 --- a/graphics/java/android/graphics/drawable/RippleBackground.java +++ b/graphics/java/android/graphics/drawable/RippleBackground.java @@ -43,10 +43,12 @@ class RippleBackground { private static final float WAVE_OPACITY_DECAY_VELOCITY = 3.0f / GLOBAL_SPEED; private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MAX = 4.5f * GLOBAL_SPEED; private static final float WAVE_OUTER_OPACITY_EXIT_VELOCITY_MIN = 1.5f * GLOBAL_SPEED; - private static final float WAVE_OUTER_OPACITY_ENTER_VELOCITY = 10.0f * GLOBAL_SPEED; private static final float WAVE_OUTER_SIZE_INFLUENCE_MAX = 200f; private static final float WAVE_OUTER_SIZE_INFLUENCE_MIN = 40f; + private static final int ENTER_DURATION = 667; + private static final int ENTER_DURATION_FAST = 100; + // Hardware animators. private final ArrayList<RenderNodeAnimator> mRunningAnimations = new ArrayList<RenderNodeAnimator>(); @@ -224,21 +226,20 @@ class RippleBackground { /** * Starts the enter animation. */ - public void enter() { + public void enter(boolean fast) { cancel(); - final int outerDuration = (int) (1000 * 1.0f / WAVE_OUTER_OPACITY_ENTER_VELOCITY); - final ObjectAnimator outer = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1); - outer.setAutoCancel(true); - outer.setDuration(outerDuration); - outer.setInterpolator(LINEAR_INTERPOLATOR); + final ObjectAnimator opacity = ObjectAnimator.ofFloat(this, "outerOpacity", 0, 1); + opacity.setAutoCancel(true); + opacity.setDuration(fast ? ENTER_DURATION_FAST : ENTER_DURATION); + opacity.setInterpolator(LINEAR_INTERPOLATOR); - mAnimOuterOpacity = outer; + mAnimOuterOpacity = opacity; // Enter animations always run on the UI thread, since it's unlikely // that anything interesting is happening until the user lifts their // finger. - outer.start(); + opacity.start(); } /** diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index c7aa98e..316139b 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -167,7 +167,7 @@ public class RippleDrawable extends LayerDrawable { * Constructor used for drawable inflation. */ RippleDrawable() { - this(new RippleState(null, null, null), null, null); + this(new RippleState(null, null, null), null); } /** @@ -180,7 +180,7 @@ public class RippleDrawable extends LayerDrawable { */ public RippleDrawable(@NonNull ColorStateList color, @Nullable Drawable content, @Nullable Drawable mask) { - this(new RippleState(null, null, null), null, null); + this(new RippleState(null, null, null), null); if (color == null) { throw new IllegalArgumentException("RippleDrawable requires a non-null color"); @@ -280,7 +280,7 @@ public class RippleDrawable extends LayerDrawable { } setRippleActive(enabled && pressed); - setBackgroundActive(focused || (enabled && pressed)); + setBackgroundActive(focused || (enabled && pressed), focused); return changed; } @@ -296,11 +296,11 @@ public class RippleDrawable extends LayerDrawable { } } - private void setBackgroundActive(boolean active) { + private void setBackgroundActive(boolean active, boolean focused) { if (mBackgroundActive != active) { mBackgroundActive = active; if (active) { - tryBackgroundEnter(); + tryBackgroundEnter(focused); } else { tryBackgroundExit(); } @@ -333,8 +333,11 @@ public class RippleDrawable extends LayerDrawable { } if (mBackgroundActive) { - tryBackgroundEnter(); + tryBackgroundEnter(false); } + + // Skip animations, just show the correct final states. + jumpToCurrentState(); } return changed; @@ -470,7 +473,7 @@ public class RippleDrawable extends LayerDrawable { @Override public boolean canApplyTheme() { - return super.canApplyTheme() || mState != null && mState.mTouchThemeAttrs != null; + return super.canApplyTheme() || mState != null && mState.canApplyTheme(); } @Override @@ -489,14 +492,14 @@ public class RippleDrawable extends LayerDrawable { /** * Creates an active hotspot at the specified location. */ - private void tryBackgroundEnter() { + private void tryBackgroundEnter(boolean focused) { if (mBackground == null) { mBackground = new RippleBackground(this, mHotspotBounds); } final int color = mState.mColor.getColorForState(getState(), Color.TRANSPARENT); mBackground.setup(mState.mMaxRadius, color, mDensity); - mBackground.enter(); + mBackground.enter(focused); } private void tryBackgroundExit() { @@ -715,10 +718,12 @@ public class RippleDrawable extends LayerDrawable { final ChildDrawable[] array = mLayerState.mChildren; final int count = mLayerState.mNum; - // We don't need a layer if we don't expect to draw any ripples, we have - // an explicit mask, or if the non-mask content is all opaque. + // We don't need a layer if we don't expect to draw any ripples or + // a background, we have an explicit mask, or if the non-mask content + // is all opaque. boolean needsLayer = false; - if ((mExitingRipplesCount > 0 || mBackground != null) && mMask == null) { + if ((mExitingRipplesCount > 0 || (mBackground != null && mBackground.shouldDraw())) + && mMask == null) { for (int i = 0; i < count; i++) { if (array[i].mId != R.id.mask && array[i].mDrawable.getOpacity() != PixelFormat.OPAQUE) { @@ -924,17 +929,12 @@ public class RippleDrawable extends LayerDrawable { @Override public Drawable newDrawable() { - return new RippleDrawable(this, null, null); + return new RippleDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { - return new RippleDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new RippleDrawable(this, res, theme); + return new RippleDrawable(this, res); } } @@ -968,37 +968,18 @@ public class RippleDrawable extends LayerDrawable { return mState.mMaxRadius; } - private RippleDrawable(RippleState state, Resources res, Theme theme) { - boolean needsTheme = false; + private RippleDrawable(RippleState state, Resources res) { + mState = new RippleState(state, this, res); + mLayerState = mState; - final RippleState ns; - if (theme != null && state != null && state.canApplyTheme()) { - ns = new RippleState(state, this, res); - needsTheme = true; - } else if (state == null) { - ns = new RippleState(null, this, res); - } else { - // We always need a new state since child drawables contain local - // state but live within the parent's constant state. - // TODO: Move child drawables into local state. - ns = new RippleState(state, this, res); + if (mState.mNum > 0) { + ensurePadding(); } if (res != null) { mDensity = res.getDisplayMetrics().density; } - mState = ns; - mLayerState = ns; - - if (ns.mNum > 0) { - ensurePadding(); - } - - if (needsTheme) { - applyTheme(theme); - } - initializeFromState(); } diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index 55c9637..3f75bc3 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -16,6 +16,8 @@ package android.graphics.drawable; +import com.android.internal.R; + import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -476,6 +478,26 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { } @Override + public void applyTheme(Theme t) { + super.applyTheme(t); + + final RotateState state = mState; + if (state == null) { + return; + } + + if (state.mDrawable != null) { + state.mDrawable.applyTheme(t); + } + } + + @Override + public boolean canApplyTheme() { + final RotateState state = mState; + return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme(); + } + + @Override public Drawable mutate() { if (!mMutated && super.mutate() == this) { mState.mDrawable.mutate(); @@ -485,6 +507,15 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { } /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mState.mDrawable.clearMutated(); + mMutated = false; + } + + /** * Represents the state of a rotation for a given drawable. The same * rotate drawable can be invoked with different states to drive several * rotations at the same time. diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index b990249..9a5b8fb 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -128,6 +128,26 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { } } + @Override + public void applyTheme(Theme t) { + super.applyTheme(t); + + final ScaleState state = mScaleState; + if (state == null) { + return; + } + + if (state.mDrawable != null) { + state.mDrawable.applyTheme(t); + } + } + + @Override + public boolean canApplyTheme() { + final ScaleState state = mScaleState; + return state != null && state.mDrawable != null && state.mDrawable.canApplyTheme(); + } + // overrides from Drawable.Callback public void invalidateDrawable(Drawable who) { @@ -276,6 +296,15 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mScaleState.mDrawable.clearMutated(); + mMutated = false; + } + final static class ScaleState extends ConstantState { Drawable mDrawable; int mChangingConfigurations; diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index bd69d76..a3d8c92 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -76,7 +76,7 @@ public class ShapeDrawable extends Drawable { * ShapeDrawable constructor. */ public ShapeDrawable() { - this(new ShapeState(null), null, null); + this(new ShapeState(null), null); } /** @@ -85,7 +85,7 @@ public class ShapeDrawable extends Drawable { * @param s the Shape that this ShapeDrawable should be */ public ShapeDrawable(Shape s) { - this(new ShapeState(null), null, null); + this(new ShapeState(null), null); mShapeState.mShape = s; } @@ -508,6 +508,14 @@ public class ShapeDrawable extends Drawable { } /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + + /** * Defines the intrinsic properties of this ShapeDrawable's Shape. */ final static class ShapeState extends ConstantState { @@ -547,17 +555,12 @@ public class ShapeDrawable extends Drawable { @Override public Drawable newDrawable() { - return new ShapeDrawable(this, null, null); + return new ShapeDrawable(this, null); } @Override public Drawable newDrawable(Resources res) { - return new ShapeDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new ShapeDrawable(this, res, theme); + return new ShapeDrawable(this, res); } @Override @@ -570,13 +573,8 @@ public class ShapeDrawable extends Drawable { * The one constructor to rule them all. This is called by all public * constructors to set the state and initialize local properties. */ - private ShapeDrawable(ShapeState state, Resources res, Theme theme) { - if (theme != null && state.canApplyTheme()) { - mShapeState = new ShapeState(state); - applyTheme(theme); - } else { - mShapeState = state; - } + private ShapeDrawable(ShapeState state, Resources res) { + mShapeState = state; initializeWithState(state, res); } diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 2eb8a80..a299b3c 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -263,6 +263,14 @@ public class StateListDrawable extends DrawableContainer { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + /** @hide */ @Override public void setLayoutDirection(int layoutDirection) { @@ -280,7 +288,16 @@ public class StateListDrawable extends DrawableContainer { super(orig, owner, res); if (orig != null) { - mStateSets = Arrays.copyOf(orig.mStateSets, orig.mStateSets.length); + // Perform a deep copy. + final int[][] sets = orig.mStateSets; + final int count = sets.length; + mStateSets = new int[count][]; + for (int i = 0; i < count; i++) { + final int[] set = sets[i]; + if (set != null) { + mStateSets[i] = set.clone(); + } + } } else { mStateSets = new int[getCapacity()][]; } @@ -322,6 +339,13 @@ public class StateListDrawable extends DrawableContainer { } } + @Override + public void applyTheme(Theme theme) { + super.applyTheme(theme); + + onStateChange(getState()); + } + void setConstantState(StateListState state) { super.setConstantState(state); diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java index 4380ca4..e5c235e 100644 --- a/graphics/java/android/graphics/drawable/TransitionDrawable.java +++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java @@ -17,7 +17,6 @@ package android.graphics.drawable; import android.content.res.Resources; -import android.content.res.Resources.Theme; import android.graphics.Canvas; import android.os.SystemClock; @@ -86,11 +85,11 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba * @see #TransitionDrawable(Drawable[]) */ TransitionDrawable() { - this(new TransitionState(null, null, null), null, null); + this(new TransitionState(null, null, null), (Resources) null); } - private TransitionDrawable(TransitionState state, Resources res, Theme theme) { - super(state, res, theme); + private TransitionDrawable(TransitionState state, Resources res) { + super(state, res); } private TransitionDrawable(TransitionState state, Drawable[] layers) { @@ -245,24 +244,18 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba } static class TransitionState extends LayerState { - TransitionState(TransitionState orig, TransitionDrawable owner, - Resources res) { + TransitionState(TransitionState orig, TransitionDrawable owner, Resources res) { super(orig, owner, res); } @Override public Drawable newDrawable() { - return new TransitionDrawable(this, null, null); + return new TransitionDrawable(this, (Resources) null); } @Override public Drawable newDrawable(Resources res) { - return new TransitionDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new TransitionDrawable(this, res, theme); + return new TransitionDrawable(this, res); } @Override diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index db0c94f..848fc53 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -14,6 +14,7 @@ package android.graphics.drawable; +import android.annotation.NonNull; import android.content.res.ColorStateList; import android.content.res.Resources; import android.content.res.Resources.Theme; @@ -212,15 +213,8 @@ public class VectorDrawable extends Drawable { mVectorState = new VectorDrawableState(); } - private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) { - if (theme != null && state.canApplyTheme()) { - // If we need to apply a theme, implicitly mutate. - mVectorState = new VectorDrawableState(state); - applyTheme(theme); - } else { - mVectorState = state; - } - + private VectorDrawable(@NonNull VectorDrawableState state) { + mVectorState = state; mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode); } @@ -233,6 +227,14 @@ public class VectorDrawable extends Drawable { return this; } + /** + * @hide + */ + public void clearMutated() { + super.clearMutated(); + mMutated = false; + } + Object getTargetByName(String name) { return mVectorState.mVPathRenderer.mVGTargetsMap.get(name); } @@ -758,17 +760,12 @@ public class VectorDrawable extends Drawable { @Override public Drawable newDrawable() { - return new VectorDrawable(this, null, null); + return new VectorDrawable(this); } @Override public Drawable newDrawable(Resources res) { - return new VectorDrawable(this, res, null); - } - - @Override - public Drawable newDrawable(Resources res, Theme theme) { - return new VectorDrawable(this, res, theme); + return new VectorDrawable(this); } @Override diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk index 597250a..a0442e4 100644 --- a/libs/androidfw/tests/Android.mk +++ b/libs/androidfw/tests/Android.mk @@ -26,6 +26,7 @@ testFiles := \ Idmap_test.cpp \ ResTable_test.cpp \ Split_test.cpp \ + TestHelpers.cpp \ Theme_test.cpp \ TypeWrappers_test.cpp \ ZipUtils_test.cpp @@ -50,6 +51,7 @@ include $(BUILD_HOST_NATIVE_TEST) # ========================================================== # Build the device tests: libandroidfw_tests # ========================================================== +ifneq ($(SDK_ONLY),true) include $(CLEAR_VARS) LOCAL_MODULE := libandroidfw_tests @@ -65,3 +67,5 @@ LOCAL_SHARED_LIBRARIES := \ libui \ include $(BUILD_NATIVE_TEST) +endif # Not SDK_ONLY + diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp index 89d271d0..6a9314e 100644 --- a/libs/androidfw/tests/ResTable_test.cpp +++ b/libs/androidfw/tests/ResTable_test.cpp @@ -37,8 +37,6 @@ namespace { #include "data/lib/lib_arsc.h" -enum { MAY_NOT_BE_BAG = false }; - TEST(ResTableTest, shouldLoadSuccessfully) { ResTable table; ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); @@ -48,15 +46,7 @@ TEST(ResTableTest, simpleTypeIsRetrievedCorrectly) { ResTable table; ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); - Res_value val; - ssize_t block = table.getResource(base::R::string::test1, &val, MAY_NOT_BE_BAG); - - ASSERT_GE(block, 0); - ASSERT_EQ(Res_value::TYPE_STRING, val.dataType); - - const ResStringPool* pool = table.getTableStringBlock(block); - ASSERT_TRUE(NULL != pool); - ASSERT_EQ(String8("test1"), pool->string8ObjectAt(val.data)); + EXPECT_TRUE(IsStringEqual(table, base::R::string::test1, "test1")); } TEST(ResTableTest, resourceNameIsResolved) { diff --git a/libs/androidfw/tests/Split_test.cpp b/libs/androidfw/tests/Split_test.cpp index f63f566..b69d685 100644 --- a/libs/androidfw/tests/Split_test.cpp +++ b/libs/androidfw/tests/Split_test.cpp @@ -42,6 +42,9 @@ namespace { * Package: com.android.test.basic */ #include "data/basic/split_de_fr_arsc.h" +#include "data/basic/split_hdpi_v4_arsc.h" +#include "data/basic/split_xhdpi_v4_arsc.h" +#include "data/basic/split_xxhdpi_v4_arsc.h" /** * Include a binary resource table. This table @@ -163,6 +166,33 @@ TEST(SplitTest, TypeEntrySpecFlagsAreUpdated) { EXPECT_EQ(ResTable_config::CONFIG_LOCALE, frSpecFlags); } +TEST(SplitTest, SelectBestDensity) { + ResTable_config baseConfig; + memset(&baseConfig, 0, sizeof(baseConfig)); + baseConfig.density = ResTable_config::DENSITY_XHIGH; + baseConfig.sdkVersion = 21; + + ResTable table; + table.setParameters(&baseConfig); + ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); + ASSERT_EQ(NO_ERROR, table.add(split_hdpi_v4_arsc, split_hdpi_v4_arsc_len)); + + EXPECT_TRUE(IsStringEqual(table, base::R::string::density, "hdpi")); + + ASSERT_EQ(NO_ERROR, table.add(split_xhdpi_v4_arsc, split_xhdpi_v4_arsc_len)); + + EXPECT_TRUE(IsStringEqual(table, base::R::string::density, "xhdpi")); + + ASSERT_EQ(NO_ERROR, table.add(split_xxhdpi_v4_arsc, split_xxhdpi_v4_arsc_len)); + + EXPECT_TRUE(IsStringEqual(table, base::R::string::density, "xhdpi")); + + baseConfig.density = ResTable_config::DENSITY_XXHIGH; + table.setParameters(&baseConfig); + + EXPECT_TRUE(IsStringEqual(table, base::R::string::density, "xxhdpi")); +} + TEST(SplitFeatureTest, TestNewResourceIsAccessible) { ResTable table; ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len)); @@ -188,7 +218,7 @@ TEST(SplitFeatureTest, TestNewResourceNameHasCorrectName) { ASSERT_EQ(NO_ERROR, table.add(feature_arsc, feature_arsc_len)); - EXPECT_TRUE(table.getResourceName(base::R::string::test3, false, &name)); + ASSERT_TRUE(table.getResourceName(base::R::string::test3, false, &name)); EXPECT_EQ(String16("com.android.test.basic"), String16(name.package, name.packageLen)); diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp new file mode 100644 index 0000000..41a19a7 --- /dev/null +++ b/libs/androidfw/tests/TestHelpers.cpp @@ -0,0 +1,48 @@ +/* + * 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. + */ + +#include "TestHelpers.h" + +#include <androidfw/ResourceTypes.h> +#include <utils/String8.h> +#include <gtest/gtest.h> + +namespace android { + +::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resourceId, const char* expectedStr) { + Res_value val; + ssize_t block = table.getResource(resourceId, &val, MAY_NOT_BE_BAG); + if (block < 0) { + return ::testing::AssertionFailure() << "could not find resource"; + } + + if (val.dataType != Res_value::TYPE_STRING) { + return ::testing::AssertionFailure() << "resource is not a string"; + } + + const ResStringPool* pool = table.getTableStringBlock(block); + if (pool == NULL) { + return ::testing::AssertionFailure() << "table has no string pool for block " << block; + } + + const String8 actual = pool->string8ObjectAt(val.data); + if (String8(expectedStr) != actual) { + return ::testing::AssertionFailure() << actual.string(); + } + return ::testing::AssertionSuccess() << actual.string(); +} + +} // namespace android diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h index fe2e5ce..ac80d88 100644 --- a/libs/androidfw/tests/TestHelpers.h +++ b/libs/androidfw/tests/TestHelpers.h @@ -6,6 +6,7 @@ #include <androidfw/ResourceTypes.h> #include <utils/String8.h> #include <utils/String16.h> +#include <gtest/gtest.h> static inline ::std::ostream& operator<<(::std::ostream& out, const android::String8& str) { return out << str.string(); @@ -17,6 +18,8 @@ static inline ::std::ostream& operator<<(::std::ostream& out, const android::Str namespace android { +enum { MAY_NOT_BE_BAG = false }; + static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) { return memcmp(&a, &b, sizeof(a)) == 0; } @@ -25,6 +28,8 @@ static inline ::std::ostream& operator<<(::std::ostream& out, const android::Res return out << c.toString().string(); } +::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resourceId, const char* expectedStr); + } // namespace android #endif // __TEST_HELPERS_H diff --git a/libs/androidfw/tests/data/app/R.h b/libs/androidfw/tests/data/app/R.h index 780a116..23e68e3 100644 --- a/libs/androidfw/tests/data/app/R.h +++ b/libs/androidfw/tests/data/app/R.h @@ -1,3 +1,19 @@ +/* + * 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. + */ + #ifndef __APP_R_H #define __APP_R_H diff --git a/libs/androidfw/tests/data/app/build b/libs/androidfw/tests/data/app/build index 89c4641..62257bc 100755 --- a/libs/androidfw/tests/data/app/build +++ b/libs/androidfw/tests/data/app/build @@ -1,4 +1,19 @@ #!/bin/bash +# +# 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. +# aapt package -v -I ../system/bundle.apk -M AndroidManifest.xml -S res -F bundle.apk -f && \ unzip bundle.apk resources.arsc && \ diff --git a/libs/androidfw/tests/data/app/res/values/values.xml b/libs/androidfw/tests/data/app/res/values/values.xml index b0ead38..c1cf64c 100644 --- a/libs/androidfw/tests/data/app/res/values/values.xml +++ b/libs/androidfw/tests/data/app/res/values/values.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <attr name="number" format="integer"/> <style name="Theme.One" parent="@android:style/Theme.One"> diff --git a/libs/androidfw/tests/data/basic/R.h b/libs/androidfw/tests/data/basic/R.h index 363dcb9..aaac740 100644 --- a/libs/androidfw/tests/data/basic/R.h +++ b/libs/androidfw/tests/data/basic/R.h @@ -1,3 +1,19 @@ +/* + * 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. + */ + #ifndef __BASE_R_H #define __BASE_R_H @@ -21,9 +37,10 @@ namespace string { enum { test1 = 0x7f030000, // default test2 = 0x7f030001, // default + density = 0x7f030002, // default - test3 = 0x7f070000, // default (in feature) - test4 = 0x7f070001, // default (in feature) + test3 = 0x7f080000, // default (in feature) + test4 = 0x7f080001, // default (in feature) }; } @@ -32,7 +49,7 @@ namespace integer { number1 = 0x7f040000, // default, sv number2 = 0x7f040001, // default - test3 = 0x7f080000, // default (in feature) + test3 = 0x7f090000, // default (in feature) }; } diff --git a/libs/androidfw/tests/data/basic/basic_arsc.h b/libs/androidfw/tests/data/basic/basic_arsc.h index 61cb94c..13ab4fa 100644 --- a/libs/androidfw/tests/data/basic/basic_arsc.h +++ b/libs/androidfw/tests/data/basic/basic_arsc.h @@ -1,5 +1,5 @@ unsigned char basic_arsc[] = { - 0x02, 0x00, 0x0c, 0x00, 0x60, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0x68, 0x07, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0xbc, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, @@ -16,7 +16,7 @@ unsigned char basic_arsc[] = { 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, - 0x98, 0x06, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, + 0xa0, 0x06, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, @@ -101,61 +101,61 @@ unsigned char basic_arsc[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, - 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, - 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, - 0x6c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, + 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, - 0xc8, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x06, 0x7f, 0x01, 0x02, 0x44, 0x00, - 0x5c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x73, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, - 0x08, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, - 0x90, 0x01, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x90, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x06, 0x7f, 0x01, 0x02, 0x44, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, 0x90, 0x01, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x44, 0x00, 0x90, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x64, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x7f, - 0x10, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x7f, - 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, - 0x2c, 0x01, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x44, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x07, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x7f, + 0x08, 0x00, 0x00, 0x10, 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f, + 0x08, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x7f, 0x10, 0x00, 0x01, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x7f, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x7f, 0x08, 0x00, 0x00, 0x10, 0x2c, 0x01, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, + 0x7c, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x10, 0x00, 0x01, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, - 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, - 0x03, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x02, 0x08, 0x00, 0x00, 0x10, 0x03, 0x00, 0x00, 0x00 }; -unsigned int basic_arsc_len = 1888; +unsigned int basic_arsc_len = 1896; diff --git a/libs/androidfw/tests/data/basic/build b/libs/androidfw/tests/data/basic/build index 036e468..fd289fa 100755 --- a/libs/androidfw/tests/data/basic/build +++ b/libs/androidfw/tests/data/basic/build @@ -1,11 +1,39 @@ #!/bin/bash +# +# 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. +# PATH_TO_FRAMEWORK_RES=$(gettop)/prebuilts/sdk/current/android.jar -aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --split fr,de -F bundle.apk -f && \ +aapt package -M AndroidManifest.xml -S res -I $PATH_TO_FRAMEWORK_RES --split hdpi --split xhdpi --split xxhdpi --split fr,de -F bundle.apk -f && \ unzip bundle.apk resources.arsc && \ mv resources.arsc basic.arsc && \ xxd -i basic.arsc > basic_arsc.h && \ +\ unzip bundle_de_fr.apk resources.arsc && \ mv resources.arsc split_de_fr.arsc && \ -xxd -i split_de_fr.arsc > split_de_fr_arsc.h +xxd -i split_de_fr.arsc > split_de_fr_arsc.h && \ +\ +unzip bundle_hdpi-v4.apk resources.arsc && \ +mv resources.arsc split_hdpi_v4.arsc && \ +xxd -i split_hdpi_v4.arsc > split_hdpi_v4_arsc.h && \ +\ +unzip bundle_xhdpi-v4.apk resources.arsc && \ +mv resources.arsc split_xhdpi_v4.arsc && \ +xxd -i split_xhdpi_v4.arsc > split_xhdpi_v4_arsc.h && \ +\ +unzip bundle_xxhdpi-v4.apk resources.arsc && \ +mv resources.arsc split_xxhdpi_v4.arsc && \ +xxd -i split_xxhdpi_v4.arsc > split_xxhdpi_v4_arsc.h \ diff --git a/libs/androidfw/tests/data/basic/res/layout-fr-sw600dp/main.xml b/libs/androidfw/tests/data/basic/res/layout-fr-sw600dp/main.xml index 05ffd58..0dcf7e0 100644 --- a/libs/androidfw/tests/data/basic/res/layout-fr-sw600dp/main.xml +++ b/libs/androidfw/tests/data/basic/res/layout-fr-sw600dp/main.xml @@ -1,3 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <merge> </merge> diff --git a/libs/androidfw/tests/data/basic/res/layout/main.xml b/libs/androidfw/tests/data/basic/res/layout/main.xml index 05ffd58..0dcf7e0 100644 --- a/libs/androidfw/tests/data/basic/res/layout/main.xml +++ b/libs/androidfw/tests/data/basic/res/layout/main.xml @@ -1,3 +1,18 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <merge> </merge> diff --git a/libs/androidfw/tests/data/basic/res/values-de/values.xml b/libs/androidfw/tests/data/basic/res/values-de/values.xml index 103c6a3..2683a7e 100644 --- a/libs/androidfw/tests/data/basic/res/values-de/values.xml +++ b/libs/androidfw/tests/data/basic/res/values-de/values.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <string name="test1">versuch 1</string> <string name="test2">versuch 2</string> diff --git a/libs/androidfw/tests/data/basic/res/values-fr/values.xml b/libs/androidfw/tests/data/basic/res/values-fr/values.xml index 1806a2d..7d3bed3 100644 --- a/libs/androidfw/tests/data/basic/res/values-fr/values.xml +++ b/libs/androidfw/tests/data/basic/res/values-fr/values.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <string name="test1">essai 1</string> <string name="test2">essai 2</string> diff --git a/libs/androidfw/tests/data/basic/res/values-hdpi/values.xml b/libs/androidfw/tests/data/basic/res/values-hdpi/values.xml new file mode 100644 index 0000000..04bf943 --- /dev/null +++ b/libs/androidfw/tests/data/basic/res/values-hdpi/values.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <string name="density">hdpi</string> +</resources> diff --git a/libs/androidfw/tests/data/basic/res/values-sv/values.xml b/libs/androidfw/tests/data/basic/res/values-sv/values.xml index 9d52307..7351b49 100644 --- a/libs/androidfw/tests/data/basic/res/values-sv/values.xml +++ b/libs/androidfw/tests/data/basic/res/values-sv/values.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <integer name="number1">400</integer> </resources> diff --git a/libs/androidfw/tests/data/basic/res/values-xhdpi/values.xml b/libs/androidfw/tests/data/basic/res/values-xhdpi/values.xml new file mode 100644 index 0000000..845e9a0 --- /dev/null +++ b/libs/androidfw/tests/data/basic/res/values-xhdpi/values.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <string name="density">xhdpi</string> +</resources> diff --git a/libs/androidfw/tests/data/basic/res/values-xxhdpi/values.xml b/libs/androidfw/tests/data/basic/res/values-xxhdpi/values.xml new file mode 100644 index 0000000..964da02 --- /dev/null +++ b/libs/androidfw/tests/data/basic/res/values-xxhdpi/values.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<resources> + <string name="density">xxhdpi</string> +</resources> diff --git a/libs/androidfw/tests/data/basic/res/values/values.xml b/libs/androidfw/tests/data/basic/res/values/values.xml index 662eda6..a010cca 100644 --- a/libs/androidfw/tests/data/basic/res/values/values.xml +++ b/libs/androidfw/tests/data/basic/res/values/values.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <attr name="attr1" format="reference|integer" /> <attr name="attr2" format="reference|integer" /> diff --git a/libs/androidfw/tests/data/basic/split_de_fr_arsc.h b/libs/androidfw/tests/data/basic/split_de_fr_arsc.h index a8eaf0b..b742d28 100644 --- a/libs/androidfw/tests/data/basic/split_de_fr_arsc.h +++ b/libs/androidfw/tests/data/basic/split_de_fr_arsc.h @@ -1,5 +1,5 @@ unsigned char split_de_fr_arsc[] = { - 0x02, 0x00, 0x0c, 0x00, 0xd8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0xe4, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, @@ -10,7 +10,7 @@ unsigned char split_de_fr_arsc[] = { 0x32, 0x00, 0x00, 0x00, 0x07, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x61, 0x00, 0x69, 0x00, 0x20, 0x00, 0x31, 0x00, 0x00, 0x00, 0x07, 0x00, 0x65, 0x00, 0x73, 0x00, 0x73, 0x00, 0x61, 0x00, 0x69, 0x00, 0x20, 0x00, - 0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x50, 0x03, 0x00, 0x00, + 0x32, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x5c, 0x03, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, @@ -55,24 +55,25 @@ unsigned char split_de_fr_arsc[] = { 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x65, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, + 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x64, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x44, 0x00, 0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x10, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, @@ -82,4 +83,4 @@ unsigned char split_de_fr_arsc[] = { 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -unsigned int split_de_fr_arsc_len = 984; +unsigned int split_de_fr_arsc_len = 996; diff --git a/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h new file mode 100644 index 0000000..e9fb7ea --- /dev/null +++ b/libs/androidfw/tests/data/basic/split_hdpi_v4_arsc.h @@ -0,0 +1,68 @@ +unsigned char split_hdpi_v4_arsc[] = { + 0x02, 0x00, 0x0c, 0x00, 0x08, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x1c, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x68, 0x00, + 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, + 0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, + 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, + 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, + 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, + 0x69, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0xb0, 0x01, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, + 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, 0x6f, 0x00, 0x75, 0x00, + 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, + 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, + 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, + 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, + 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x72, 0x00, 0x72, 0x00, + 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x64, 0x00, 0x65, 0x00, 0x6e, 0x00, + 0x73, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +unsigned int split_hdpi_v4_arsc_len = 776; diff --git a/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h new file mode 100644 index 0000000..7835f71 --- /dev/null +++ b/libs/androidfw/tests/data/basic/split_xhdpi_v4_arsc.h @@ -0,0 +1,68 @@ +unsigned char split_xhdpi_v4_arsc[] = { + 0x02, 0x00, 0x0c, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x78, 0x00, + 0x68, 0x00, 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x20, 0x01, 0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, + 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, + 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xb0, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x1c, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, + 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, + 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, + 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, + 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, + 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x1c, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x64, 0x00, + 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +unsigned int split_xhdpi_v4_arsc_len = 780; diff --git a/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h b/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h new file mode 100644 index 0000000..f805db1 --- /dev/null +++ b/libs/androidfw/tests/data/basic/split_xxhdpi_v4_arsc.h @@ -0,0 +1,68 @@ +unsigned char split_xxhdpi_v4_arsc[] = { + 0x02, 0x00, 0x0c, 0x00, 0x0c, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x1c, 0x00, 0x30, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x78, 0x00, + 0x78, 0x00, 0x68, 0x00, 0x64, 0x00, 0x70, 0x00, 0x69, 0x00, 0x00, 0x00, + 0x00, 0x02, 0x20, 0x01, 0xd0, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, + 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, + 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x2e, 0x00, 0x62, 0x00, + 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0xb0, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x1c, 0x00, 0x90, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, + 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, 0x6c, 0x00, 0x61, 0x00, 0x79, 0x00, + 0x6f, 0x00, 0x75, 0x00, 0x74, 0x00, 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, + 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, + 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, + 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, + 0x72, 0x00, 0x72, 0x00, 0x61, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x1c, 0x00, 0x34, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x64, 0x00, + 0x65, 0x00, 0x6e, 0x00, 0x73, 0x00, 0x69, 0x00, 0x74, 0x00, 0x79, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x60, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +unsigned int split_xxhdpi_v4_arsc_len = 780; diff --git a/libs/androidfw/tests/data/feature/build b/libs/androidfw/tests/data/feature/build index b547dc2..0f3307f 100755 --- a/libs/androidfw/tests/data/feature/build +++ b/libs/androidfw/tests/data/feature/build @@ -1,4 +1,19 @@ #!/bin/bash +# +# 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. +# aapt package -M AndroidManifest.xml -S res --feature-of ../basic/bundle.apk -F bundle.apk -f && \ unzip bundle.apk resources.arsc && \ diff --git a/libs/androidfw/tests/data/feature/feature_arsc.h b/libs/androidfw/tests/data/feature/feature_arsc.h index cf7647d..cd29910 100644 --- a/libs/androidfw/tests/data/feature/feature_arsc.h +++ b/libs/androidfw/tests/data/feature/feature_arsc.h @@ -1,11 +1,11 @@ unsigned char feature_arsc[] = { - 0x02, 0x00, 0x0c, 0x00, 0x40, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0x44, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf4, 0x02, 0x00, 0x00, + 0x34, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf8, 0x02, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, @@ -28,46 +28,46 @@ unsigned char feature_arsc[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x7c, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, - 0x2e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x3c, 0x00, 0x65, 0x00, 0x6d, 0x00, - 0x70, 0x00, 0x74, 0x00, 0x79, 0x00, 0x3e, 0x00, 0x00, 0x00, 0x04, 0x00, - 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00, 0x06, 0x00, - 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x67, 0x00, - 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00, - 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, - 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, 0x33, 0x00, - 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, - 0x34, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, - 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x6c, 0x00, 0x00, 0x00, - 0x07, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x07, 0x00, 0x3c, 0x00, + 0x65, 0x00, 0x6d, 0x00, 0x70, 0x00, 0x74, 0x00, 0x79, 0x00, 0x3e, 0x00, + 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, + 0x00, 0x00, 0x06, 0x00, 0x73, 0x00, 0x74, 0x00, 0x72, 0x00, 0x69, 0x00, + 0x6e, 0x00, 0x67, 0x00, 0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, + 0x74, 0x00, 0x65, 0x00, 0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x1c, 0x00, 0x58, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x1c, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, + 0x74, 0x00, 0x33, 0x00, 0x00, 0x00, 0x05, 0x00, 0x74, 0x00, 0x65, 0x00, + 0x73, 0x00, 0x74, 0x00, 0x34, 0x00, 0x00, 0x00, 0x07, 0x00, 0x6e, 0x00, + 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00, 0x33, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x03, - 0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x01, 0x02, 0x44, 0x00, 0x58, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10, - 0xc8, 0x00, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x08, 0x00, 0x00, 0x10, 0xc8, 0x00, 0x00, 0x00 }; -unsigned int feature_arsc_len = 832; +unsigned int feature_arsc_len = 836; diff --git a/libs/androidfw/tests/data/feature/res/values/values.xml b/libs/androidfw/tests/data/feature/res/values/values.xml index d03445a..343fd6c 100644 --- a/libs/androidfw/tests/data/feature/res/values/values.xml +++ b/libs/androidfw/tests/data/feature/res/values/values.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <string name="test3">test3</string> <string name="test4">test4</string> diff --git a/libs/androidfw/tests/data/lib/R.h b/libs/androidfw/tests/data/lib/R.h index 13bf095..ff31120 100644 --- a/libs/androidfw/tests/data/lib/R.h +++ b/libs/androidfw/tests/data/lib/R.h @@ -1,3 +1,19 @@ +/* + * 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. + */ + #ifndef __LIB_R_H #define __LIB_R_H diff --git a/libs/androidfw/tests/data/lib/build b/libs/androidfw/tests/data/lib/build index 8e6e70c..4102903 100755 --- a/libs/androidfw/tests/data/lib/build +++ b/libs/androidfw/tests/data/lib/build @@ -1,4 +1,19 @@ #!/bin/bash +# +# 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. +# aapt package -M AndroidManifest.xml -S res -F bundle.apk -f --shared-lib && \ unzip bundle.apk resources.arsc && \ diff --git a/libs/androidfw/tests/data/lib/lib_arsc.h b/libs/androidfw/tests/data/lib/lib_arsc.h index d670c5b..dd3dad5 100644 --- a/libs/androidfw/tests/data/lib/lib_arsc.h +++ b/libs/androidfw/tests/data/lib/lib_arsc.h @@ -1,8 +1,8 @@ unsigned char lib_arsc[] = { - 0x02, 0x00, 0x0c, 0x00, 0xc8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x0c, 0x00, 0xb8, 0x02, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xa0, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0x90, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, @@ -37,48 +37,25 @@ unsigned char lib_arsc[] = { 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x05, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x31, 0x00, 0x00, 0x00, 0x05, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00, 0x00, 0x00, - 0x03, 0x02, 0x0c, 0x00, 0x10, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x63, 0x00, 0x6f, 0x00, 0x6d, 0x00, 0x2e, 0x00, - 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00, 0x6f, 0x00, 0x69, 0x00, - 0x64, 0x00, 0x2e, 0x00, 0x74, 0x00, 0x65, 0x00, 0x73, 0x00, 0x74, 0x00, - 0x2e, 0x00, 0x62, 0x00, 0x61, 0x00, 0x73, 0x00, 0x69, 0x00, 0x63, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, - 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, - 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, 0x64, 0x00, 0x00, 0x00, - 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x48, 0x00, 0x00, 0x00, - 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00, + 0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x44, 0x00, + 0x64, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, - 0x08, 0x00, 0x00, 0x10, 0xbc, 0x02, 0x00, 0x00 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x08, 0x00, 0x00, 0x10, 0xbc, 0x02, 0x00, 0x00 }; -unsigned int lib_arsc_len = 968; +unsigned int lib_arsc_len = 696; diff --git a/libs/androidfw/tests/data/lib/res/values/values.xml b/libs/androidfw/tests/data/lib/res/values/values.xml index a77f0c7..3ec79b1 100644 --- a/libs/androidfw/tests/data/lib/res/values/values.xml +++ b/libs/androidfw/tests/data/lib/res/values/values.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <attr name="attr1" format="integer" /> diff --git a/libs/androidfw/tests/data/overlay/build b/libs/androidfw/tests/data/overlay/build index 87cf6de..f737677 100755 --- a/libs/androidfw/tests/data/overlay/build +++ b/libs/androidfw/tests/data/overlay/build @@ -1,4 +1,19 @@ #!/bin/bash +# +# 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. +# aapt package -M AndroidManifest.xml -S res -F bundle.apk -f && \ unzip bundle.apk resources.arsc && \ diff --git a/libs/androidfw/tests/data/overlay/res/values/values.xml b/libs/androidfw/tests/data/overlay/res/values/values.xml index 227e889..3e1af98 100644 --- a/libs/androidfw/tests/data/overlay/res/values/values.xml +++ b/libs/androidfw/tests/data/overlay/res/values/values.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <string name="test2">test2-overlay</string> <integer-array name="integerArray1"> diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h index 7a9d3db..27f25fe 100644 --- a/libs/androidfw/tests/data/system/R.h +++ b/libs/androidfw/tests/data/system/R.h @@ -1,3 +1,19 @@ +/* + * 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. + */ + #ifndef __ANDROID_R_H #define __ANDROID_R_H diff --git a/libs/androidfw/tests/data/system/build b/libs/androidfw/tests/data/system/build index 2a3ac0b..1a70e84 100755 --- a/libs/androidfw/tests/data/system/build +++ b/libs/androidfw/tests/data/system/build @@ -1,4 +1,19 @@ #!/bin/bash +# +# 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. +# aapt package -x -M AndroidManifest.xml -S res -F bundle.apk -f && \ unzip bundle.apk resources.arsc && \ diff --git a/libs/androidfw/tests/data/system/res/values/themes.xml b/libs/androidfw/tests/data/system/res/values/themes.xml index b29848e..35d43c7 100644 --- a/libs/androidfw/tests/data/system/res/values/themes.xml +++ b/libs/androidfw/tests/data/system/res/values/themes.xml @@ -1,4 +1,19 @@ <?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + <resources> <public name="background" type="attr" id="0x01010000"/> <public name="foreground" type="attr" id="0x01010001"/> diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp index a998594..fab4a1a 100644 --- a/libs/hwui/DeferredDisplayList.cpp +++ b/libs/hwui/DeferredDisplayList.cpp @@ -525,7 +525,7 @@ void DeferredDisplayList::addDrawOp(OpenGLRenderer& renderer, DrawOp* op) { deferInfo.mergeable &= !recordingComplexClip(); deferInfo.opaqueOverBounds &= !recordingComplexClip() && mSaveStack.isEmpty(); - if (CC_LIKELY(mAvoidOverdraw) && mBatches.size() && + if (mBatches.size() && state->mClipSideFlags != kClipSide_ConservativeFull && deferInfo.opaqueOverBounds && state->mBounds.contains(mBounds)) { // avoid overdraw by resetting drawing state + discarding drawing ops @@ -677,13 +677,12 @@ status_t DeferredDisplayList::flush(OpenGLRenderer& renderer, Rect& dirty) { DrawModifiers restoreDrawModifiers = renderer.getDrawModifiers(); renderer.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag); - if (CC_LIKELY(mAvoidOverdraw)) { - for (unsigned int i = 1; i < mBatches.size(); i++) { - if (mBatches[i] && mBatches[i]->coversBounds(mBounds)) { - discardDrawingBatches(i - 1); - } + for (unsigned int i = 1; i < mBatches.size(); i++) { + if (mBatches[i] && mBatches[i]->coversBounds(mBounds)) { + discardDrawingBatches(i - 1); } } + // NOTE: depth of the save stack at this point, before playback, should be reflected in // FLUSH_SAVE_STACK_DEPTH, so that save/restores match up correctly status |= replayBatchList(mBatches, renderer, dirty); diff --git a/libs/hwui/DeferredDisplayList.h b/libs/hwui/DeferredDisplayList.h index 8a015b2..885b411 100644 --- a/libs/hwui/DeferredDisplayList.h +++ b/libs/hwui/DeferredDisplayList.h @@ -81,8 +81,8 @@ public: class DeferredDisplayList { friend class DeferStateStruct; // used to give access to allocator public: - DeferredDisplayList(const Rect& bounds, bool avoidOverdraw = true) : - mBounds(bounds), mAvoidOverdraw(avoidOverdraw) { + DeferredDisplayList(const Rect& bounds) : + mBounds(bounds) { clear(); } ~DeferredDisplayList() { clear(); } @@ -150,7 +150,6 @@ private: // layer space bounds of rendering Rect mBounds; - const bool mAvoidOverdraw; /** * At defer time, stores the *defer time* savecount of save/saveLayer ops that were deferred, so diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h index cb3ef9b..d78c1cb 100644 --- a/libs/hwui/DisplayListOp.h +++ b/libs/hwui/DisplayListOp.h @@ -212,10 +212,13 @@ protected: // check state/paint for transparency if (mPaint) { + if (mPaint->getAlpha() != 0xFF) { + return false; + } if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) { return false; } - if (mPaint->getAlpha() != 0xFF) { + if (Renderer::isBlendedColorFilter(mPaint->getColorFilter())) { return false; } } diff --git a/libs/hwui/DrawProfiler.cpp b/libs/hwui/DrawProfiler.cpp index 2409554..e590642 100644 --- a/libs/hwui/DrawProfiler.cpp +++ b/libs/hwui/DrawProfiler.cpp @@ -22,7 +22,8 @@ #define DEFAULT_MAX_FRAMES 128 -#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == kNone)) return +#define RETURN_IF_PROFILING_DISABLED() if (CC_LIKELY(mType == kNone)) return +#define RETURN_IF_DISABLED() if (CC_LIKELY(mType == kNone && !mShowDirtyRegions)) return #define NANOS_TO_MILLIS_FLOAT(nanos) ((nanos) * 0.000001f) @@ -64,7 +65,9 @@ DrawProfiler::DrawProfiler() , mPreviousTime(0) , mVerticalUnit(0) , mHorizontalUnit(0) - , mThresholdStroke(0) { + , mThresholdStroke(0) + , mShowDirtyRegions(false) + , mFlashToggle(false) { setDensity(1); } @@ -82,27 +85,27 @@ void DrawProfiler::setDensity(float density) { } void DrawProfiler::startFrame(nsecs_t recordDurationNanos) { - RETURN_IF_DISABLED(); + RETURN_IF_PROFILING_DISABLED(); mData[mCurrentFrame].record = NANOS_TO_MILLIS_FLOAT(recordDurationNanos); mPreviousTime = systemTime(CLOCK_MONOTONIC); } void DrawProfiler::markPlaybackStart() { - RETURN_IF_DISABLED(); + RETURN_IF_PROFILING_DISABLED(); nsecs_t now = systemTime(CLOCK_MONOTONIC); mData[mCurrentFrame].prepare = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime); mPreviousTime = now; } void DrawProfiler::markPlaybackEnd() { - RETURN_IF_DISABLED(); + RETURN_IF_PROFILING_DISABLED(); nsecs_t now = systemTime(CLOCK_MONOTONIC); mData[mCurrentFrame].playback = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime); mPreviousTime = now; } void DrawProfiler::finishFrame() { - RETURN_IF_DISABLED(); + RETURN_IF_PROFILING_DISABLED(); nsecs_t now = systemTime(CLOCK_MONOTONIC); mData[mCurrentFrame].swapBuffers = NANOS_TO_MILLIS_FLOAT(now - mPreviousTime); mPreviousTime = now; @@ -114,19 +117,30 @@ void DrawProfiler::unionDirty(SkRect* dirty) { // Not worth worrying about minimizing the dirty region for debugging, so just // dirty the entire viewport. if (dirty) { + mDirtyRegion = *dirty; dirty->setEmpty(); } } void DrawProfiler::draw(OpenGLRenderer* canvas) { - if (CC_LIKELY(mType != kBars)) { - return; + RETURN_IF_DISABLED(); + + if (mShowDirtyRegions) { + mFlashToggle = !mFlashToggle; + if (mFlashToggle) { + SkPaint paint; + paint.setColor(0x7fff0000); + canvas->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop, + mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint); + } } - prepareShapes(canvas->getViewportHeight()); - drawGraph(canvas); - drawCurrentFrame(canvas); - drawThreshold(canvas); + if (mType == kBars) { + prepareShapes(canvas->getViewportHeight()); + drawGraph(canvas); + drawCurrentFrame(canvas); + drawThreshold(canvas); + } } void DrawProfiler::createData() { @@ -217,6 +231,7 @@ DrawProfiler::ProfileType DrawProfiler::loadRequestedProfileType() { } bool DrawProfiler::loadSystemProperties() { + bool changed = false; ProfileType newType = loadRequestedProfileType(); if (newType != mType) { mType = newType; @@ -225,13 +240,18 @@ bool DrawProfiler::loadSystemProperties() { } else { createData(); } - return true; + changed = true; } - return false; + bool showDirty = property_get_bool(PROPERTY_DEBUG_SHOW_DIRTY_REGIONS, false); + if (showDirty != mShowDirtyRegions) { + mShowDirtyRegions = showDirty; + changed = true; + } + return changed; } void DrawProfiler::dumpData(int fd) { - RETURN_IF_DISABLED(); + RETURN_IF_PROFILING_DISABLED(); // This method logs the last N frames (where N is <= mDataSize) since the // last call to dumpData(). In other words if there's a dumpData(), draw frame, diff --git a/libs/hwui/DrawProfiler.h b/libs/hwui/DrawProfiler.h index 7c06e5d..de64088 100644 --- a/libs/hwui/DrawProfiler.h +++ b/libs/hwui/DrawProfiler.h @@ -88,6 +88,10 @@ private: * information. */ float** mRects; + + bool mShowDirtyRegions; + SkRect mDirtyRegion; + bool mFlashToggle; }; } /* namespace uirenderer */ diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp index ce1d09f..19fc9a3 100755 --- a/libs/hwui/OpenGLRenderer.cpp +++ b/libs/hwui/OpenGLRenderer.cpp @@ -51,6 +51,21 @@ #define EVENT_LOGD(...) #endif +static void atraceFormatBegin(const char* fmt, ...) { + const int BUFFER_SIZE = 256; + va_list ap; + char buf[BUFFER_SIZE]; + + va_start(ap, fmt); + vsnprintf(buf, BUFFER_SIZE, fmt, ap); + va_end(ap); + + ATRACE_BEGIN(buf); +} + +#define ATRACE_FORMAT_BEGIN(fmt, ...) \ + if (CC_UNLIKELY(ATRACE_ENABLED())) atraceFormatBegin(fmt, ##__VA_ARGS__) + namespace android { namespace uirenderer { @@ -136,7 +151,6 @@ OpenGLRenderer::OpenGLRenderer(RenderState& renderState) , mScissorOptimizationDisabled(false) , mSuppressTiling(false) , mFirstFrameAfterResize(true) - , mCountOverdraw(false) , mLightCenter((Vector3){FLT_MIN, FLT_MIN, FLT_MIN}) , mLightRadius(FLT_MIN) , mAmbientShadowAlpha(0) @@ -251,7 +265,7 @@ void OpenGLRenderer::discardFramebuffer(float left, float top, float right, floa } status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) { - if (!opaque || mCountOverdraw) { + if (!opaque) { mCaches.enableScissor(); mCaches.setScissor(left, getViewportHeight() - bottom, right - left, bottom - top); glClear(GL_COLOR_BUFFER_BIT); @@ -332,10 +346,6 @@ void OpenGLRenderer::finish() { #endif } - if (mCountOverdraw) { - countOverdraw(); - } - mFrameStarted = false; } @@ -449,21 +459,6 @@ void OpenGLRenderer::renderOverdraw() { } } -void OpenGLRenderer::countOverdraw() { - size_t count = getWidth() * getHeight(); - uint32_t* buffer = new uint32_t[count]; - glReadPixels(0, 0, getWidth(), getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, &buffer[0]); - - size_t total = 0; - for (size_t i = 0; i < count; i++) { - total += buffer[i] & 0xff; - } - - mOverdraw = total / float(count); - - delete[] buffer; -} - /////////////////////////////////////////////////////////////////////////////// // Layers /////////////////////////////////////////////////////////////////////////////// @@ -537,17 +532,18 @@ void OpenGLRenderer::flushLayers() { // Note: it is very important to update the layers in order for (int i = 0; i < count; i++) { + Layer* layer = mLayerUpdates.itemAt(i); + sprintf(layerName, "Layer #%d", i); startMark(layerName); + ATRACE_FORMAT_BEGIN("flushLayer %ux%u", layer->getWidth(), layer->getHeight()); - ATRACE_BEGIN("flushLayer"); - Layer* layer = mLayerUpdates.itemAt(i); layer->flush(); + ATRACE_END(); + endMark(); mCaches.resourceCache.decrementRefcount(layer); - - endMark(); } mLayerUpdates.clear(); @@ -631,6 +627,7 @@ void OpenGLRenderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& if (restoreLayer) { endMark(); // Savelayer + ATRACE_END(); // SaveLayer startMark("ComposeLayer"); composeLayer(removed, restored); endMark(); @@ -814,6 +811,9 @@ bool OpenGLRenderer::createLayer(float left, float top, float right, float botto mSnapshot->flags |= Snapshot::kFlagIsLayer; mSnapshot->layer = layer; + ATRACE_FORMAT_BEGIN("%ssaveLayer %ux%u", + fboLayer ? "" : "unclipped ", + layer->getWidth(), layer->getHeight()); startMark("SaveLayer"); if (fboLayer) { return createFboLayer(layer, bounds, clip); @@ -1627,8 +1627,6 @@ void OpenGLRenderer::setupDraw(bool clearLayer) { mDescription.hasDebugHighlight = !mCaches.debugOverdraw && mCaches.debugStencilClip == Caches::kStencilShowHighlight && mCaches.stencil.isTestEnabled(); - - mDescription.emulateStencil = mCountOverdraw; } void OpenGLRenderer::setupDrawWithTexture(bool isAlpha8) { @@ -1714,13 +1712,6 @@ void OpenGLRenderer::accountForClear(SkXfermode::Mode mode) { } } -static bool isBlendedColorFilter(const SkColorFilter* filter) { - if (filter == NULL) { - return false; - } - return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0; -} - void OpenGLRenderer::setupDrawBlending(const Layer* layer, bool swapSrcDst) { SkXfermode::Mode mode = layer->getMode(); // When the blending mode is kClear_Mode, we need to use a modulate color @@ -1967,8 +1958,7 @@ status_t OpenGLRenderer::drawRenderNode(RenderNode* renderNode, Rect& dirty, int return status | replayStruct.mDrawGlStatus; } - bool avoidOverdraw = !mCaches.debugOverdraw && !mCountOverdraw; // shh, don't tell devs! - DeferredDisplayList deferredList(*currentClipRect(), avoidOverdraw); + DeferredDisplayList deferredList(*currentClipRect()); DeferStateStruct deferStruct(deferredList, *this, replayFlags); renderNode->defer(deferStruct, 0); @@ -3440,19 +3430,6 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, } mSkipOutlineClip = true; - if (mCountOverdraw) { - if (!mCaches.blend) glEnable(GL_BLEND); - if (mCaches.lastSrcMode != GL_ONE || mCaches.lastDstMode != GL_ONE) { - glBlendFunc(GL_ONE, GL_ONE); - } - - mCaches.blend = true; - mCaches.lastSrcMode = GL_ONE; - mCaches.lastDstMode = GL_ONE; - - return; - } - blend = blend || mode != SkXfermode::kSrcOver_Mode; if (blend) { diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h index 47ef1a9..c2c0b0e 100755 --- a/libs/hwui/OpenGLRenderer.h +++ b/libs/hwui/OpenGLRenderer.h @@ -136,14 +136,6 @@ public: virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque); virtual void finish(); - void setCountOverdrawEnabled(bool enabled) { - mCountOverdraw = enabled; - } - - float getOverdraw() { - return mCountOverdraw ? mOverdraw : 0.0f; - } - virtual status_t callDrawGLFunction(Functor* functor, Rect& dirty); void pushLayerUpdate(Layer* layer); @@ -1015,11 +1007,6 @@ private: bool mSuppressTiling; bool mFirstFrameAfterResize; - // If true, this renderer will setup drawing to emulate - // an increment stencil buffer in the color buffer - bool mCountOverdraw; - float mOverdraw; - bool mSkipOutlineClip; // Lighting + shadows diff --git a/libs/hwui/Program.h b/libs/hwui/Program.h index 56773f4..d05b331 100644 --- a/libs/hwui/Program.h +++ b/libs/hwui/Program.h @@ -84,8 +84,7 @@ namespace uirenderer { #define PROGRAM_HAS_COLORS 42 #define PROGRAM_HAS_DEBUG_HIGHLIGHT 43 -#define PROGRAM_EMULATE_STENCIL 44 -#define PROGRAM_HAS_ROUND_RECT_CLIP 45 +#define PROGRAM_HAS_ROUND_RECT_CLIP 44 /////////////////////////////////////////////////////////////////////////////// // Types @@ -161,7 +160,6 @@ struct ProgramDescription { float gamma; bool hasDebugHighlight; - bool emulateStencil; bool hasRoundRectClip; /** @@ -204,7 +202,6 @@ struct ProgramDescription { gamma = 2.2f; hasDebugHighlight = false; - emulateStencil = false; hasRoundRectClip = false; } @@ -272,7 +269,6 @@ struct ProgramDescription { if (isSimpleGradient) key |= programid(0x1) << PROGRAM_IS_SIMPLE_GRADIENT; if (hasColors) key |= programid(0x1) << PROGRAM_HAS_COLORS; if (hasDebugHighlight) key |= programid(0x1) << PROGRAM_HAS_DEBUG_HIGHLIGHT; - if (emulateStencil) key |= programid(0x1) << PROGRAM_EMULATE_STENCIL; if (hasRoundRectClip) key |= programid(0x1) << PROGRAM_HAS_ROUND_RECT_CLIP; return key; } diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp index 06353c0..62835e0 100644 --- a/libs/hwui/ProgramCache.cpp +++ b/libs/hwui/ProgramCache.cpp @@ -347,12 +347,6 @@ const char* gFS_Main_FragColor_HasRoundRectClip = const char* gFS_Main_DebugHighlight = " gl_FragColor.rgb = vec3(0.0, gl_FragColor.a, 0.0);\n"; -const char* gFS_Main_EmulateStencil = - " gl_FragColor.rgba = vec4(1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0, 1.0);\n" - " return;\n" - " /*\n"; -const char* gFS_Footer_EmulateStencil = - " */\n"; const char* gFS_Footer = "}\n\n"; @@ -617,7 +611,6 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti && !description.hasColors && description.colorOp == ProgramDescription::kColorNone && !description.hasDebugHighlight - && !description.emulateStencil && !description.hasRoundRectClip) { bool fast = false; @@ -698,9 +691,6 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti // Begin the shader shader.append(gFS_Main); { - if (description.emulateStencil) { - shader.append(gFS_Main_EmulateStencil); - } // Stores the result in fragColor directly if (description.hasTexture || description.hasExternalTexture) { if (description.hasAlpha8Texture) { @@ -779,9 +769,6 @@ String8 ProgramCache::generateFragmentShader(const ProgramDescription& descripti shader.append(gFS_Main_DebugHighlight); } } - if (description.emulateStencil) { - shader.append(gFS_Footer_EmulateStencil); - } // End the shader shader.append(gFS_Footer); diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h index 7eb9a32..befed16 100644 --- a/libs/hwui/Properties.h +++ b/libs/hwui/Properties.h @@ -133,6 +133,15 @@ enum DebugLevel { #define PROPERTY_DEBUG_STENCIL_CLIP "debug.hwui.show_non_rect_clip" /** + * Turn on to draw dirty regions every other frame. + * + * Possible values: + * "true", to enable dirty regions debugging + * "false", to disable dirty regions debugging + */ +#define PROPERTY_DEBUG_SHOW_DIRTY_REGIONS "debug.hwui.show_dirty_regions" + +/** * Disables draw operation deferral if set to "true", forcing draw * commands to be issued to OpenGL in order, and processed in sequence * with state-manipulation canvas commands. diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp index 254492f..40cd13e 100644 --- a/libs/hwui/RenderNode.cpp +++ b/libs/hwui/RenderNode.cpp @@ -50,10 +50,13 @@ void RenderNode::outputLogBuffer(int fd) { fprintf(file, "\nRecent DisplayList operations\n"); logBuffer.outputCommands(file); - String8 cachesLog; - Caches::getInstance().dumpMemoryUsage(cachesLog); - fprintf(file, "\nCaches:\n%s", cachesLog.string()); - fprintf(file, "\n"); + if (Caches::hasInstance()) { + String8 cachesLog; + Caches::getInstance().dumpMemoryUsage(cachesLog); + fprintf(file, "\nCaches:\n%s\n", cachesLog.string()); + } else { + fprintf(file, "\nNo caches instance.\n"); + } fflush(file); } @@ -293,6 +296,9 @@ void RenderNode::pushStagingDisplayListChanges(TreeInfo& info) { mStagingDisplayListData->children()[i]->mRenderNode->incParentRefCount(); } } + // Damage with the old display list first then the new one to catch any + // changes in isRenderable or, in the future, bounds + damageSelf(info); deleteDisplayListData(); mDisplayListData = mStagingDisplayListData; mStagingDisplayListData = NULL; diff --git a/libs/hwui/Renderer.h b/libs/hwui/Renderer.h index 9cedd5a..a2f8c05 100644 --- a/libs/hwui/Renderer.h +++ b/libs/hwui/Renderer.h @@ -17,12 +17,13 @@ #ifndef ANDROID_HWUI_RENDERER_H #define ANDROID_HWUI_RENDERER_H +#include <SkColorFilter.h> +#include <SkPaint.h> #include <SkRegion.h> #include <utils/String8.h> #include "AssetAtlas.h" -#include "SkPaint.h" namespace android { @@ -81,6 +82,14 @@ public: && !paint.getColorFilter() && getXfermode(paint.getXfermode()) == SkXfermode::kSrcOver_Mode; } + + static bool isBlendedColorFilter(const SkColorFilter* filter) { + if (filter == NULL) { + return false; + } + return (filter->getFlags() & SkColorFilter::kAlphaUnchanged_Flag) == 0; + } + // ---------------------------------------------------------------------------- // Frame state operations // ---------------------------------------------------------------------------- diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp index dbedf94..df28ae8 100644 --- a/libs/hwui/SpotShadow.cpp +++ b/libs/hwui/SpotShadow.cpp @@ -60,7 +60,7 @@ namespace android { namespace uirenderer { -static const double EPSILON = 1e-7; +static const float EPSILON = 1e-7; /** * For each polygon's vertex, the light center will project it to the receiver @@ -118,17 +118,17 @@ static float rayIntersectPoints(const Vector2& rayOrigin, float dx, float dy, // intersection point should stay on both the ray and the edge of (p1, p2). // solve([p1x+t*(p2x-p1x)=dx*t2+px,p1y+t*(p2y-p1y)=dy*t2+py],[t,t2]); - double divisor = (dx * (p1.y - p2.y) + dy * p2.x - dy * p1.x); + float divisor = (dx * (p1.y - p2.y) + dy * p2.x - dy * p1.x); if (divisor == 0) return -1.0f; // error, invalid divisor #if DEBUG_SHADOW - double interpVal = (dx * (p1.y - rayOrigin.y) + dy * rayOrigin.x - dy * p1.x) / divisor; + float interpVal = (dx * (p1.y - rayOrigin.y) + dy * rayOrigin.x - dy * p1.x) / divisor; if (interpVal < 0 || interpVal > 1) { ALOGW("rayIntersectPoints is hitting outside the segment %f", interpVal); } #endif - double distance = (p1.x * (rayOrigin.y - p2.y) + p2.x * (p1.y - rayOrigin.y) + + float distance = (p1.x * (rayOrigin.y - p2.y) + p2.x * (p1.y - rayOrigin.y) + rayOrigin.x * (p2.y - p1.y)) / divisor; return distance; // may be negative in error cases @@ -217,146 +217,12 @@ int SpotShadow::hull(Vector2* points, int pointsLength, Vector2* retPoly) { * * @return true if a right hand turn */ -bool SpotShadow::ccw(double ax, double ay, double bx, double by, - double cx, double cy) { +bool SpotShadow::ccw(float ax, float ay, float bx, float by, + float cx, float cy) { return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax) > EPSILON; } /** - * Calculates the intersection of poly1 with poly2 and put in poly2. - * Note that both poly1 and poly2 must be in CW order already! - * - * @param poly1 The 1st polygon, as a Vector2 array. - * @param poly1Length The number of vertices of 1st polygon. - * @param poly2 The 2nd and output polygon, as a Vector2 array. - * @param poly2Length The number of vertices of 2nd polygon. - * @return number of vertices in output polygon as poly2. - */ -int SpotShadow::intersection(const Vector2* poly1, int poly1Length, - Vector2* poly2, int poly2Length) { -#if DEBUG_SHADOW - if (!ShadowTessellator::isClockwise(poly1, poly1Length)) { - ALOGW("Poly1 is not clockwise! Intersection is wrong!"); - } - if (!ShadowTessellator::isClockwise(poly2, poly2Length)) { - ALOGW("Poly2 is not clockwise! Intersection is wrong!"); - } -#endif - Vector2 poly[poly1Length * poly2Length + 2]; - int count = 0; - int pcount = 0; - - // If one vertex from one polygon sits inside another polygon, add it and - // count them. - for (int i = 0; i < poly1Length; i++) { - if (testPointInsidePolygon(poly1[i], poly2, poly2Length)) { - poly[count] = poly1[i]; - count++; - pcount++; - - } - } - - int insidePoly2 = pcount; - for (int i = 0; i < poly2Length; i++) { - if (testPointInsidePolygon(poly2[i], poly1, poly1Length)) { - poly[count] = poly2[i]; - count++; - } - } - - int insidePoly1 = count - insidePoly2; - // If all vertices from poly1 are inside poly2, then just return poly1. - if (insidePoly2 == poly1Length) { - memcpy(poly2, poly1, poly1Length * sizeof(Vector2)); - return poly1Length; - } - - // If all vertices from poly2 are inside poly1, then just return poly2. - if (insidePoly1 == poly2Length) { - return poly2Length; - } - - // Since neither polygon fully contain the other one, we need to add all the - // intersection points. - Vector2 intersection = {0, 0}; - for (int i = 0; i < poly2Length; i++) { - for (int j = 0; j < poly1Length; j++) { - int poly2LineStart = i; - int poly2LineEnd = ((i + 1) % poly2Length); - int poly1LineStart = j; - int poly1LineEnd = ((j + 1) % poly1Length); - bool found = lineIntersection( - poly2[poly2LineStart].x, poly2[poly2LineStart].y, - poly2[poly2LineEnd].x, poly2[poly2LineEnd].y, - poly1[poly1LineStart].x, poly1[poly1LineStart].y, - poly1[poly1LineEnd].x, poly1[poly1LineEnd].y, - intersection); - if (found) { - poly[count].x = intersection.x; - poly[count].y = intersection.y; - count++; - } else { - Vector2 delta = poly2[i] - poly1[j]; - if (delta.lengthSquared() < EPSILON) { - poly[count] = poly2[i]; - count++; - } - } - } - } - - if (count == 0) { - return 0; - } - - // Sort the result polygon around the center. - Vector2 center = {0.0f, 0.0f}; - for (int i = 0; i < count; i++) { - center += poly[i]; - } - center /= count; - sort(poly, count, center); - -#if DEBUG_SHADOW - // Since poly2 is overwritten as the result, we need to save a copy to do - // our verification. - Vector2 oldPoly2[poly2Length]; - int oldPoly2Length = poly2Length; - memcpy(oldPoly2, poly2, sizeof(Vector2) * poly2Length); -#endif - - // Filter the result out from poly and put it into poly2. - poly2[0] = poly[0]; - int lastOutputIndex = 0; - for (int i = 1; i < count; i++) { - Vector2 delta = poly[i] - poly2[lastOutputIndex]; - if (delta.lengthSquared() >= EPSILON) { - poly2[++lastOutputIndex] = poly[i]; - } else { - // If the vertices are too close, pick the inner one, because the - // inner one is more likely to be an intersection point. - Vector2 delta1 = poly[i] - center; - Vector2 delta2 = poly2[lastOutputIndex] - center; - if (delta1.lengthSquared() < delta2.lengthSquared()) { - poly2[lastOutputIndex] = poly[i]; - } - } - } - int resultLength = lastOutputIndex + 1; - -#if DEBUG_SHADOW - testConvex(poly2, resultLength, "intersection"); - testConvex(poly1, poly1Length, "input poly1"); - testConvex(oldPoly2, oldPoly2Length, "input poly2"); - - testIntersection(poly1, poly1Length, oldPoly2, oldPoly2Length, poly2, resultLength); -#endif - - return resultLength; -} - -/** * Sort points about a center point * * @param poly The in and out polyogon as a Vector2 array. @@ -441,13 +307,13 @@ void SpotShadow::quicksortX(Vector2* points, int low, int high) { bool SpotShadow::testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len) { bool c = false; - double testx = testPoint.x; - double testy = testPoint.y; + float testx = testPoint.x; + float testy = testPoint.y; for (int i = 0, j = len - 1; i < len; j = i++) { - double startX = poly[j].x; - double startY = poly[j].y; - double endX = poly[i].x; - double endY = poly[i].y; + float startX = poly[j].x; + float startY = poly[j].y; + float endX = poly[i].x; + float endY = poly[i].y; if (((endY > testy) != (startY > testy)) && (testx < (startX - endX) * (testy - endY) @@ -490,46 +356,6 @@ void SpotShadow::reverse(Vector2* polygon, int len) { } /** - * Intersects two lines in parametric form. This function is called in a tight - * loop, and we need double precision to get things right. - * - * @param x1 the x coordinate point 1 of line 1 - * @param y1 the y coordinate point 1 of line 1 - * @param x2 the x coordinate point 2 of line 1 - * @param y2 the y coordinate point 2 of line 1 - * @param x3 the x coordinate point 1 of line 2 - * @param y3 the y coordinate point 1 of line 2 - * @param x4 the x coordinate point 2 of line 2 - * @param y4 the y coordinate point 2 of line 2 - * @param ret the x,y location of the intersection - * @return true if it found an intersection - */ -inline bool SpotShadow::lineIntersection(double x1, double y1, double x2, double y2, - double x3, double y3, double x4, double y4, Vector2& ret) { - double d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); - if (d == 0.0) return false; - - double dx = (x1 * y2 - y1 * x2); - double dy = (x3 * y4 - y3 * x4); - double x = (dx * (x3 - x4) - (x1 - x2) * dy) / d; - double y = (dx * (y3 - y4) - (y1 - y2) * dy) / d; - - // The intersection should be in the middle of the point 1 and point 2, - // likewise point 3 and point 4. - if (((x - x1) * (x - x2) > EPSILON) - || ((x - x3) * (x - x4) > EPSILON) - || ((y - y1) * (y - y2) > EPSILON) - || ((y - y3) * (y - y4) > EPSILON)) { - // Not interesected - return false; - } - ret.x = x; - ret.y = y; - return true; - -} - -/** * Compute a horizontal circular polygon about point (x , y , height) of radius * (size) * @@ -542,7 +368,7 @@ void SpotShadow::computeLightPolygon(int points, const Vector3& lightCenter, float size, Vector3* ret) { // TODO: Caching all the sin / cos values and store them in a look up table. for (int i = 0; i < points; i++) { - double angle = 2 * i * M_PI / points; + float angle = 2 * i * M_PI / points; ret[i].x = cosf(angle) * size + lightCenter.x; ret[i].y = sinf(angle) * size + lightCenter.y; ret[i].z = lightCenter.z; @@ -853,21 +679,6 @@ bool convertPolyToRayDist(const Vector2* poly, int polyLength, const Vector2& po return true; } -int SpotShadow::calculateOccludedUmbra(const Vector2* umbra, int umbraLength, - const Vector3* poly, int polyLength, Vector2* occludedUmbra) { - // Occluded umbra area is computed as the intersection of the projected 2D - // poly and umbra. - for (int i = 0; i < polyLength; i++) { - occludedUmbra[i].x = poly[i].x; - occludedUmbra[i].y = poly[i].y; - } - - // Both umbra and incoming polygon are guaranteed to be CW, so we can call - // intersection() directly. - return intersection(umbra, umbraLength, - occludedUmbra, polyLength); -} - /** * This is only for experimental purpose. * After intersections are calculated, we could smooth the polygon if needed. @@ -1585,8 +1396,8 @@ bool SpotShadow::testConvex(const Vector2* polygon, int polygonLength, Vector2 middle = polygon[(i + 1) % polygonLength]; Vector2 end = polygon[(i + 2) % polygonLength]; - double delta = (double(middle.x) - start.x) * (double(end.y) - start.y) - - (double(middle.y) - start.y) * (double(end.x) - start.x); + float delta = (float(middle.x) - start.x) * (float(end.y) - start.y) - + (float(middle.y) - start.y) * (float(end.x) - start.x); bool isCCWOrCoLinear = (delta >= EPSILON); if (isCCWOrCoLinear) { @@ -1621,8 +1432,8 @@ void SpotShadow::testIntersection(const Vector2* poly1, int poly1Length, bool dumpPoly = false; for (int k = 0; k < TEST_POINT_NUMBER; k++) { // Generate a random point between minX, minY and maxX, maxY. - double randomX = rand() / double(RAND_MAX); - double randomY = rand() / double(RAND_MAX); + float randomX = rand() / float(RAND_MAX); + float randomY = rand() / float(RAND_MAX); Vector2 testPoint; testPoint.x = lowerBound.x + randomX * (upperBound.x - lowerBound.x); diff --git a/libs/hwui/SpotShadow.h b/libs/hwui/SpotShadow.h index 23fdca9..6fa2028 100644 --- a/libs/hwui/SpotShadow.h +++ b/libs/hwui/SpotShadow.h @@ -35,8 +35,6 @@ private: static float projectCasterToOutline(Vector2& outline, const Vector3& lightCenter, const Vector3& polyVertex); - static int calculateOccludedUmbra(const Vector2* umbra, int umbraLength, - const Vector3* poly, int polyLength, Vector2* occludedUmbra); static int setupAngleList(VertexAngleData* angleDataList, int polyLength, const Vector2* polygon, const Vector2& centroid, @@ -81,8 +79,7 @@ private: static void xsort(Vector2* points, int pointsLength); static int hull(Vector2* points, int pointsLength, Vector2* retPoly); - static bool ccw(double ax, double ay, double bx, double by, double cx, double cy); - static int intersection(const Vector2* poly1, int poly1length, Vector2* poly2, int poly2length); + static bool ccw(float ax, float ay, float bx, float by, float cx, float cy); static void sort(Vector2* poly, int polyLength, const Vector2& center); static void swap(Vector2* points, int i, int j); @@ -92,8 +89,6 @@ private: static bool testPointInsidePolygon(const Vector2 testPoint, const Vector2* poly, int len); static void makeClockwise(Vector2* polygon, int len); static void reverse(Vector2* polygon, int len); - static inline bool lineIntersection(double x1, double y1, double x2, double y2, - double x3, double y3, double x4, double y4, Vector2& ret); static void generateTriangleStrip(bool isCasterOpaque, float shadowStrengthScale, Vector2* penumbra, int penumbraLength, Vector2* umbra, int umbraLength, diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp index b50a433..9d2ae8b 100644 --- a/libs/hwui/renderthread/CanvasContext.cpp +++ b/libs/hwui/renderthread/CanvasContext.cpp @@ -42,7 +42,8 @@ CanvasContext::CanvasContext(RenderThread& thread, bool translucent, : mRenderThread(thread) , mEglManager(thread.eglManager()) , mEglSurface(EGL_NO_SURFACE) - , mDirtyRegionsEnabled(false) + , mBufferPreserved(false) + , mSwapBehavior(kSwap_default) , mOpaque(!translucent) , mCanvas(NULL) , mHaveNewSurface(false) @@ -82,7 +83,8 @@ void CanvasContext::setSurface(ANativeWindow* window) { } if (mEglSurface != EGL_NO_SURFACE) { - mDirtyRegionsEnabled = mEglManager.enableDirtyRegions(mEglSurface); + const bool preserveBuffer = (mSwapBehavior != kSwap_discardBuffer); + mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer); mHaveNewSurface = true; makeCurrent(); } else { @@ -103,6 +105,10 @@ void CanvasContext::requireSurface() { makeCurrent(); } +void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) { + mSwapBehavior = swapBehavior; +} + bool CanvasContext::initialize(ANativeWindow* window) { setSurface(window); if (mCanvas) return false; @@ -200,7 +206,7 @@ void CanvasContext::draw() { if (width != mCanvas->getViewportWidth() || height != mCanvas->getViewportHeight()) { mCanvas->setViewport(width, height); dirty.setEmpty(); - } else if (!mDirtyRegionsEnabled || mHaveNewSurface) { + } else if (!mBufferPreserved || mHaveNewSurface) { dirty.setEmpty(); } else { if (!dirty.isEmpty() && !dirty.intersect(0, 0, width, height)) { @@ -330,6 +336,7 @@ void CanvasContext::trimMemory(RenderThread& thread, int level) { // No context means nothing to free if (!thread.eglManager().hasEglContext()) return; + ATRACE_CALL(); thread.eglManager().requireGlContext(); if (level >= TRIM_MEMORY_COMPLETE) { Caches::getInstance().flush(Caches::kFlushMode_Full); diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h index d4282fa..e20564b 100644 --- a/libs/hwui/renderthread/CanvasContext.h +++ b/libs/hwui/renderthread/CanvasContext.h @@ -48,6 +48,11 @@ namespace renderthread { class EglManager; +enum SwapBehavior { + kSwap_default, + kSwap_discardBuffer, +}; + // This per-renderer class manages the bridge between the global EGL context // and the render surface. // TODO: Rename to Renderer or some other per-window, top-level manager @@ -57,6 +62,9 @@ public: IContextFactory* contextFactory); virtual ~CanvasContext(); + // Won't take effect until next EGLSurface creation + void setSwapBehavior(SwapBehavior swapBehavior); + bool initialize(ANativeWindow* window); void updateSurface(ANativeWindow* window); void pauseSurface(ANativeWindow* window); @@ -111,7 +119,8 @@ private: EglManager& mEglManager; sp<ANativeWindow> mNativeWindow; EGLSurface mEglSurface; - bool mDirtyRegionsEnabled; + bool mBufferPreserved; + SwapBehavior mSwapBehavior; bool mOpaque; OpenGLRenderer* mCanvas; diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp index a87834e..760fc15 100644 --- a/libs/hwui/renderthread/EglManager.cpp +++ b/libs/hwui/renderthread/EglManager.cpp @@ -70,12 +70,12 @@ EglManager::EglManager(RenderThread& thread) , mEglConfig(0) , mEglContext(EGL_NO_CONTEXT) , mPBufferSurface(EGL_NO_SURFACE) - , mRequestDirtyRegions(load_dirty_regions_property()) + , mAllowPreserveBuffer(load_dirty_regions_property()) , mCurrentSurface(EGL_NO_SURFACE) , mAtlasMap(NULL) , mAtlasMapSize(0) { - mCanSetDirtyRegions = mRequestDirtyRegions; - ALOGD("Render dirty regions requested: %s", mRequestDirtyRegions ? "true" : "false"); + mCanSetPreserveBuffer = mAllowPreserveBuffer; + ALOGD("Use EGL_SWAP_BEHAVIOR_PRESERVED: %s", mAllowPreserveBuffer ? "true" : "false"); } void EglManager::initialize() { @@ -113,7 +113,7 @@ void EglManager::requireGlContext() { } void EglManager::loadConfig() { - EGLint swapBehavior = mCanSetDirtyRegions ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; + EGLint swapBehavior = mCanSetPreserveBuffer ? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0; EGLint attribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_RED_SIZE, 8, @@ -131,10 +131,10 @@ void EglManager::loadConfig() { if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs) || num_configs != 1) { // Failed to get a valid config - if (mCanSetDirtyRegions) { + if (mCanSetPreserveBuffer) { ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without..."); // Try again without dirty regions enabled - mCanSetDirtyRegions = false; + mCanSetPreserveBuffer = false; loadConfig(); } else { LOG_ALWAYS_FATAL("Failed to choose config, error = %s", egl_error_str()); @@ -273,25 +273,30 @@ bool EglManager::swapBuffers(EGLSurface surface) { return false; } -bool EglManager::enableDirtyRegions(EGLSurface surface) { - if (!mRequestDirtyRegions) return false; +bool EglManager::setPreserveBuffer(EGLSurface surface, bool preserve) { + if (CC_UNLIKELY(!mAllowPreserveBuffer)) return false; - if (mCanSetDirtyRegions) { - if (!eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) { + bool preserved = false; + if (mCanSetPreserveBuffer) { + preserved = eglSurfaceAttrib(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, + preserve ? EGL_BUFFER_PRESERVED : EGL_BUFFER_DESTROYED); + if (CC_UNLIKELY(!preserved)) { ALOGW("Failed to set EGL_SWAP_BEHAVIOR on surface %p, error=%s", (void*) surface, egl_error_str()); - return false; } - return true; } - // Perhaps it is already enabled? - EGLint value; - if (!eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &value)) { - ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p", - (void*) surface, egl_error_str()); - return false; + if (CC_UNLIKELY(!preserved)) { + // Maybe it's already set? + EGLint swapBehavior; + if (eglQuerySurface(mEglDisplay, surface, EGL_SWAP_BEHAVIOR, &swapBehavior)) { + preserved = (swapBehavior == EGL_BUFFER_PRESERVED); + } else { + ALOGW("Failed to query EGL_SWAP_BEHAVIOR on surface %p, error=%p", + (void*) surface, egl_error_str()); + } } - return value == EGL_BUFFER_PRESERVED; + + return preserved; } } /* namespace renderthread */ diff --git a/libs/hwui/renderthread/EglManager.h b/libs/hwui/renderthread/EglManager.h index 71213fb..ae03ea1 100644 --- a/libs/hwui/renderthread/EglManager.h +++ b/libs/hwui/renderthread/EglManager.h @@ -49,7 +49,8 @@ public: void beginFrame(EGLSurface surface, EGLint* width, EGLint* height); bool swapBuffers(EGLSurface surface); - bool enableDirtyRegions(EGLSurface surface); + // Returns true iff the surface is now preserving buffers. + bool setPreserveBuffer(EGLSurface surface, bool preserve); void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t mapSize); @@ -71,8 +72,8 @@ private: EGLContext mEglContext; EGLSurface mPBufferSurface; - const bool mRequestDirtyRegions; - bool mCanSetDirtyRegions; + const bool mAllowPreserveBuffer; + bool mCanSetPreserveBuffer; EGLSurface mCurrentSurface; diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp index 047819d..8f99b4e 100644 --- a/libs/hwui/renderthread/RenderProxy.cpp +++ b/libs/hwui/renderthread/RenderProxy.cpp @@ -103,6 +103,18 @@ void RenderProxy::setFrameInterval(nsecs_t frameIntervalNanos) { post(task); } +CREATE_BRIDGE2(setSwapBehavior, CanvasContext* context, SwapBehavior swapBehavior) { + args->context->setSwapBehavior(args->swapBehavior); + return NULL; +} + +void RenderProxy::setSwapBehavior(SwapBehavior swapBehavior) { + SETUP_TASK(setSwapBehavior); + args->context = mContext; + args->swapBehavior = swapBehavior; + post(task); +} + CREATE_BRIDGE1(loadSystemProperties, CanvasContext* context) { bool needsRedraw = false; if (Caches::hasInstance()) { diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h index 678e7e2..dddf0c7 100644 --- a/libs/hwui/renderthread/RenderProxy.h +++ b/libs/hwui/renderthread/RenderProxy.h @@ -31,6 +31,7 @@ #include "../Caches.h" #include "../IContextFactory.h" +#include "CanvasContext.h" #include "DrawFrameTask.h" namespace android { @@ -44,7 +45,6 @@ class Rect; namespace renderthread { -class CanvasContext; class ErrorChannel; class RenderThread; class RenderProxyBridge; @@ -63,6 +63,8 @@ public: ANDROID_API virtual ~RenderProxy(); ANDROID_API void setFrameInterval(nsecs_t frameIntervalNanos); + // Won't take effect until next EGLSurface creation + ANDROID_API void setSwapBehavior(SwapBehavior swapBehavior); ANDROID_API bool loadSystemProperties(); ANDROID_API bool initialize(const sp<ANativeWindow>& window); diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp index cf3d039..9bd4eae 100644 --- a/libs/hwui/renderthread/TimeLord.cpp +++ b/libs/hwui/renderthread/TimeLord.cpp @@ -20,7 +20,7 @@ namespace uirenderer { namespace renderthread { TimeLord::TimeLord() - : mFrameIntervalNanos(0) + : mFrameIntervalNanos(milliseconds_to_nanoseconds(16)) , mFrameTimeNanos(0) { } diff --git a/libs/hwui/tests/Android.mk b/libs/hwui/tests/Android.mk new file mode 100644 index 0000000..9622073 --- /dev/null +++ b/libs/hwui/tests/Android.mk @@ -0,0 +1,55 @@ +# +# 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. +# + +local_target_dir := $(TARGET_OUT_DATA)/local/tmp +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_CFLAGS += -DUSE_OPENGL_RENDERER -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES +LOCAL_CFLAGS += -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\" + +LOCAL_SRC_FILES:= \ + TestContext.cpp \ + main.cpp + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH)/.. \ + external/skia/src/core + +LOCAL_SHARED_LIBRARIES := \ + liblog \ + libcutils \ + libutils \ + libskia \ + libgui \ + libui \ + libhwui + +ifeq ($(WITH_MALLOC_LEAK_CHECK),true) + LOCAL_CFLAGS += -DMALLOC_LEAK_CHECK +endif + +LOCAL_MODULE_PATH := $(local_target_dir) +LOCAL_MODULE:= hwuitest +LOCAL_MODULE_TAGS := tests +LOCAL_MULTILIB := both +LOCAL_MODULE_STEM_32 := hwuitest +LOCAL_MODULE_STEM_64 := hwuitest64 + +include external/stlport/libstlport.mk +include $(BUILD_EXECUTABLE) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/libs/hwui/tests/TestContext.cpp b/libs/hwui/tests/TestContext.cpp new file mode 100644 index 0000000..35e402d --- /dev/null +++ b/libs/hwui/tests/TestContext.cpp @@ -0,0 +1,45 @@ +/* + * 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. + */ + +#include "TestContext.h" + +#include <gui/ISurfaceComposer.h> +#include <gui/SurfaceComposerClient.h> + +using namespace android; + +DisplayInfo gDisplay; +sp<SurfaceComposerClient> gSession; + +void createTestEnvironment() { + gSession = new SurfaceComposerClient(); + sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay( + ISurfaceComposer::eDisplayIdMain)); + status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &gDisplay); + LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n"); +} + +sp<SurfaceControl> createWindow(int width, int height) { + sp<SurfaceControl> control = gSession->createSurface(String8("HwuiTest"), + width, height, PIXEL_FORMAT_RGBX_8888); + + SurfaceComposerClient::openGlobalTransaction(); + control->setLayer(0x7FFFFFF); + control->show(); + SurfaceComposerClient::closeGlobalTransaction(); + + return control; +} diff --git a/libs/hwui/tests/TestContext.h b/libs/hwui/tests/TestContext.h new file mode 100644 index 0000000..8a5d530 --- /dev/null +++ b/libs/hwui/tests/TestContext.h @@ -0,0 +1,33 @@ +/* + * 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. + */ + +#ifndef TESTCONTEXT_H +#define TESTCONTEXT_H + +#include <ui/DisplayInfo.h> +#include <gui/SurfaceControl.h> + +extern android::DisplayInfo gDisplay; +#define dp(x) ((x) * gDisplay.density) + +// Initializes all the static globals that are shared across all contexts +// such as display info +void createTestEnvironment(); + +// Defaults to fullscreen +android::sp<android::SurfaceControl> createWindow(int width = -1, int height = -1); + +#endif diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp new file mode 100644 index 0000000..2d99e9f --- /dev/null +++ b/libs/hwui/tests/main.cpp @@ -0,0 +1,131 @@ +/* + * 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. + */ + +#include <stdio.h> + +#include <cutils/log.h> +#include <gui/Surface.h> +#include <ui/PixelFormat.h> + +#include <AnimationContext.h> +#include <DisplayListRenderer.h> +#include <RenderNode.h> +#include <renderthread/RenderProxy.h> + +#include "TestContext.h" + +using namespace android; +using namespace android::uirenderer; +using namespace android::uirenderer::renderthread; + +class ContextFactory : public IContextFactory { +public: + virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) { + return new AnimationContext(clock); + } +}; + +static DisplayListRenderer* startRecording(RenderNode* node) { + DisplayListRenderer* renderer = new DisplayListRenderer(); + renderer->setViewport(node->getWidth(), node->getHeight()); + renderer->prepare(false); + return renderer; +} + +static void endRecording(DisplayListRenderer* renderer, RenderNode* node) { + renderer->finish(); + node->setStagingDisplayList(renderer->finishRecording()); + delete renderer; +} + +sp<RenderNode> createCard(int x, int y, int width, int height) { + sp<RenderNode> node = new RenderNode(); + node->mutateStagingProperties().setLeftTopRightBottom(x, y, x + width, y + height); + node->mutateStagingProperties().setElevation(dp(16)); + node->mutateStagingProperties().mutableOutline().setRoundRect(0, 0, width, height, dp(10), 1); + node->mutateStagingProperties().mutableOutline().setShouldClip(true); + node->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y | RenderNode::Z); + + DisplayListRenderer* renderer = startRecording(node.get()); + renderer->drawColor(0xFFEEEEEE, SkXfermode::kSrcOver_Mode); + endRecording(renderer, node.get()); + + return node; +} + +int main(int argc, char* argv[]) { + createTestEnvironment(); + + // create the native surface + const int width = gDisplay.w; + const int height = gDisplay.h; + sp<SurfaceControl> control = createWindow(width, height); + sp<Surface> surface = control->getSurface(); + + RenderNode* rootNode = new RenderNode(); + rootNode->incStrong(0); + rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, width, height); + rootNode->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + rootNode->mutateStagingProperties().setClipToBounds(false); + rootNode->setPropertyFieldsDirty(RenderNode::GENERIC); + + ContextFactory factory; + RenderProxy* proxy = new RenderProxy(false, rootNode, &factory); + proxy->loadSystemProperties(); + proxy->initialize(surface); + float lightX = width / 2.0; + proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)}, + dp(800.0f), 255 * 0.075, 255 * 0.15); + + android::uirenderer::Rect DUMMY; + + std::vector< sp<RenderNode> > cards; + + DisplayListRenderer* renderer = startRecording(rootNode); + renderer->drawColor(0xFFFFFFFF, SkXfermode::kSrcOver_Mode); + renderer->insertReorderBarrier(true); + + for (int x = dp(16); x < (width - dp(116)); x += dp(116)) { + for (int y = dp(16); y < (height - dp(116)); y += dp(116)) { + sp<RenderNode> card = createCard(x, y, dp(100), dp(100)); + renderer->drawRenderNode(card.get(), DUMMY, 0); + cards.push_back(card); + } + } + + renderer->insertReorderBarrier(false); + endRecording(renderer, rootNode); + + for (int i = 0; i < 150; i++) { + ATRACE_NAME("UI-Draw Frame"); + for (int ci = 0; ci < cards.size(); ci++) { + cards[ci]->mutateStagingProperties().setTranslationX(i); + cards[ci]->mutateStagingProperties().setTranslationY(i); + cards[ci]->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y); + } + nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC); + proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density); + usleep(12000); + } + + sleep(5); + + delete proxy; + rootNode->decStrong(0); + + printf("Success!\n"); + return 0; +} diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java index 25dfee6..17d3251 100644 --- a/media/java/android/media/AudioAttributes.java +++ b/media/java/android/media/AudioAttributes.java @@ -518,14 +518,15 @@ public final class AudioAttributes implements Parcelable { /** * @hide - * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD and - * REMOTE_SUBMIX. + * Same as {@link #setCapturePreset(int)} but authorizes the use of HOTWORD, + * REMOTE_SUBMIX and FM_TUNER. * @param preset * @return the same Builder instance. */ public Builder setInternalCapturePreset(int preset) { if ((preset == MediaRecorder.AudioSource.HOTWORD) - || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX)) { + || (preset == MediaRecorder.AudioSource.REMOTE_SUBMIX) + || (preset == MediaRecorder.AudioSource.FM_TUNER)) { mSource = preset; } else { setCapturePreset(preset); diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java index 7975e04..b10736b 100644 --- a/media/java/android/media/AudioDevicePort.java +++ b/media/java/android/media/AudioDevicePort.java @@ -16,6 +16,8 @@ package android.media; +import android.media.AudioSystem; + /** * The AudioDevicePort is a specialized type of AudioPort * describing an input (e.g microphone) or output device (e.g speaker) @@ -85,8 +87,11 @@ public class AudioDevicePort extends AudioPort { @Override public String toString() { + String type = (mRole == ROLE_SOURCE ? + AudioSystem.getInputDeviceName(mType) : + AudioSystem.getOutputDeviceName(mType)); return "{" + super.toString() - + ", mType:" + mType + + ", mType: " + type + ", mAddress: " + mAddress + "}"; } diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java index 69c1142..716ff99 100644 --- a/media/java/android/media/AudioManager.java +++ b/media/java/android/media/AudioManager.java @@ -353,21 +353,6 @@ public class AudioManager { */ @Deprecated public static final int NUM_STREAMS = AudioSystem.NUM_STREAMS; - - /** @hide Default volume index values for audio streams */ - public static final int[] DEFAULT_STREAM_VOLUME = new int[] { - 4, // STREAM_VOICE_CALL - 7, // STREAM_SYSTEM - 5, // STREAM_RING - 11, // STREAM_MUSIC - 6, // STREAM_ALARM - 5, // STREAM_NOTIFICATION - 7, // STREAM_BLUETOOTH_SCO - 7, // STREAM_SYSTEM_ENFORCED - 11, // STREAM_DTMF - 11 // STREAM_TTS - }; - /** * Increase the ringer volume. * @@ -512,8 +497,11 @@ public class AudioManager { */ public static final int RINGER_MODE_NORMAL = 2; - // maximum valid ringer mode value. Values must start from 0 and be contiguous. - private static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL; + /** + * Maximum valid ringer mode value. Values must start from 0 and be contiguous. + * @hide + */ + public static final int RINGER_MODE_MAX = RINGER_MODE_NORMAL; /** * Vibrate type that corresponds to the ringer. @@ -887,7 +875,13 @@ public class AudioManager { if (ringerMode < 0 || ringerMode > RINGER_MODE_MAX) { return false; } - return true; + IAudioService service = getService(); + try { + return service.isValidRingerMode(ringerMode); + } catch (RemoteException e) { + Log.e(TAG, "Dead object in isValidRingerMode", e); + return false; + } } /** diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java index 81eceb1..acadb41 100644 --- a/media/java/android/media/AudioPatch.java +++ b/media/java/android/media/AudioPatch.java @@ -52,4 +52,25 @@ public class AudioPatch { public AudioPortConfig[] sinks() { return mSinks; } + + @Override + public String toString() { + StringBuilder s = new StringBuilder(); + s.append("mHandle: "); + s.append(mHandle.toString()); + + s.append(" mSources: {"); + for (AudioPortConfig source : mSources) { + s.append(source.toString()); + s.append(", "); + } + s.append("} mSinks: {"); + for (AudioPortConfig sink : mSinks) { + s.append(sink.toString()); + s.append(", "); + } + s.append("}"); + + return s.toString(); + } } diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java index 53212aa..1ab7e89 100644 --- a/media/java/android/media/AudioPort.java +++ b/media/java/android/media/AudioPort.java @@ -67,7 +67,7 @@ public class AudioPort { AudioHandle mHandle; - private final int mRole; + protected final int mRole; private final int[] mSamplingRates; private final int[] mChannelMasks; private final int[] mFormats; @@ -176,8 +176,20 @@ public class AudioPort { @Override public String toString() { - return "{mHandle:" + mHandle - + ", mRole:" + mRole + String role = Integer.toString(mRole); + switch (mRole) { + case ROLE_NONE: + role = "NONE"; + break; + case ROLE_SOURCE: + role = "SOURCE"; + break; + case ROLE_SINK: + role = "SINK"; + break; + } + return "{mHandle: " + mHandle + + ", mRole: " + role + "}"; } } diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 52b4649..ce78bb6 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -371,6 +371,7 @@ public class AudioRecord // audio source if ( (audioSource < MediaRecorder.AudioSource.DEFAULT) || ((audioSource > MediaRecorder.getAudioSourceMax()) && + (audioSource != MediaRecorder.AudioSource.FM_TUNER) && (audioSource != MediaRecorder.AudioSource.HOTWORD)) ) { throw new IllegalArgumentException("Invalid audio source."); } diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java index b0bf4a1..a84fe44 100644 --- a/media/java/android/media/AudioService.java +++ b/media/java/android/media/AudioService.java @@ -248,7 +248,7 @@ public class AudioService extends IAudioService.Stub { private final int[][] SOUND_EFFECT_FILES_MAP = new int[AudioManager.NUM_SOUND_EFFECTS][2]; /** @hide Maximum volume index values for audio streams */ - private static final int[] MAX_STREAM_VOLUME = new int[] { + private static int[] MAX_STREAM_VOLUME = new int[] { 5, // STREAM_VOICE_CALL 7, // STREAM_SYSTEM 7, // STREAM_RING @@ -260,6 +260,20 @@ public class AudioService extends IAudioService.Stub { 15, // STREAM_DTMF 15 // STREAM_TTS }; + + private static int[] DEFAULT_STREAM_VOLUME = new int[] { + 4, // STREAM_VOICE_CALL + 7, // STREAM_SYSTEM + 5, // STREAM_RING + 11, // STREAM_MUSIC + 6, // STREAM_ALARM + 5, // STREAM_NOTIFICATION + 7, // STREAM_BLUETOOTH_SCO + 7, // STREAM_SYSTEM_ENFORCED + 11, // STREAM_DTMF + 11 // STREAM_TTS + }; + /* mStreamVolumeAlias[] indicates for each stream if it uses the volume settings * of another stream: This avoids multiplying the volume settings for hidden * stream types that follow other stream behavior for volume settings @@ -541,12 +555,18 @@ public class AudioService extends IAudioService.Stub { mHasVibrator = vibrator == null ? false : vibrator.hasVibrator(); // Intialized volume - MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = SystemProperties.getInt( - "ro.config.vc_call_vol_steps", - MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); - MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = SystemProperties.getInt( - "ro.config.media_vol_steps", - MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]); + int maxVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", + MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]); + if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL]) { + MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxVolume; + DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = (maxVolume * 3) / 4; + } + maxVolume = SystemProperties.getInt("ro.config.media_vol_steps", + MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]); + if (maxVolume != MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC]) { + MAX_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = maxVolume; + DEFAULT_STREAM_VOLUME[AudioSystem.STREAM_MUSIC] = (maxVolume * 3) / 4; + } sSoundEffectVolumeDb = context.getResources().getInteger( com.android.internal.R.integer.config_soundEffectVolumeDb); @@ -843,7 +863,7 @@ public class AudioService extends IAudioService.Stub { int ringerMode = ringerModeFromSettings; // sanity check in case the settings are restored from a device with incompatible // ringer modes - if (!AudioManager.isValidRingerMode(ringerMode)) { + if (!isValidRingerMode(ringerMode)) { ringerMode = AudioManager.RINGER_MODE_NORMAL; } if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { @@ -1625,6 +1645,10 @@ public class AudioService extends IAudioService.Stub { return MAX_STREAM_VOLUME[streamType]; } + public static int getDefaultStreamVolume(int streamType) { + return DEFAULT_STREAM_VOLUME[streamType]; + } + /** @see AudioManager#getStreamVolume(int) */ public int getStreamVolume(int streamType) { ensureValidStreamType(streamType); @@ -1733,17 +1757,22 @@ public class AudioService extends IAudioService.Stub { } private void ensureValidRingerMode(int ringerMode) { - if (!AudioManager.isValidRingerMode(ringerMode)) { + if (!isValidRingerMode(ringerMode)) { throw new IllegalArgumentException("Bad ringer mode " + ringerMode); } } + /** @see AudioManager#isValidRingerMode(int) */ + public boolean isValidRingerMode(int ringerMode) { + return ringerMode >= 0 && ringerMode <= AudioManager.RINGER_MODE_MAX; + } + /** @see AudioManager#setRingerMode(int) */ public void setRingerMode(int ringerMode, boolean checkZen) { if (mUseFixedVolume || isPlatformTelevision()) { return; } - + ensureValidRingerMode(ringerMode); if ((ringerMode == AudioManager.RINGER_MODE_VIBRATE) && !mHasVibrator) { ringerMode = AudioManager.RINGER_MODE_SILENT; } @@ -3351,7 +3380,7 @@ public class AudioService extends IAudioService.Stub { // only be stale values if ((mStreamType == AudioSystem.STREAM_SYSTEM) || (mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED)) { - int index = 10 * AudioManager.DEFAULT_STREAM_VOLUME[mStreamType]; + int index = 10 * DEFAULT_STREAM_VOLUME[mStreamType]; synchronized (mCameraSoundForced) { if (mCameraSoundForced) { index = mIndexMax; @@ -3375,7 +3404,7 @@ public class AudioService extends IAudioService.Stub { // if no volume stored for current stream and device, use default volume if default // device, continue otherwise int defaultIndex = (device == AudioSystem.DEVICE_OUT_DEFAULT) ? - AudioManager.DEFAULT_STREAM_VOLUME[mStreamType] : -1; + DEFAULT_STREAM_VOLUME[mStreamType] : -1; int index = Settings.System.getIntForUser( mContentResolver, name, defaultIndex, UserHandle.USER_CURRENT); if (index == -1) { diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java index 9a76f94..e795fa7 100644 --- a/media/java/android/media/AudioSystem.java +++ b/media/java/android/media/AudioSystem.java @@ -255,6 +255,7 @@ public class AudioSystem public static final int DEVICE_OUT_SPDIF = 0x80000; public static final int DEVICE_OUT_FM = 0x100000; public static final int DEVICE_OUT_AUX_LINE = 0x200000; + public static final int DEVICE_OUT_SPEAKER_SAFE = 0x400000; public static final int DEVICE_OUT_DEFAULT = DEVICE_BIT_DEFAULT; @@ -280,6 +281,7 @@ public class AudioSystem DEVICE_OUT_SPDIF | DEVICE_OUT_FM | DEVICE_OUT_AUX_LINE | + DEVICE_OUT_SPEAKER_SAFE | DEVICE_OUT_DEFAULT); public static final int DEVICE_OUT_ALL_A2DP = (DEVICE_OUT_BLUETOOTH_A2DP | DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES | @@ -372,6 +374,27 @@ public class AudioSystem public static final String DEVICE_OUT_SPDIF_NAME = "spdif"; public static final String DEVICE_OUT_FM_NAME = "fm_transmitter"; public static final String DEVICE_OUT_AUX_LINE_NAME = "aux_line"; + public static final String DEVICE_OUT_SPEAKER_SAFE_NAME = "speaker_safe"; + + public static final String DEVICE_IN_COMMUNICATION_NAME = "communication"; + public static final String DEVICE_IN_AMBIENT_NAME = "ambient"; + public static final String DEVICE_IN_BUILTIN_MIC_NAME = "mic"; + public static final String DEVICE_IN_BLUETOOTH_SCO_HEADSET_NAME = "bt_sco_hs"; + public static final String DEVICE_IN_WIRED_HEADSET_NAME = "headset"; + public static final String DEVICE_IN_AUX_DIGITAL_NAME = "aux_digital"; + public static final String DEVICE_IN_TELEPHONY_RX_NAME = "telephony_rx"; + public static final String DEVICE_IN_BACK_MIC_NAME = "back_mic"; + public static final String DEVICE_IN_REMOTE_SUBMIX_NAME = "remote_submix"; + public static final String DEVICE_IN_ANLG_DOCK_HEADSET_NAME = "analog_dock"; + public static final String DEVICE_IN_DGTL_DOCK_HEADSET_NAME = "digital_dock"; + public static final String DEVICE_IN_USB_ACCESSORY_NAME = "usb_accessory"; + public static final String DEVICE_IN_USB_DEVICE_NAME = "usb_device"; + public static final String DEVICE_IN_FM_TUNER_NAME = "fm_tuner"; + public static final String DEVICE_IN_TV_TUNER_NAME = "tv_tuner"; + public static final String DEVICE_IN_LINE_NAME = "line"; + public static final String DEVICE_IN_SPDIF_NAME = "spdif"; + public static final String DEVICE_IN_BLUETOOTH_A2DP_NAME = "bt_a2dp"; + public static final String DEVICE_IN_LOOPBACK_NAME = "loopback"; public static String getOutputDeviceName(int device) { @@ -420,12 +443,60 @@ public class AudioSystem return DEVICE_OUT_FM_NAME; case DEVICE_OUT_AUX_LINE: return DEVICE_OUT_AUX_LINE_NAME; + case DEVICE_OUT_SPEAKER_SAFE: + return DEVICE_OUT_SPEAKER_SAFE_NAME; case DEVICE_OUT_DEFAULT: default: - return ""; + return Integer.toString(device); } } + public static String getInputDeviceName(int device) + { + switch(device) { + case DEVICE_IN_COMMUNICATION: + return DEVICE_IN_COMMUNICATION_NAME; + case DEVICE_IN_AMBIENT: + return DEVICE_IN_AMBIENT_NAME; + case DEVICE_IN_BUILTIN_MIC: + return DEVICE_IN_BUILTIN_MIC_NAME; + case DEVICE_IN_BLUETOOTH_SCO_HEADSET: + return DEVICE_IN_BLUETOOTH_SCO_HEADSET_NAME; + case DEVICE_IN_WIRED_HEADSET: + return DEVICE_IN_WIRED_HEADSET_NAME; + case DEVICE_IN_AUX_DIGITAL: + return DEVICE_IN_AUX_DIGITAL_NAME; + case DEVICE_IN_TELEPHONY_RX: + return DEVICE_IN_TELEPHONY_RX_NAME; + case DEVICE_IN_BACK_MIC: + return DEVICE_IN_BACK_MIC_NAME; + case DEVICE_IN_REMOTE_SUBMIX: + return DEVICE_IN_REMOTE_SUBMIX_NAME; + case DEVICE_IN_ANLG_DOCK_HEADSET: + return DEVICE_IN_ANLG_DOCK_HEADSET_NAME; + case DEVICE_IN_DGTL_DOCK_HEADSET: + return DEVICE_IN_DGTL_DOCK_HEADSET_NAME; + case DEVICE_IN_USB_ACCESSORY: + return DEVICE_IN_USB_ACCESSORY_NAME; + case DEVICE_IN_USB_DEVICE: + return DEVICE_IN_USB_DEVICE_NAME; + case DEVICE_IN_FM_TUNER: + return DEVICE_IN_FM_TUNER_NAME; + case DEVICE_IN_TV_TUNER: + return DEVICE_IN_TV_TUNER_NAME; + case DEVICE_IN_LINE: + return DEVICE_IN_LINE_NAME; + case DEVICE_IN_SPDIF: + return DEVICE_IN_SPDIF_NAME; + case DEVICE_IN_BLUETOOTH_A2DP: + return DEVICE_IN_BLUETOOTH_A2DP_NAME; + case DEVICE_IN_LOOPBACK: + return DEVICE_IN_LOOPBACK_NAME; + case DEVICE_IN_DEFAULT: + default: + return Integer.toString(device); + } + } // phone state, match audio_mode??? public static final int PHONE_STATE_OFFCALL = 0; diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 39b074e..2d8042c 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -80,6 +80,8 @@ interface IAudioService { int getRingerMode(); + boolean isValidRingerMode(int ringerMode); + void setVibrateSetting(int vibrateType, int vibrateSetting); int getVibrateSetting(int vibrateType); diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java index 522e45d..0d6b91a 100644 --- a/media/java/android/media/Image.java +++ b/media/java/android/media/Image.java @@ -146,8 +146,10 @@ public abstract class Image implements AutoCloseable { * using coordinates in the largest-resolution plane. */ public void setCropRect(Rect cropRect) { - cropRect = new Rect(cropRect); // make a copy - cropRect.intersect(0, 0, getWidth(), getHeight()); + if (cropRect != null) { + cropRect = new Rect(cropRect); // make a copy + cropRect.intersect(0, 0, getWidth(), getHeight()); + } mCropRect = cropRect; } diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index 420510a..bdd62f2 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -1778,10 +1778,6 @@ final public class MediaCodec { mIsValid = true; mIsReadOnly = buffer.isReadOnly(); mBuffer = buffer.duplicate(); - if (cropRect != null) { - cropRect.offset(-xOffset, -yOffset); - } - super.setCropRect(cropRect); // save offsets and info mXOffset = xOffset; @@ -1833,6 +1829,12 @@ final public class MediaCodec { throw new UnsupportedOperationException( "unsupported info length: " + info.remaining()); } + + if (cropRect == null) { + cropRect = new Rect(0, 0, mWidth, mHeight); + } + cropRect.offset(-xOffset, -yOffset); + super.setCropRect(cropRect); } private class MediaPlane extends Plane { diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java index a77bb96..81d5afe 100644 --- a/media/java/android/media/MediaRecorder.java +++ b/media/java/android/media/MediaRecorder.java @@ -222,6 +222,14 @@ public class MediaRecorder public static final int REMOTE_SUBMIX = 8; /** + * Audio source for FM, which is used to capture current FM tuner output by FMRadio app. + * There are two use cases, one is for record FM stream for later listening, another is + * for FM indirect mode(the routing except FM to headset(headphone) device routing). + * @hide + */ + public static final int FM_TUNER = 1998; + + /** * Audio source for preemptible, low-priority software hotword detection * It presents the same gain and pre processing tuning as {@link #VOICE_RECOGNITION}. * <p> diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java index b3890d4..691df77 100644 --- a/media/java/android/media/tv/TvContract.java +++ b/media/java/android/media/tv/TvContract.java @@ -1052,6 +1052,24 @@ public final class TvContract { /** The genre for Gaming. */ public static final String GAMING = "GAMING"; + /** The genre for Arts. */ + public static final String ARTS = "ARTS"; + + /** The genre for Entertainment. */ + public static final String ENTERTAINMENT = "ENTERTAINMENT"; + + /** The genre for Life Style. */ + public static final String LIFE_STYLE = "LIFE_STYLE"; + + /** The genre for Music. */ + public static final String MUSIC = "MUSIC"; + + /** The genre for Premier. */ + public static final String PREMIER = "PREMIER"; + + /** The genre for Tech/Science. */ + public static final String TECH_SCIENCE = "TECH_SCIENCE"; + private static final ArraySet<String> CANONICAL_GENRES = new ArraySet<String>(); static { CANONICAL_GENRES.add(FAMILY_KIDS); @@ -1065,6 +1083,12 @@ public final class TvContract { CANONICAL_GENRES.add(ANIMAL_WILDLIFE); CANONICAL_GENRES.add(NEWS); CANONICAL_GENRES.add(GAMING); + CANONICAL_GENRES.add(ARTS); + CANONICAL_GENRES.add(ENTERTAINMENT); + CANONICAL_GENRES.add(LIFE_STYLE); + CANONICAL_GENRES.add(MUSIC); + CANONICAL_GENRES.add(PREMIER); + CANONICAL_GENRES.add(TECH_SCIENCE); } private Genres() {} diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java index 54ebc6a..b9e99d2 100644 --- a/media/java/android/media/tv/TvInputInfo.java +++ b/media/java/android/media/tv/TvInputInfo.java @@ -241,6 +241,9 @@ public final class TvInputInfo implements Parcelable { if (DEBUG) { Log.d(TAG, "Setup activity loaded. [" + input.mSetupActivity + "] for " + si.name); } + if (inputType == TYPE_TUNER && TextUtils.isEmpty(input.mSetupActivity)) { + throw new XmlPullParserException("Setup activity not found in " + si.name); + } input.mSettingsActivity = sa.getString( com.android.internal.R.styleable.TvInputService_settingsActivity); if (DEBUG) { diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index 78714d2..51bd205 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -159,12 +159,12 @@ public final class TvInputManager { private final Object mLock = new Object(); - // @GuardedBy(mLock) + // @GuardedBy("mLock") private final List<TvInputCallbackRecord> mCallbackRecords = new LinkedList<TvInputCallbackRecord>(); // A mapping from TV input ID to the state of corresponding input. - // @GuardedBy(mLock) + // @GuardedBy("mLock") private final Map<String, Integer> mStateMap = new ArrayMap<String, Integer>(); // A mapping from the sequence number of a session to its SessionCallbackRecord. @@ -207,7 +207,7 @@ public final class TvInputManager { /** * This is called when the channel of this session is changed by the underlying TV input - * with out any {@link TvInputManager.Session#tune(Uri)} request. + * without any {@link TvInputManager.Session#tune(Uri)} request. * * @param session A {@link TvInputManager.Session} associated with this callback. * @param channelUri The URI of a channel. @@ -227,7 +227,7 @@ public final class TvInputManager { /** * This is called when a track for a given type is selected. * - * @param session A {@link TvInputManager.Session} associated with this callback + * @param session A {@link TvInputManager.Session} associated with this callback. * @param type The type of the selected track. The type can be * {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or * {@link TvTrackInfo#TYPE_SUBTITLE}. @@ -238,6 +238,18 @@ public final class TvInputManager { } /** + * This is invoked when the video size has been changed. It is also called when the first + * time video size information becomes available after the session is tuned to a specific + * channel. + * + * @param session A {@link TvInputManager.Session} associated with this callback. + * @param width The width of the video. + * @param height The height of the video. + */ + public void onVideoSizeChanged(Session session, int width, int height) { + } + + /** * This is called when the video is available, so the TV input starts the playback. * * @param session A {@link TvInputManager.Session} associated with this callback. @@ -312,13 +324,13 @@ public final class TvInputManager { private final Handler mHandler; private Session mSession; - public SessionCallbackRecord(SessionCallback sessionCallback, + SessionCallbackRecord(SessionCallback sessionCallback, Handler handler) { mSessionCallback = sessionCallback; mHandler = handler; } - public void postSessionCreated(final Session session) { + void postSessionCreated(final Session session) { mSession = session; mHandler.post(new Runnable() { @Override @@ -328,7 +340,7 @@ public final class TvInputManager { }); } - public void postSessionReleased() { + void postSessionReleased() { mHandler.post(new Runnable() { @Override public void run() { @@ -337,7 +349,7 @@ public final class TvInputManager { }); } - public void postChannelRetuned(final Uri channelUri) { + void postChannelRetuned(final Uri channelUri) { mHandler.post(new Runnable() { @Override public void run() { @@ -346,49 +358,34 @@ public final class TvInputManager { }); } - public void postTracksChanged(final List<TvTrackInfo> tracks) { + void postTracksChanged(final List<TvTrackInfo> tracks) { mHandler.post(new Runnable() { @Override public void run() { - mSession.mAudioTracks.clear(); - mSession.mVideoTracks.clear(); - mSession.mSubtitleTracks.clear(); - for (TvTrackInfo track : tracks) { - if (track.getType() == TvTrackInfo.TYPE_AUDIO) { - mSession.mAudioTracks.add(track); - } else if (track.getType() == TvTrackInfo.TYPE_VIDEO) { - mSession.mVideoTracks.add(track); - } else if (track.getType() == TvTrackInfo.TYPE_SUBTITLE) { - mSession.mSubtitleTracks.add(track); - } else { - // Silently ignore. - } - } mSessionCallback.onTracksChanged(mSession, tracks); } }); } - public void postTrackSelected(final int type, final String trackId) { + void postTrackSelected(final int type, final String trackId) { mHandler.post(new Runnable() { @Override public void run() { - if (type == TvTrackInfo.TYPE_AUDIO) { - mSession.mSelectedAudioTrackId = trackId; - } else if (type == TvTrackInfo.TYPE_VIDEO) { - mSession.mSelectedVideoTrackId = trackId; - } else if (type == TvTrackInfo.TYPE_SUBTITLE) { - mSession.mSelectedSubtitleTrackId = trackId; - } else { - // Silently ignore. - return; - } mSessionCallback.onTrackSelected(mSession, type, trackId); } }); } - public void postVideoAvailable() { + void postVideoSizeChanged(final int width, final int height) { + mHandler.post(new Runnable() { + @Override + public void run() { + mSessionCallback.onVideoSizeChanged(mSession, width, height); + } + }); + } + + void postVideoAvailable() { mHandler.post(new Runnable() { @Override public void run() { @@ -397,7 +394,7 @@ public final class TvInputManager { }); } - public void postVideoUnavailable(final int reason) { + void postVideoUnavailable(final int reason) { mHandler.post(new Runnable() { @Override public void run() { @@ -406,7 +403,7 @@ public final class TvInputManager { }); } - public void postContentAllowed() { + void postContentAllowed() { mHandler.post(new Runnable() { @Override public void run() { @@ -415,7 +412,7 @@ public final class TvInputManager { }); } - public void postContentBlocked(final TvContentRating rating) { + void postContentBlocked(final TvContentRating rating) { mHandler.post(new Runnable() { @Override public void run() { @@ -424,7 +421,7 @@ public final class TvInputManager { }); } - public void postLayoutSurface(final int left, final int top, final int right, + void postLayoutSurface(final int left, final int top, final int right, final int bottom) { mHandler.post(new Runnable() { @Override @@ -434,7 +431,7 @@ public final class TvInputManager { }); } - public void postSessionEvent(final String eventType, final Bundle eventArgs) { + void postSessionEvent(final String eventType, final Bundle eventArgs) { mHandler.post(new Runnable() { @Override public void run() { @@ -610,7 +607,10 @@ public final class TvInputManager { Log.e(TAG, "Callback not found for seq " + seq); return; } - record.postTracksChanged(tracks); + if (record.mSession.updateTracks(tracks)) { + record.postTracksChanged(tracks); + postVideoSizeChangedIfNeededLocked(record); + } } } @@ -622,7 +622,17 @@ public final class TvInputManager { Log.e(TAG, "Callback not found for seq " + seq); return; } - record.postTrackSelected(type, trackId); + if (record.mSession.updateTrackSelection(type, trackId)) { + record.postTrackSelected(type, trackId); + postVideoSizeChangedIfNeededLocked(record); + } + } + } + + private void postVideoSizeChangedIfNeededLocked(SessionCallbackRecord record) { + TvTrackInfo track = record.mSession.getVideoTrackToNotify(); + if (track != null) { + record.postVideoSizeChanged(track.getVideoWidth(), track.getVideoHeight()); } } @@ -778,7 +788,7 @@ public final class TvInputManager { } /** - * Returns the state of a given TV input. It retuns one of the following: + * Returns the state of a given TV input. It returns one of the following: * <ul> * <li>{@link #INPUT_STATE_CONNECTED} * <li>{@link #INPUT_STATE_CONNECTED_STANDBY} @@ -1133,12 +1143,24 @@ public final class TvInputManager { private IBinder mToken; private TvInputEventSender mSender; private InputChannel mChannel; + + private final Object mTrackLock = new Object(); + // @GuardedBy("mTrackLock") private final List<TvTrackInfo> mAudioTracks = new ArrayList<TvTrackInfo>(); + // @GuardedBy("mTrackLock") private final List<TvTrackInfo> mVideoTracks = new ArrayList<TvTrackInfo>(); + // @GuardedBy("mTrackLock") private final List<TvTrackInfo> mSubtitleTracks = new ArrayList<TvTrackInfo>(); + // @GuardedBy("mTrackLock") private String mSelectedAudioTrackId; + // @GuardedBy("mTrackLock") private String mSelectedVideoTrackId; + // @GuardedBy("mTrackLock") private String mSelectedSubtitleTrackId; + // @GuardedBy("mTrackLock") + private int mVideoWidth; + // @GuardedBy("mTrackLock") + private int mVideoHeight; private Session(IBinder token, InputChannel channel, ITvInputManager service, int userId, int seq, SparseArray<SessionCallbackRecord> sessionCallbackRecordMap) { @@ -1273,12 +1295,16 @@ public final class TvInputManager { Log.w(TAG, "The session has been already released"); return; } - mAudioTracks.clear(); - mVideoTracks.clear(); - mSubtitleTracks.clear(); - mSelectedAudioTrackId = null; - mSelectedVideoTrackId = null; - mSelectedSubtitleTrackId = null; + synchronized (mTrackLock) { + mAudioTracks.clear(); + mVideoTracks.clear(); + mSubtitleTracks.clear(); + mSelectedAudioTrackId = null; + mSelectedVideoTrackId = null; + mSelectedSubtitleTrackId = null; + mVideoWidth = 0; + mVideoHeight = 0; + } try { mService.tune(mToken, channelUri, params, mUserId); } catch (RemoteException e) { @@ -1314,23 +1340,25 @@ public final class TvInputManager { * @see #getTracks */ public void selectTrack(int type, String trackId) { - if (type == TvTrackInfo.TYPE_AUDIO) { - if (trackId != null && !containsTrack(mAudioTracks, trackId)) { - Log.w(TAG, "Invalid audio trackId: " + trackId); - return; - } - } else if (type == TvTrackInfo.TYPE_VIDEO) { - if (trackId != null && !containsTrack(mVideoTracks, trackId)) { - Log.w(TAG, "Invalid video trackId: " + trackId); - return; - } - } else if (type == TvTrackInfo.TYPE_SUBTITLE) { - if (trackId != null && !containsTrack(mSubtitleTracks, trackId)) { - Log.w(TAG, "Invalid subtitle trackId: " + trackId); - return; + synchronized (mTrackLock) { + if (type == TvTrackInfo.TYPE_AUDIO) { + if (trackId != null && !containsTrack(mAudioTracks, trackId)) { + Log.w(TAG, "Invalid audio trackId: " + trackId); + return; + } + } else if (type == TvTrackInfo.TYPE_VIDEO) { + if (trackId != null && !containsTrack(mVideoTracks, trackId)) { + Log.w(TAG, "Invalid video trackId: " + trackId); + return; + } + } else if (type == TvTrackInfo.TYPE_SUBTITLE) { + if (trackId != null && !containsTrack(mSubtitleTracks, trackId)) { + Log.w(TAG, "Invalid subtitle trackId: " + trackId); + return; + } + } else { + throw new IllegalArgumentException("invalid type: " + type); } - } else { - throw new IllegalArgumentException("invalid type: " + type); } if (mToken == null) { Log.w(TAG, "The session has been already released"); @@ -1361,21 +1389,23 @@ public final class TvInputManager { * @return the list of tracks for the given type. */ public List<TvTrackInfo> getTracks(int type) { - if (type == TvTrackInfo.TYPE_AUDIO) { - if (mAudioTracks == null) { - return null; - } - return mAudioTracks; - } else if (type == TvTrackInfo.TYPE_VIDEO) { - if (mVideoTracks == null) { - return null; - } - return mVideoTracks; - } else if (type == TvTrackInfo.TYPE_SUBTITLE) { - if (mSubtitleTracks == null) { - return null; + synchronized (mTrackLock) { + if (type == TvTrackInfo.TYPE_AUDIO) { + if (mAudioTracks == null) { + return null; + } + return new ArrayList<TvTrackInfo>(mAudioTracks); + } else if (type == TvTrackInfo.TYPE_VIDEO) { + if (mVideoTracks == null) { + return null; + } + return new ArrayList<TvTrackInfo>(mVideoTracks); + } else if (type == TvTrackInfo.TYPE_SUBTITLE) { + if (mSubtitleTracks == null) { + return null; + } + return new ArrayList<TvTrackInfo>(mSubtitleTracks); } - return mSubtitleTracks; } throw new IllegalArgumentException("invalid type: " + type); } @@ -1388,17 +1418,89 @@ public final class TvInputManager { * @see #selectTrack */ public String getSelectedTrack(int type) { - if (type == TvTrackInfo.TYPE_AUDIO) { - return mSelectedAudioTrackId; - } else if (type == TvTrackInfo.TYPE_VIDEO) { - return mSelectedVideoTrackId; - } else if (type == TvTrackInfo.TYPE_SUBTITLE) { - return mSelectedSubtitleTrackId; + synchronized (mTrackLock) { + if (type == TvTrackInfo.TYPE_AUDIO) { + return mSelectedAudioTrackId; + } else if (type == TvTrackInfo.TYPE_VIDEO) { + return mSelectedVideoTrackId; + } else if (type == TvTrackInfo.TYPE_SUBTITLE) { + return mSelectedSubtitleTrackId; + } } throw new IllegalArgumentException("invalid type: " + type); } /** + * Responds to onTracksChanged() and updates the internal track information. Returns true if + * there is an update. + */ + boolean updateTracks(List<TvTrackInfo> tracks) { + synchronized (mTrackLock) { + mAudioTracks.clear(); + mVideoTracks.clear(); + mSubtitleTracks.clear(); + for (TvTrackInfo track : tracks) { + if (track.getType() == TvTrackInfo.TYPE_AUDIO) { + mAudioTracks.add(track); + } else if (track.getType() == TvTrackInfo.TYPE_VIDEO) { + mVideoTracks.add(track); + } else if (track.getType() == TvTrackInfo.TYPE_SUBTITLE) { + mSubtitleTracks.add(track); + } + } + return !mAudioTracks.isEmpty() || !mVideoTracks.isEmpty() + || !mSubtitleTracks.isEmpty(); + } + } + + /** + * Responds to onTrackSelected() and updates the internal track selection information. + * Returns true if there is an update. + */ + boolean updateTrackSelection(int type, String trackId) { + synchronized (mTrackLock) { + if (type == TvTrackInfo.TYPE_AUDIO && trackId != mSelectedAudioTrackId) { + mSelectedAudioTrackId = trackId; + return true; + } else if (type == TvTrackInfo.TYPE_VIDEO && trackId != mSelectedVideoTrackId) { + mSelectedVideoTrackId = trackId; + return true; + } else if (type == TvTrackInfo.TYPE_SUBTITLE + && trackId != mSelectedSubtitleTrackId) { + mSelectedSubtitleTrackId = trackId; + return true; + } + } + return false; + } + + /** + * Returns the new/updated video track that contains new video size information. Returns + * null if there is no video track to notify. Subsequent calls of this method results in a + * non-null video track returned only by the first call and null returned by following + * calls. The caller should immediately notify of the video size change upon receiving the + * track. + */ + TvTrackInfo getVideoTrackToNotify() { + synchronized (mTrackLock) { + if (!mVideoTracks.isEmpty() && mSelectedVideoTrackId != null) { + for (TvTrackInfo track : mVideoTracks) { + if (track.getId().equals(mSelectedVideoTrackId)) { + int videoWidth = track.getVideoWidth(); + int videoHeight = track.getVideoHeight(); + if (mVideoWidth != videoWidth || mVideoHeight != videoHeight) { + mVideoWidth = videoWidth; + mVideoHeight = videoHeight; + return track; + } + } + } + } + } + return null; + } + + /** * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle) * TvInputService.Session.appPrivateCommand()} on the current TvView. * diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java index 4f8facb..5d5ea02 100644 --- a/media/java/android/media/tv/TvInputService.java +++ b/media/java/android/media/tv/TvInputService.java @@ -332,8 +332,13 @@ public abstract class TvInputService extends Service { } /** - * Sends the change on the track information. This is expected to be called whenever a track - * is added/removed and the metadata of a track is modified. + * Sends the list of all audio/video/subtitle tracks. The is used by the framework to + * maintain the track information for a given session, which in turn is used by + * {@link TvView#getTracks} for the application to retrieve metadata for a given track type. + * The TV input service must call this method as soon as the track information becomes + * available or is updated. Note that in a case where a part of the information for a + * certain track is updated, it is not necessary to create a new {@link TvTrackInfo} object + * with a different track ID. * * @param tracks A list which includes track information. * @throws IllegalArgumentException if {@code tracks} contains redundant tracks. @@ -364,8 +369,12 @@ public abstract class TvInputService extends Service { } /** - * Sends the ID of the selected track for a given track type. This is expected to be called - * whenever there is a change on track selection. + * Sends the type and ID of a selected track. This is used to inform the application that a + * specific track is selected. The TV input service must call this method as soon as a track + * is selected either by default or in response to a call to {@link #onSelectTrack}. The + * selected track ID for a given type is maintained in the framework until the next call to + * this method even after the entire track list is updated (but is reset when the session is + * tuned to a new channel), so care must be taken not to result in an obsolete track ID. * * @param type The type of the selected track. The type can be * {@link TvTrackInfo#TYPE_AUDIO}, {@link TvTrackInfo#TYPE_VIDEO} or @@ -1067,9 +1076,19 @@ public abstract class TvInputService extends Service { /** * Base class for a TV input session which represents an external device connected to a - * hardware TV input. Once TV input returns an implementation of this class on - * {@link #onCreateSession(String)}, the framework will create a hardware session and forward - * the application's surface to the hardware TV input. + * hardware TV input. + * <p> + * This class is for an input which provides channels for the external set-top box to the + * application. Once a TV input returns an implementation of this class on + * {@link #onCreateSession(String)}, the framework will create a separate session for + * a hardware TV Input (e.g. HDMI 1) and forward the application's surface to the session so + * that the user can see the screen of the hardware TV Input when she tunes to a channel from + * this TV input. The implementation of this class is expected to change the channel of the + * external set-top box via a proprietary protocol when {@link HardwareSession#onTune(Uri)} is + * requested by the application. + * </p><p> + * Note that this class is not for inputs for internal hardware like built-in tuner and HDMI 1. + * </p> * @see #onCreateSession(String) */ public abstract static class HardwareSession extends Session { diff --git a/media/java/android/media/tv/TvStreamConfig.java b/media/java/android/media/tv/TvStreamConfig.java index a7e7e44..1bdc63e 100644 --- a/media/java/android/media/tv/TvStreamConfig.java +++ b/media/java/android/media/tv/TvStreamConfig.java @@ -33,7 +33,6 @@ public class TvStreamConfig implements Parcelable { private int mStreamId; private int mType; - // TODO: Revisit if max widht/height really make sense. private int mMaxWidth; private int mMaxHeight; /** @@ -166,4 +165,17 @@ public class TvStreamConfig implements Parcelable { return config; } } + + @Override + public boolean equals(Object obj) { + if (obj == null) return false; + if (!(obj instanceof TvStreamConfig)) return false; + + TvStreamConfig config = (TvStreamConfig) obj; + return config.mGeneration == mGeneration + && config.mStreamId == mStreamId + && config.mType == mType + && config.mMaxWidth == mMaxWidth + && config.mMaxHeight == mMaxHeight; + } } diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java index 0949b1a..f9d84c1 100644 --- a/media/java/android/media/tv/TvView.java +++ b/media/java/android/media/tv/TvView.java @@ -59,8 +59,6 @@ public class TvView extends ViewGroup { private static final String TAG = "TvView"; private static final boolean DEBUG = false; - private static final int VIDEO_SIZE_VALUE_UNKNOWN = 0; - private static final int ZORDER_MEDIA = 0; private static final int ZORDER_MEDIA_OVERLAY = 1; private static final int ZORDER_ON_TOP = 2; @@ -69,7 +67,7 @@ public class TvView extends ViewGroup { private static final int CAPTION_ENABLED = 1; private static final int CAPTION_DISABLED = 2; - private static final WeakReference<TvView> NULL_TV_VIEW = new WeakReference(null); + private static final WeakReference<TvView> NULL_TV_VIEW = new WeakReference<>(null); private static final Object sMainTvViewLock = new Object(); private static WeakReference<TvView> sMainTvView = NULL_TV_VIEW; @@ -86,8 +84,10 @@ public class TvView extends ViewGroup { private OnUnhandledInputEventListener mOnUnhandledInputEventListener; private boolean mHasStreamVolume; private float mStreamVolume; - private int mVideoWidth = VIDEO_SIZE_VALUE_UNKNOWN; - private int mVideoHeight = VIDEO_SIZE_VALUE_UNKNOWN; + private int mCaptionEnabled; + private String mAppPrivateCommandAction; + private Bundle mAppPrivateCommandData; + private boolean mSurfaceChanged; private int mSurfaceFormat; private int mSurfaceWidth; @@ -100,7 +100,6 @@ public class TvView extends ViewGroup { private int mSurfaceViewRight; private int mSurfaceViewTop; private int mSurfaceViewBottom; - private int mCaptionEnabled; private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() { @Override @@ -197,7 +196,7 @@ public class TvView extends ViewGroup { @SystemApi public void setMain() { synchronized (sMainTvViewLock) { - sMainTvView = new WeakReference(this); + sMainTvView = new WeakReference<>(this); if (hasWindowFocus() && mSession != null) { mSession.setMain(); } @@ -291,7 +290,7 @@ public class TvView extends ViewGroup { } synchronized (sMainTvViewLock) { if (sMainTvView.get() == null) { - sMainTvView = new WeakReference(this); + sMainTvView = new WeakReference<>(this); } } if (mSessionCallback != null && mSessionCallback.mInputId.equals(inputId)) { @@ -421,10 +420,10 @@ public class TvView extends ViewGroup { * Calls {@link TvInputService.Session#appPrivateCommand(String, Bundle) * TvInputService.Session.appPrivateCommand()} on the current TvView. * - * @param action Name of the command to be performed. This <em>must</em> be a scoped name, i.e. - * prefixed with a package name you own, so that different developers will not create - * conflicting commands. - * @param data Any data to include with the command. + * @param action The name of the private command to send. This <em>must</em> be a scoped name, + * i.e. prefixed with a package name you own, so that different developers will not + * create conflicting commands. + * @param data An optional bundle to send with the command. * @hide */ @SystemApi @@ -434,6 +433,13 @@ public class TvView extends ViewGroup { } if (mSession != null) { mSession.sendAppPrivateCommand(action, data); + } else { + Log.w(TAG, "sendAppPrivateCommand - session not created (action " + action + " cached)"); + if (mAppPrivateCommandAction != null) { + Log.w(TAG, "previous cached action " + action + " removed"); + } + mAppPrivateCommandAction = action; + mAppPrivateCommandData = data; } } @@ -619,6 +625,9 @@ public class TvView extends ViewGroup { } private void release() { + mAppPrivateCommandAction = null; + mAppPrivateCommandData = null; + setSessionSurface(null); removeSessionOverlayView(); mUseRequestedSurfaceLayout = false; @@ -703,19 +712,8 @@ public class TvView extends ViewGroup { } /** - * This is invoked when the view is tuned to a specific channel and starts decoding video - * stream from there. It is also called later when the video size is changed. - * - * @param inputId The ID of the TV input bound to this view. - * @param width The width of the video. - * @param height The height of the video. - */ - public void onVideoSizeChanged(String inputId, int width, int height) { - } - - /** * This is invoked when the channel of this TvView is changed by the underlying TV input - * with out any {@link TvView#tune(String, Uri)} request. + * without any {@link TvView#tune(String, Uri)} request. * * @param inputId The ID of the TV input bound to this view. * @param channelUri The URI of a channel. @@ -745,6 +743,18 @@ public class TvView extends ViewGroup { } /** + * This is invoked when the video size has been changed. It is also called when the first + * time video size information becomes available after this view is tuned to a specific + * channel. + * + * @param inputId The ID of the TV input bound to this view. + * @param width The width of the video. + * @param height The height of the video. + */ + public void onVideoSizeChanged(String inputId, int width, int height) { + } + + /** * This is called when the video is available, so the TV input starts the playback. * * @param inputId The ID of the TV input bound to this view. @@ -828,16 +838,17 @@ public class TvView extends ViewGroup { @Override public void onSessionCreated(Session session) { + if (DEBUG) { + Log.d(TAG, "onSessionCreated()"); + } if (this != mSessionCallback) { + Log.w(TAG, "onSessionCreated - session already created"); // This callback is obsolete. if (session != null) { session.release(); } return; } - if (DEBUG) { - Log.d(TAG, "onSessionCreated()"); - } mSession = session; if (session != null) { synchronized (sMainTvViewLock) { @@ -862,6 +873,12 @@ public class TvView extends ViewGroup { if (mHasStreamVolume) { mSession.setStreamVolume(mStreamVolume); } + if (mAppPrivateCommandAction != null) { + mSession.sendAppPrivateCommand( + mAppPrivateCommandAction, mAppPrivateCommandData); + mAppPrivateCommandAction = null; + mAppPrivateCommandData = null; + } } else { mSessionCallback = null; if (mCallback != null) { @@ -872,7 +889,11 @@ public class TvView extends ViewGroup { @Override public void onSessionReleased(Session session) { + if (DEBUG) { + Log.d(TAG, "onSessionReleased()"); + } if (this != mSessionCallback) { + Log.w(TAG, "onSessionReleased - session not created"); return; } mOverlayViewCreated = false; @@ -886,12 +907,13 @@ public class TvView extends ViewGroup { @Override public void onChannelRetuned(Session session, Uri channelUri) { - if (this != mSessionCallback) { - return; - } if (DEBUG) { Log.d(TAG, "onChannelChangedByTvInput(" + channelUri + ")"); } + if (this != mSessionCallback) { + Log.w(TAG, "onChannelRetuned - session not created"); + return; + } if (mCallback != null) { mCallback.onChannelRetuned(mInputId, channelUri); } @@ -899,12 +921,13 @@ public class TvView extends ViewGroup { @Override public void onTracksChanged(Session session, List<TvTrackInfo> tracks) { + if (DEBUG) { + Log.d(TAG, "onTracksChanged(" + tracks + ")"); + } if (this != mSessionCallback) { + Log.w(TAG, "onTracksChanged - session not created"); return; } - if (DEBUG) { - Log.d(TAG, "onTracksChanged()"); - } if (mCallback != null) { mCallback.onTracksChanged(mInputId, tracks); } @@ -912,26 +935,41 @@ public class TvView extends ViewGroup { @Override public void onTrackSelected(Session session, int type, String trackId) { + if (DEBUG) { + Log.d(TAG, "onTrackSelected(type=" + type + ", trackId=" + trackId + ")"); + } if (this != mSessionCallback) { + Log.w(TAG, "onTrackSelected - session not created"); return; } - if (DEBUG) { - Log.d(TAG, "onTrackSelected()"); - } - // TODO: Update the video size when the type is TYPE_VIDEO. if (mCallback != null) { mCallback.onTrackSelected(mInputId, type, trackId); } } @Override - public void onVideoAvailable(Session session) { + public void onVideoSizeChanged(Session session, int width, int height) { + if (DEBUG) { + Log.d(TAG, "onVideoSizeChanged()"); + } if (this != mSessionCallback) { + Log.w(TAG, "onVideoSizeChanged - session not created"); return; } + if (mCallback != null) { + mCallback.onVideoSizeChanged(mInputId, width, height); + } + } + + @Override + public void onVideoAvailable(Session session) { if (DEBUG) { Log.d(TAG, "onVideoAvailable()"); } + if (this != mSessionCallback) { + Log.w(TAG, "onVideoAvailable - session not created"); + return; + } if (mCallback != null) { mCallback.onVideoAvailable(mInputId); } @@ -939,12 +977,13 @@ public class TvView extends ViewGroup { @Override public void onVideoUnavailable(Session session, int reason) { + if (DEBUG) { + Log.d(TAG, "onVideoUnavailable(reason=" + reason + ")"); + } if (this != mSessionCallback) { + Log.w(TAG, "onVideoUnavailable - session not created"); return; } - if (DEBUG) { - Log.d(TAG, "onVideoUnavailable(" + reason + ")"); - } if (mCallback != null) { mCallback.onVideoUnavailable(mInputId, reason); } @@ -952,12 +991,13 @@ public class TvView extends ViewGroup { @Override public void onContentAllowed(Session session) { - if (this != mSessionCallback) { - return; - } if (DEBUG) { Log.d(TAG, "onContentAllowed()"); } + if (this != mSessionCallback) { + Log.w(TAG, "onContentAllowed - session not created"); + return; + } if (mCallback != null) { mCallback.onContentAllowed(mInputId); } @@ -965,12 +1005,13 @@ public class TvView extends ViewGroup { @Override public void onContentBlocked(Session session, TvContentRating rating) { + if (DEBUG) { + Log.d(TAG, "onContentBlocked(rating=" + rating + ")"); + } if (this != mSessionCallback) { + Log.w(TAG, "onContentBlocked - session not created"); return; } - if (DEBUG) { - Log.d(TAG, "onContentBlocked()"); - } if (mCallback != null) { mCallback.onContentBlocked(mInputId, rating); } @@ -978,13 +1019,14 @@ public class TvView extends ViewGroup { @Override public void onLayoutSurface(Session session, int left, int top, int right, int bottom) { - if (this != mSessionCallback) { - return; - } if (DEBUG) { Log.d(TAG, "onLayoutSurface (left=" + left + ", top=" + top + ", right=" + right + ", bottom=" + bottom + ",)"); } + if (this != mSessionCallback) { + Log.w(TAG, "onLayoutSurface - session not created"); + return; + } mSurfaceViewLeft = left; mSurfaceViewTop = top; mSurfaceViewRight = right; @@ -995,12 +1037,13 @@ public class TvView extends ViewGroup { @Override public void onSessionEvent(Session session, String eventType, Bundle eventArgs) { - if (this != mSessionCallback) { - return; - } if (DEBUG) { Log.d(TAG, "onSessionEvent(" + eventType + ")"); } + if (this != mSessionCallback) { + Log.w(TAG, "onSessionEvent - session not created"); + return; + } if (mCallback != null) { mCallback.onEvent(mInputId, eventType, eventArgs); } diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp index 5646740..3b1b1d7 100644 --- a/media/jni/android_media_MediaRecorder.cpp +++ b/media/jni/android_media_MediaRecorder.cpp @@ -182,7 +182,8 @@ static void android_media_MediaRecorder_setAudioSource(JNIEnv *env, jobject thiz, jint as) { ALOGV("setAudioSource(%d)", as); - if (as < AUDIO_SOURCE_DEFAULT || as >= AUDIO_SOURCE_CNT) { + if (as < AUDIO_SOURCE_DEFAULT || + (as >= AUDIO_SOURCE_CNT && as != AUDIO_SOURCE_FM_TUNER)) { jniThrowException(env, "java/lang/IllegalArgumentException", "Invalid audio source"); return; } diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp index 19b54a6..62b4a36 100644 --- a/media/jni/android_mtp_MtpDatabase.cpp +++ b/media/jni/android_mtp_MtpDatabase.cpp @@ -207,7 +207,8 @@ MyMtpDatabase::MyMtpDatabase(JNIEnv *env, jobject client) return; // Already threw. } mLongBuffer = (jlongArray)env->NewGlobalRef(longArray); - jcharArray charArray = env->NewCharArray(256); + // Needs to be long enough to hold a file path for getObjectFilePath() + jcharArray charArray = env->NewCharArray(PATH_MAX + 1); if (!charArray) { return; // Already threw. } @@ -761,7 +762,7 @@ MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle, return result; } -static void foreachentry(ExifEntry *entry, void *user) { +static void foreachentry(ExifEntry *entry, void * /*user*/) { char buf[1024]; ALOGI("entry %x, format %d, size %d: %s", entry->tag, entry->format, entry->size, exif_entry_get_value(entry, buf, sizeof(buf))); diff --git a/media/tests/omxjpegdecoder/Android.mk b/media/tests/omxjpegdecoder/Android.mk deleted file mode 100644 index b0bc5d4..0000000 --- a/media/tests/omxjpegdecoder/Android.mk +++ /dev/null @@ -1,45 +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. - -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := \ - omx_jpeg_decoder.cpp \ - jpeg_decoder_bench.cpp \ - StreamSource.cpp - -LOCAL_SHARED_LIBRARIES := \ - libcutils \ - libskia \ - libstagefright \ - libstagefright_foundation \ - libbinder \ - libutils \ - liblog \ - libjpeg - -LOCAL_C_INCLUDES := \ - $(TOP)/external/jpeg \ - $(TOP)/frameworks/base/media/libstagefright \ - $(TOP)/frameworks/base/include/ \ - $(TOP)/frameworks/base/ \ - $(TOP)/frameworks/native/include/media/openmax - -LOCAL_MODULE := jpeg_bench - -LOCAL_MODULE_TAGS := optional - -include $(BUILD_EXECUTABLE) diff --git a/media/tests/omxjpegdecoder/StreamSource.cpp b/media/tests/omxjpegdecoder/StreamSource.cpp deleted file mode 100644 index f764121a..0000000 --- a/media/tests/omxjpegdecoder/StreamSource.cpp +++ /dev/null @@ -1,53 +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. - */ - -#include <media/stagefright/foundation/ADebug.h> - -#include "StreamSource.h" - -namespace android { - -StreamSource::StreamSource(SkStream *stream) - : mStream(stream) { - CHECK(stream != NULL); - mSize = stream->getLength(); -} - -StreamSource::~StreamSource() { - delete mStream; - mStream = NULL; -} - -status_t StreamSource::initCheck() const { - return mStream != NULL ? OK : NO_INIT; -} - -ssize_t StreamSource::readAt(off64_t offset, void *data, size_t size) { - Mutex::Autolock autoLock(mLock); - - mStream->rewind(); - mStream->skip(offset); - ssize_t result = mStream->read(data, size); - - return result; -} - -status_t StreamSource::getSize(off64_t *size) { - *size = mSize; - return OK; -} - -} // namespace android diff --git a/media/tests/omxjpegdecoder/StreamSource.h b/media/tests/omxjpegdecoder/StreamSource.h deleted file mode 100644 index 9807385..0000000 --- a/media/tests/omxjpegdecoder/StreamSource.h +++ /dev/null @@ -1,52 +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. - */ - -#ifndef STREAM_SOURCE_H_ - -#define STREAM_SOURCE_H_ - -#include <stdio.h> - -#include <SkStream.h> -#include <media/stagefright/DataSource.h> -#include <media/stagefright/MediaErrors.h> -#include <utils/threads.h> - -namespace android { - -class StreamSource : public DataSource { -public: - // Pass the ownership of SkStream to StreamSource. - StreamSource(SkStream *SkStream); - virtual status_t initCheck() const; - virtual ssize_t readAt(off64_t offset, void *data, size_t size); - virtual status_t getSize(off64_t *size); - -protected: - virtual ~StreamSource(); - -private: - SkStream *mStream; - size_t mSize; - Mutex mLock; - - StreamSource(const StreamSource &); - StreamSource &operator=(const StreamSource &); -}; - -} // namespace android - -#endif // STREAM_SOURCE_H_ diff --git a/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp b/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp deleted file mode 100644 index de6294d..0000000 --- a/media/tests/omxjpegdecoder/jpeg_decoder_bench.cpp +++ /dev/null @@ -1,114 +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. - */ - -#define LOG_TAG "OmxJpegDecoder" -#include <sys/time.h> -#include <utils/Log.h> - -#include <binder/ProcessState.h> - -#include "SkBitmap.h" -#include "SkImageDecoder.h" -#include "SkStream.h" -#include "omx_jpeg_decoder.h" - -class SkJPEGImageDecoder : public SkImageDecoder { -public: - virtual Format getFormat() const { - return kJPEG_Format; - } - -protected: - virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode); -}; - -int nullObjectReturn(const char msg[]) { - if (msg) { - SkDebugf("--- %s\n", msg); - } - return -1; -} - -static int64_t getNowUs() { - struct timeval tv; - gettimeofday(&tv, NULL); - - return tv.tv_usec + (int64_t) tv.tv_sec * 1000000; -} - -int testDecodeBounds(SkImageDecoder* decoder, SkStream* stream, - SkBitmap* bitmap) { - int64_t startTime = getNowUs(); - SkColorType prefColorType = kN32_SkColorType; - SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodeBounds_Mode; - - // Decode the input stream and then use the bitmap. - if (!decoder->decode(stream, bitmap, prefColorType, decodeMode)) { - return nullObjectReturn("decoder->decode returned false"); - } else { - int64_t delay = getNowUs() - startTime; - printf("WidthxHeight: %dx%d\n", bitmap->width(), bitmap->height()); - printf("Decoding Time in BoundsMode %.1f msec.\n", delay / 1000.0f); - return 0; - } -} - -int testDecodePixels(SkImageDecoder* decoder, SkStream* stream, - SkBitmap* bitmap) { - int64_t startTime = getNowUs(); - SkColorType prefColorType = kN32_SkColorType; - SkImageDecoder::Mode decodeMode = SkImageDecoder::kDecodePixels_Mode; - - // Decode the input stream and then use the bitmap. - if (!decoder->decode(stream, bitmap, prefColorType, decodeMode)) { - return nullObjectReturn("decoder->decode returned false"); - } else { - int64_t delay = getNowUs() - startTime; - printf("Decoding Time in PixelsMode %.1f msec.\n", delay / 1000.0f); - const char* filename = "/sdcard/omxJpegDecodedBitmap.rgba"; - return storeBitmapToFile(bitmap, filename); - } -} - -int testDecoder(SkImageDecoder* decoder, char* filename) { - // test DecodeMode == Pixels - SkStream* stream = new SkFILEStream(filename); - SkBitmap* bitmap = new SkBitmap; - testDecodePixels(decoder, stream, bitmap); - delete bitmap; - - // test DecodeMode == Bounds - stream = new SkFILEStream(filename); - bitmap = new SkBitmap; - testDecodeBounds(decoder, stream, bitmap); - delete bitmap; - - delete decoder; - return 0; -} - -int main(int argc, char** argv) { - android::ProcessState::self()->startThreadPool(); - - printf("Decoding jpeg with libjpeg...\n"); - SkJPEGImageDecoder* libjpeg = new SkJPEGImageDecoder; - testDecoder(libjpeg, argv[1]); - - printf("\nDecoding jpeg with OMX...\n"); - OmxJpegImageDecoder* omx = new OmxJpegImageDecoder; - testDecoder(omx, argv[1]); - return 0; -} diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp b/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp deleted file mode 100644 index 229bfdb..0000000 --- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.cpp +++ /dev/null @@ -1,177 +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. - */ - -#define LOG_TAG "OmxJpegDecoder" -#include <sys/time.h> -#include <utils/Log.h> - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <binder/IServiceManager.h> -#include <binder/ProcessState.h> -#include <media/IMediaPlayerService.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/MediaSource.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/OMXClient.h> -#include <media/stagefright/OMXCodec.h> -#include <SkImage.h> -#include <SkMallocPixelRef.h> - -#include "omx_jpeg_decoder.h" -#include "StreamSource.h" - -using namespace android; - -static void getJpegOutput(MediaBuffer* buffer, const char* filename) { - int size = buffer->range_length(); - int offset = buffer->range_offset(); - FILE *pFile = fopen(filename, "w+"); - - if (pFile == NULL) { - printf("Error: cannot open %s.\n", filename); - } else { - char* data = (char*) buffer->data(); - data += offset; - while (size > 0) { - int numChars = fwrite(data, sizeof(char), 1024, pFile); - int numBytes = numChars * sizeof(char); - size -= numBytes; - data += numBytes; - } - fclose(pFile); - } - return; -} - -extern int storeBitmapToFile(SkBitmap* bitmap, const char* filename) { - bitmap->lockPixels(); - uint8_t* data = (uint8_t *)bitmap->getPixels(); - int size = bitmap->getSize(); - FILE* fp = fopen(filename, "w+"); - - if (NULL == fp) { - printf("Cannot open the output file! \n"); - return -1; - } else { - while (size > 0) { - int numChars = fwrite(data, sizeof(char), 1024, fp); - int numBytes = numChars * sizeof(char); - size -= numBytes; - data += numBytes; - } - fclose(fp); - } - return 0; -} - -static int64_t getNowUs() { - struct timeval tv; - gettimeofday(&tv, NULL); - - return (int64_t)tv.tv_usec + tv.tv_sec * 1000000; -} - -OmxJpegImageDecoder::OmxJpegImageDecoder() { - status_t err = mClient.connect(); - CHECK_EQ(err, (status_t)OK); -} - -OmxJpegImageDecoder::~OmxJpegImageDecoder() { - mClient.disconnect(); -} - -bool OmxJpegImageDecoder::onDecode(SkStream* stream, - SkBitmap* bm, Mode mode) { - sp<MediaSource> source = prepareMediaSource(stream); - sp<MetaData> meta = source->getFormat(); - int width; - int height; - meta->findInt32(kKeyWidth, &width); - meta->findInt32(kKeyHeight, &height); - configBitmapSize( - bm, getPrefColorType(k32Bit_SrcDepth, false), - width, height); - - // mode == DecodeBounds - if (mode == SkImageDecoder::kDecodeBounds_Mode) { - return true; - } - - // mode == DecodePixels - if (!this->allocPixelRef(bm, NULL)) { - ALOGI("Cannot allocPixelRef()!"); - return false; - } - - sp<MediaSource> decoder = getDecoder(&mClient, source); - return decodeSource(decoder, source, bm); -} - -JPEGSource* OmxJpegImageDecoder::prepareMediaSource(SkStream* stream) { - DataSource::RegisterDefaultSniffers(); - sp<DataSource> dataSource = new StreamSource(stream); - return new JPEGSource(dataSource); -} - -sp<MediaSource> OmxJpegImageDecoder::getDecoder( - OMXClient *client, const sp<MediaSource>& source) { - sp<MetaData> meta = source->getFormat(); - sp<MediaSource> decoder = OMXCodec::Create( - client->interface(), meta, false /* createEncoder */, source); - - CHECK(decoder != NULL); - return decoder; -} - -bool OmxJpegImageDecoder::decodeSource(sp<MediaSource> decoder, - const sp<MediaSource>& source, SkBitmap* bm) { - status_t rt = decoder->start(); - if (rt != OK) { - ALOGE("Cannot start OMX Decoder!"); - return false; - } - int64_t startTime = getNowUs(); - MediaBuffer *buffer; - - // decode source - status_t err = decoder->read(&buffer, NULL); - int64_t duration = getNowUs() - startTime; - - if (err != OK) { - CHECK(buffer == NULL); - } - printf("Duration in decoder->read(): %.1f (msecs). \n", - duration / 1E3 ); - - // Copy pixels from buffer to bm. - // May need to check buffer->rawBytes() == bm->rawBytes(). - CHECK_EQ(buffer->size(), bm->getSize()); - memcpy(bm->getPixels(), buffer->data(), buffer->size()); - buffer->release(); - decoder->stop(); - - return true; -} - -void OmxJpegImageDecoder::configBitmapSize(SkBitmap* bm, SkColorType pref, - int width, int height) { - // Set the color space to ARGB_8888 for now (ignoring pref) - // because of limitation in hardware support. - bm->setInfo(SkImageInfo::MakeN32(width, height, kOpaque_SkAlphaType)); -} diff --git a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h b/media/tests/omxjpegdecoder/omx_jpeg_decoder.h deleted file mode 100644 index e487245..0000000 --- a/media/tests/omxjpegdecoder/omx_jpeg_decoder.h +++ /dev/null @@ -1,57 +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. - */ - -#ifndef OMXJPEGIMAGEDECODER -#define OMXJPEGIMAGEDECODER - -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <media/stagefright/JPEGSource.h> -#include <media/stagefright/MediaSource.h> -#include <media/stagefright/OMXClient.h> -#include <media/stagefright/OMXCodec.h> -#include <SkImageDecoder.h> -#include <SkStream.h> - -using namespace android; - -extern int storeBitmapToFile(SkBitmap* bitmap, const char* filename); - -class OmxJpegImageDecoder : public SkImageDecoder { -public: - OmxJpegImageDecoder(); - ~OmxJpegImageDecoder(); - - virtual Format getFormat() const { - return kJPEG_Format; - } - -protected: - virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode mode); - -private: - JPEGSource* prepareMediaSource(SkStream* stream); - sp<MediaSource> getDecoder(OMXClient* client, const sp<MediaSource>& source); - bool decodeSource(sp<MediaSource> decoder, const sp<MediaSource>& source, - SkBitmap* bm); - void configBitmapSize(SkBitmap* bm, SkColorType, int width, int height); - - OMXClient mClient; -}; - -#endif diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index fef1f4a..219de38 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -574,7 +574,8 @@ public class DocumentsActivity extends Activity { // Only sort by size when visible sortSize.setVisible(mState.showSize); - final boolean searchVisible; + boolean searchVisible; + boolean fileSizeVisible = mState.action != ACTION_MANAGE; if (mState.action == ACTION_CREATE || mState.action == ACTION_OPEN_TREE) { createDir.setVisible(cwd != null && cwd.isCreateSupported()); searchVisible = false; @@ -583,6 +584,7 @@ public class DocumentsActivity extends Activity { if (cwd == null) { grid.setVisible(false); list.setVisible(false); + fileSizeVisible = false; } if (mState.action == ACTION_CREATE) { @@ -604,7 +606,7 @@ public class DocumentsActivity extends Activity { ? R.string.menu_file_size_hide : R.string.menu_file_size_show); advanced.setVisible(mState.action != ACTION_MANAGE); - fileSize.setVisible(mState.action != ACTION_MANAGE); + fileSize.setVisible(fileSizeVisible); return true; } diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java index c323a33..066acac 100644 --- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java +++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java @@ -154,7 +154,12 @@ public class ExternalStorageProvider extends DocumentsProvider { if (ROOT_ID_PRIMARY_EMULATED.equals(rootId)) { root.title = getContext().getString(R.string.root_internal_storage); } else { - root.title = volume.getUserLabel(); + final String userLabel = volume.getUserLabel(); + if (!TextUtils.isEmpty(userLabel)) { + root.title = userLabel; + } else { + root.title = volume.getDescription(getContext()); + } } root.docId = getDocIdForFile(path); mRoots.add(root); diff --git a/packages/Keyguard/res/values-sw600dp/bools.xml b/packages/Keyguard/res/values-sw600dp/bools.xml index ddc48c5..00f45c1 100644 --- a/packages/Keyguard/res/values-sw600dp/bools.xml +++ b/packages/Keyguard/res/values-sw600dp/bools.xml @@ -19,7 +19,6 @@ <bool name="show_ongoing_ime_switcher">true</bool> <bool name="kg_share_status_area">false</bool> <bool name="kg_sim_puk_account_full_screen">false</bool> - <bool name="kg_show_ime_at_screen_on">false</bool> <!-- No camera for you, tablet user --> <bool name="kg_enable_camera_default_widget">false</bool> <bool name="kg_center_small_widgets_vertically">true</bool> diff --git a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml index 796cefb..63694a8 100644 --- a/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml +++ b/packages/Keyguard/test/SampleTrustAgent/res/layout/sample_trust_agent_settings.xml @@ -44,4 +44,18 @@ android:paddingTop="8dp" android:paddingBottom="8dp" android:text="Report unlock attempts" /> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content"> + <Button android:id="@+id/check_trusted" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="Keyguard in trusted state?" /> + <TextView android:id="@+id/check_trusted_result" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:layout_weight="1" /> + </LinearLayout> + </LinearLayout>
\ No newline at end of file diff --git a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java index bea74ab..39a599e 100644 --- a/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java +++ b/packages/Keyguard/test/SampleTrustAgent/src/com/android/trustagent/test/SampleTrustAgentSettings.java @@ -18,10 +18,12 @@ package com.android.trustagent.test; import android.annotation.Nullable; import android.app.Activity; +import android.app.KeyguardManager; import android.os.Bundle; import android.view.View; import android.widget.CheckBox; import android.widget.CompoundButton; +import android.widget.TextView; public class SampleTrustAgentSettings extends Activity implements View.OnClickListener, CompoundButton.OnCheckedChangeListener { @@ -30,21 +32,31 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi private CheckBox mReportUnlockAttempts; private CheckBox mManagingTrust; + private TextView mCheckTrustedStateResult; + + private KeyguardManager mKeyguardManager; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); + + mKeyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE); + setContentView(R.layout.sample_trust_agent_settings); findViewById(R.id.enable_trust).setOnClickListener(this); findViewById(R.id.revoke_trust).setOnClickListener(this); findViewById(R.id.crash).setOnClickListener(this); + findViewById(R.id.check_trusted).setOnClickListener(this); mReportUnlockAttempts = (CheckBox) findViewById(R.id.report_unlock_attempts); mReportUnlockAttempts.setOnCheckedChangeListener(this); mManagingTrust = (CheckBox) findViewById(R.id.managing_trust); mManagingTrust.setOnCheckedChangeListener(this); + + mCheckTrustedStateResult = (TextView) findViewById(R.id.check_trusted_result); } @Override @@ -52,6 +64,7 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi super.onResume(); mReportUnlockAttempts.setChecked(SampleTrustAgent.getReportUnlockAttempts(this)); mManagingTrust.setChecked(SampleTrustAgent.getIsManagingTrust(this)); + updateTrustedState(); } @Override @@ -64,6 +77,8 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi SampleTrustAgent.sendRevokeTrust(this); } else if (id == R.id.crash) { throw new RuntimeException("crash"); + } else if (id == R.id.check_trusted) { + updateTrustedState(); } } @@ -75,4 +90,9 @@ public class SampleTrustAgentSettings extends Activity implements View.OnClickLi SampleTrustAgent.setIsManagingTrust(this, isChecked); } } + + private void updateTrustedState() { + mCheckTrustedStateResult.setText(Boolean.toString( + mKeyguardManager.isKeyguardInTrustedState())); + } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java index 85b2490..a54334a 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/PageContentRepository.java @@ -24,6 +24,7 @@ import android.content.ServiceConnection; import android.graphics.Bitmap; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; +import android.net.Uri; import android.os.AsyncTask; import android.os.IBinder; import android.os.ParcelFileDescriptor; @@ -110,13 +111,12 @@ public final class PageContentRepository { mRenderer.close(callback); } - public void destroy(Runnable callback) { - throwIfNotClosed(); + public void destroy() { mState = STATE_DESTROYED; if (DEBUG) { Log.i(LOG_TAG, "STATE_DESTROYED"); } - doDestroy(callback); + mRenderer.destroy(); } public void startPreload(int firstShownPage, int lastShownPage) { @@ -163,21 +163,13 @@ public final class PageContentRepository { try { if (mState != STATE_DESTROYED) { mCloseGuard.warnIfOpen(); - doDestroy(null); + destroy(); } } finally { super.finalize(); } } - private void doDestroy(Runnable callback) { - mState = STATE_DESTROYED; - if (DEBUG) { - Log.i(LOG_TAG, "STATE_DESTROYED"); - } - mRenderer.destroy(callback); - } - private void throwIfNotOpened() { if (mState != STATE_OPENED) { throw new IllegalStateException("Not opened"); @@ -428,6 +420,7 @@ public final class PageContentRepository { private IPdfRenderer mRenderer; private boolean mBoundToService; + private boolean mDestroyed; public AsyncRenderer(Context context, OnMalformedPdfFileListener malformedPdfFileListener) { mContext = context; @@ -441,7 +434,6 @@ public final class PageContentRepository { @Override public void onServiceConnected(ComponentName name, IBinder service) { - mBoundToService = true; synchronized (mLock) { mRenderer = IPdfRenderer.Stub.asInterface(service); mLock.notifyAll(); @@ -465,9 +457,15 @@ public final class PageContentRepository { new AsyncTask<Void, Void, Integer>() { @Override protected void onPreExecute() { + if (mDestroyed) { + cancel(true); + return; + } Intent intent = new Intent(PdfManipulationService.ACTION_GET_RENDERER); intent.setClass(mContext, PdfManipulationService.class); + intent.setData(Uri.fromParts("fake-scheme", String.valueOf(hashCode()), null)); mContext.bindService(intent, AsyncRenderer.this, Context.BIND_AUTO_CREATE); + mBoundToService = true; } @Override @@ -513,6 +511,14 @@ public final class PageContentRepository { new AsyncTask<Void, Void, Void>() { @Override + protected void onPreExecute() { + if (mDestroyed) { + cancel(true); + return; + } + } + + @Override protected Void doInBackground(Void... params) { synchronized (mLock) { try { @@ -534,27 +540,14 @@ public final class PageContentRepository { }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); } - public void destroy(final Runnable callback) { - new AsyncTask<Void, Void, Void>() { - @Override - protected Void doInBackground(Void... params) { - return null; - } - - @Override - public void onPostExecute(Void result) { - if (mBoundToService) { - mBoundToService = false; - mContext.unbindService(AsyncRenderer.this); - } - mPageContentCache.invalidate(); - mPageContentCache.clear(); - if (callback != null) { - callback.run(); - } - - } - }.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR); + public void destroy() { + if (mBoundToService) { + mBoundToService = false; + mContext.unbindService(AsyncRenderer.this); + } + mPageContentCache.invalidate(); + mPageContentCache.clear(); + mDestroyed = true; } public void startPreload(int firstShownPage, int lastShownPage, RenderSpec renderSpec) { diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java index 045a2f9..2cc5e04 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java @@ -78,7 +78,7 @@ public final class PrintSpoolerService extends Service { private static final boolean DEBUG_PERSISTENCE = false; - private static final boolean PERSISTNECE_MANAGER_ENABLED = true; + private static final boolean PERSISTENCE_MANAGER_ENABLED = true; private static final long CHECK_ALL_PRINTJOBS_HANDLED_DELAY = 5000; @@ -728,7 +728,7 @@ public final class PrintSpoolerService extends Service { } public void writeStateLocked() { - if (!PERSISTNECE_MANAGER_ENABLED) { + if (!PERSISTENCE_MANAGER_ENABLED) { return; } if (mWriteStateScheduled) { @@ -935,7 +935,7 @@ public final class PrintSpoolerService extends Service { } public void readStateLocked() { - if (!PERSISTNECE_MANAGER_ENABLED) { + if (!PERSISTENCE_MANAGER_ENABLED) { return; } FileInputStream in = null; diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java index c53fcad..f6ace41 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java +++ b/packages/PrintSpooler/src/com/android/printspooler/model/RemotePrintDocument.java @@ -137,7 +137,7 @@ public final class RemotePrintDocument { private final DeathRecipient mDeathRecipient = new DeathRecipient() { @Override public void binderDied() { - notifyPrintingAppDied(); + onPrintingAppDied(); } }; @@ -268,7 +268,7 @@ public final class RemotePrintDocument { mPrintDocumentAdapter.finish(); mState = STATE_FINISHED; } catch (RemoteException re) { - Log.e(LOG_TAG, "Error calling finish()", re); + Log.e(LOG_TAG, "Error calling finish()"); mState = STATE_FAILED; } } @@ -1108,7 +1108,8 @@ public final class RemotePrintDocument { } } - private void notifyPrintingAppDied() { + private void onPrintingAppDied() { + mState = STATE_FAILED; new Handler(mLooper).post(new Runnable() { @Override public void run() { @@ -1129,7 +1130,7 @@ public final class RemotePrintDocument { public void onDestroy() { final RemotePrintDocument document = mWeakDocument.get(); if (document != null) { - document.notifyPrintingAppDied(); + document.onPrintingAppDied(); } } } diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java index 8a65a2e..02d2715 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/FusedPrintersProvider.java @@ -48,6 +48,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -91,14 +92,14 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> { mPersistenceManager.addPrinterAndWritePrinterHistory(printer); } - private void computeAndDeliverResult(ArrayMap<PrinterId, PrinterInfo> discoveredPrinters, - ArrayMap<PrinterId, PrinterInfo> favoritePrinters) { + private void computeAndDeliverResult(Map<PrinterId, PrinterInfo> discoveredPrinters, + List<PrinterInfo> favoritePrinters) { List<PrinterInfo> printers = new ArrayList<>(); // Add the updated favorite printers. final int favoritePrinterCount = favoritePrinters.size(); for (int i = 0; i < favoritePrinterCount; i++) { - PrinterInfo favoritePrinter = favoritePrinters.valueAt(i); + PrinterInfo favoritePrinter = favoritePrinters.get(i); PrinterInfo updatedPrinter = discoveredPrinters.remove( favoritePrinter.getId()); if (updatedPrinter != null) { @@ -215,21 +216,14 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> { // printer to use its current name instead of the historical one. mPersistenceManager.updatePrintersHistoricalNamesIfNeeded(printers); - ArrayMap<PrinterId, PrinterInfo> printersMap = new ArrayMap<>(); + Map<PrinterId, PrinterInfo> printersMap = new LinkedHashMap<>(); final int printerCount = printers.size(); for (int i = 0; i < printerCount; i++) { PrinterInfo printer = printers.get(i); printersMap.put(printer.getId(), printer); } - ArrayMap<PrinterId, PrinterInfo> favoritePrintersMap = new ArrayMap<>(); - final int favoritePrinterCount = favoritePrinters.size(); - for (int i = 0; i < favoritePrinterCount; i++) { - PrinterInfo favoritePrinter = favoritePrinters.get(i); - favoritePrintersMap.put(favoritePrinter.getId(), favoritePrinter); - } - - computeAndDeliverResult(printersMap, favoritePrintersMap); + computeAndDeliverResult(printersMap, favoritePrinters); } @Override @@ -544,7 +538,7 @@ public final class FusedPrintersProvider extends Loader<List<PrinterInfo>> { mReadHistoryCompleted = true; // Deliver the printers. - updatePrinters(mDiscoverySession.getPrinters(), mHistoricalPrinters); + updatePrinters(mDiscoverySession.getPrinters(), mFavoritePrinters); // Loading the available printers if needed. loadInternal(); diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java index fbf7204..aa79568 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java @@ -484,9 +484,13 @@ public final class PageAdapter extends Adapter implements return selectedPages; } - public void destroy(Runnable callback) { - throwIfNotClosed(); - doDestroy(callback); + public void destroy() { + mPageContentRepository.destroy(); + mCloseGuard.close(); + mState = STATE_DESTROYED; + if (DEBUG) { + Log.i(LOG_TAG, "STATE_DESTROYED"); + } } @Override @@ -494,7 +498,7 @@ public final class PageAdapter extends Adapter implements try { if (mState != STATE_DESTROYED) { mCloseGuard.warnIfOpen(); - doDestroy(null); + destroy(); } } finally { super.finalize(); @@ -741,15 +745,6 @@ public final class PageAdapter extends Adapter implements mPageContentRepository.stopPreload(); } - private void doDestroy(Runnable callback) { - mPageContentRepository.destroy(callback); - mCloseGuard.close(); - mState = STATE_DESTROYED; - if (DEBUG) { - Log.i(LOG_TAG, "STATE_DESTROYED"); - } - } - private void throwIfNotOpened() { if (mState != STATE_OPENED) { throw new IllegalStateException("Not opened"); diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java index 20254f0..15ea9a7 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java @@ -688,43 +688,63 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat PrintAttributes currAttributes = mPrintJob.getAttributes(); PrintAttributes newAttributes = printJobInfo.getAttributes(); - // Take the media size only if the current printer supports is. - MediaSize oldMediaSize = currAttributes.getMediaSize(); - MediaSize newMediaSize = newAttributes.getMediaSize(); - if (!oldMediaSize.equals(newMediaSize)) { - final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount(); - MediaSize newMediaSizePortrait = newAttributes.getMediaSize().asPortrait(); - for (int i = 0; i < mediaSizeCount; i++) { - MediaSize supportedSizePortrait = mMediaSizeSpinnerAdapter.getItem(i) - .value.asPortrait(); - if (supportedSizePortrait.equals(newMediaSizePortrait)) { - currAttributes.setMediaSize(newMediaSize); - mMediaSizeSpinner.setSelection(i); - if (currAttributes.getMediaSize().isPortrait()) { - if (mOrientationSpinner.getSelectedItemPosition() != 0) { - mOrientationSpinner.setSelection(0); + if (newAttributes != null) { + // Take the media size only if the current printer supports is. + MediaSize oldMediaSize = currAttributes.getMediaSize(); + MediaSize newMediaSize = newAttributes.getMediaSize(); + if (!oldMediaSize.equals(newMediaSize)) { + final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount(); + MediaSize newMediaSizePortrait = newAttributes.getMediaSize().asPortrait(); + for (int i = 0; i < mediaSizeCount; i++) { + MediaSize supportedSizePortrait = mMediaSizeSpinnerAdapter.getItem(i) + .value.asPortrait(); + if (supportedSizePortrait.equals(newMediaSizePortrait)) { + currAttributes.setMediaSize(newMediaSize); + mMediaSizeSpinner.setSelection(i); + if (currAttributes.getMediaSize().isPortrait()) { + if (mOrientationSpinner.getSelectedItemPosition() != 0) { + mOrientationSpinner.setSelection(0); + } + } else { + if (mOrientationSpinner.getSelectedItemPosition() != 1) { + mOrientationSpinner.setSelection(1); + } } - } else { - if (mOrientationSpinner.getSelectedItemPosition() != 1) { - mOrientationSpinner.setSelection(1); + break; + } + } + } + + // Take the resolution only if the current printer supports is. + Resolution oldResolution = currAttributes.getResolution(); + Resolution newResolution = newAttributes.getResolution(); + if (!oldResolution.equals(newResolution)) { + PrinterCapabilitiesInfo capabilities = mCurrentPrinter.getCapabilities(); + if (capabilities != null) { + List<Resolution> resolutions = capabilities.getResolutions(); + final int resolutionCount = resolutions.size(); + for (int i = 0; i < resolutionCount; i++) { + Resolution resolution = resolutions.get(i); + if (resolution.equals(newResolution)) { + currAttributes.setResolution(resolution); + break; } } - break; } } - } - // Take the color mode only if the current printer supports it. - final int currColorMode = currAttributes.getColorMode(); - final int newColorMode = newAttributes.getColorMode(); - if (currColorMode != newColorMode) { - final int colorModeCount = mColorModeSpinner.getCount(); - for (int i = 0; i < colorModeCount; i++) { - final int supportedColorMode = mColorModeSpinnerAdapter.getItem(i).value; - if (supportedColorMode == newColorMode) { - currAttributes.setColorMode(newColorMode); - mColorModeSpinner.setSelection(i); - break; + // Take the color mode only if the current printer supports it. + final int currColorMode = currAttributes.getColorMode(); + final int newColorMode = newAttributes.getColorMode(); + if (currColorMode != newColorMode) { + final int colorModeCount = mColorModeSpinner.getCount(); + for (int i = 0; i < colorModeCount; i++) { + final int supportedColorMode = mColorModeSpinnerAdapter.getItem(i).value; + if (supportedColorMode == newColorMode) { + currAttributes.setColorMode(newColorMode); + mColorModeSpinner.setSelection(i); + break; + } } } } @@ -1392,12 +1412,16 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mCopiesEditText.setEnabled(true); mCopiesEditText.setFocusableInTouchMode(true); } else { + CharSequence text = mCopiesEditText.getText(); + if (TextUtils.isEmpty(text) || !MIN_COPIES_STRING.equals(text.toString())) { + mCopiesEditText.setText(MIN_COPIES_STRING); + } mCopiesEditText.setEnabled(false); mCopiesEditText.setFocusable(false); } if (mCopiesEditText.getError() == null && TextUtils.isEmpty(mCopiesEditText.getText())) { - mCopiesEditText.setText(String.valueOf(MIN_COPIES)); + mCopiesEditText.setText(MIN_COPIES_STRING); mCopiesEditText.requestFocus(); } } @@ -1592,15 +1616,9 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat mSpoolerProvider.destroy(); mPrintedDocument.finish(); mPrintedDocument.destroy(); - mPrintPreviewController.destroy(new Runnable() { - @Override - public void run() { - finish(); - } - }); - } else { - finish(); + mPrintPreviewController.destroy(); } + finish(); } private final class SpinnerItem<T> { diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java index e4eab10..15342ae 100644 --- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java +++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintPreviewController.java @@ -192,15 +192,10 @@ class PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallba }); } - public void destroy(Runnable callback) { - if (mPageAdapter.isOpened()) { - Message operation = mHandler.obtainMessage(MyHandler.MSG_CLOSE); - mHandler.enqueueOperation(operation); - } - - Message operation = mHandler.obtainMessage(MyHandler.MSG_DESTROY); - operation.obj = callback; - mHandler.enqueueOperation(operation); + public void destroy() { + mHandler.cancelQueuedOperations(); + mRecyclerView.setAdapter(null); + mPageAdapter.destroy(); } @Override @@ -226,7 +221,6 @@ class PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallba private final class MyHandler extends Handler { public static final int MSG_OPEN = 1; public static final int MSG_CLOSE = 2; - public static final int MSG_DESTROY = 3; public static final int MSG_UPDATE = 4; public static final int MSG_START_PRELOAD = 5; @@ -246,6 +240,10 @@ class PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallba super(looper, null, false); } + public void cancelQueuedOperations() { + mPendingOperations.clear(); + } + public void enqueueOperation(Message message) { mPendingOperations.add(message); handleNextOperation(); @@ -294,13 +292,6 @@ class PrintPreviewController implements MutexFileProvider.OnReleaseRequestCallba }); } break; - case MSG_DESTROY: { - Runnable callback = (Runnable) message.obj; - mRecyclerView.setAdapter(null); - mPageAdapter.destroy(callback); - handleNextOperation(); - } break; - case MSG_UPDATE: { SomeArgs args = (SomeArgs) message.obj; PageRange[] writtenPages = (PageRange[]) args.arg1; diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk index da929ae..c16f7b6 100644 --- a/packages/SettingsProvider/Android.mk +++ b/packages/SettingsProvider/Android.mk @@ -5,7 +5,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-subdir-java-files) -LOCAL_JAVA_LIBRARIES := telephony-common +LOCAL_JAVA_LIBRARIES := telephony-common ims-common LOCAL_PACKAGE_NAME := SettingsProvider LOCAL_CERTIFICATE := platform diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml index efba03d..16c6075 100644 --- a/packages/SettingsProvider/res/values/defaults.xml +++ b/packages/SettingsProvider/res/values/defaults.xml @@ -21,6 +21,7 @@ <integer name="def_screen_off_timeout">60000</integer> <integer name="def_sleep_timeout">-1</integer> <bool name="def_airplane_mode_on">false</bool> + <bool name="def_theater_mode_on">false</bool> <!-- Comma-separated list of bluetooth, wifi, and cell. --> <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string> <string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string> diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java index b17b4cc..eea97ea 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java @@ -43,6 +43,7 @@ import android.provider.Settings.Secure; import android.text.TextUtils; import android.util.Log; +import com.android.ims.ImsConfig; import com.android.internal.content.PackageHelper; import com.android.internal.telephony.RILConstants; import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager; @@ -70,7 +71,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion' // is properly propagated through your change. Not doing so will result in a loss of user // settings. - private static final int DATABASE_VERSION = 113; + private static final int DATABASE_VERSION = 116; private Context mContext; private int mUserHandle; @@ -567,7 +568,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { stmt = db.compileStatement("INSERT OR IGNORE INTO system(name,value)" + " VALUES(?,?);"); loadSetting(stmt, Settings.System.VOLUME_BLUETOOTH_SCO, - AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]); + AudioService.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO)); db.setTransactionSuccessful(); } finally { db.endTransaction(); @@ -1827,6 +1828,43 @@ public class DatabaseHelper extends SQLiteOpenHelper { upgradeVersion = 113; } + // We skipped 114 to handle a merge conflict with the introduction of theater mode. + + if (upgradeVersion < 115) { + if (mUserHandle == UserHandle.USER_OWNER) { + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)" + + " VALUES(?,?);"); + loadBooleanSetting(stmt, Global.THEATER_MODE_ON, + R.bool.def_theater_mode_on); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + } + upgradeVersion = 115; + } + + if (upgradeVersion < 116) { + if (mUserHandle == UserHandle.USER_OWNER) { + db.beginTransaction(); + SQLiteStatement stmt = null; + try { + stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)" + + " VALUES(?,?);"); + loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON); + db.setTransactionSuccessful(); + } finally { + db.endTransaction(); + if (stmt != null) stmt.close(); + } + } + upgradeVersion = 116; + } + // *** Remember to update DATABASE_VERSION above! if (upgradeVersion != currentVersion) { @@ -2131,25 +2169,25 @@ public class DatabaseHelper extends SQLiteOpenHelper { + " VALUES(?,?);"); loadSetting(stmt, Settings.System.VOLUME_MUSIC, - AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_MUSIC]); + AudioService.getDefaultStreamVolume(AudioManager.STREAM_MUSIC)); loadSetting(stmt, Settings.System.VOLUME_RING, - AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_RING]); + AudioService.getDefaultStreamVolume(AudioManager.STREAM_RING)); loadSetting(stmt, Settings.System.VOLUME_SYSTEM, - AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_SYSTEM]); + AudioService.getDefaultStreamVolume(AudioManager.STREAM_SYSTEM)); loadSetting( stmt, Settings.System.VOLUME_VOICE, - AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_VOICE_CALL]); + AudioService.getDefaultStreamVolume(AudioManager.STREAM_VOICE_CALL)); loadSetting(stmt, Settings.System.VOLUME_ALARM, - AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_ALARM]); + AudioService.getDefaultStreamVolume(AudioManager.STREAM_ALARM)); loadSetting( stmt, Settings.System.VOLUME_NOTIFICATION, - AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_NOTIFICATION]); + AudioService.getDefaultStreamVolume(AudioManager.STREAM_NOTIFICATION)); loadSetting( stmt, Settings.System.VOLUME_BLUETOOTH_SCO, - AudioManager.DEFAULT_STREAM_VOLUME[AudioManager.STREAM_BLUETOOTH_SCO]); + AudioService.getDefaultStreamVolume(AudioManager.STREAM_BLUETOOTH_SCO)); // By default: // - ringtones, notification, system and music streams are affected by ringer mode @@ -2423,6 +2461,9 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.Global.AIRPLANE_MODE_ON, R.bool.def_airplane_mode_on); + loadBooleanSetting(stmt, Settings.Global.THEATER_MODE_ON, + R.bool.def_theater_mode_on); + loadStringSetting(stmt, Settings.Global.AIRPLANE_MODE_RADIOS, R.string.def_airplane_mode_radios); @@ -2569,6 +2610,7 @@ public class DatabaseHelper extends SQLiteOpenHelper { loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED, R.bool.def_guest_user_enabled); + loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED, ImsConfig.FeatureValueConstants.ON); // --- New global settings start here } finally { if (stmt != null) stmt.close(); diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index 7e6afa6..3c44245 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -92,6 +92,7 @@ <uses-permission android:name="android.permission.FRAME_STATS" /> <uses-permission android:name="android.permission.BIND_APPWIDGET" /> <uses-permission android:name="android.permission.UPDATE_APP_OPS_STATS" /> + <uses-permission android:name="android.permission.MODIFY_APPWIDGET_BIND_PERMISSIONS"/> <application android:label="@string/app_label"> <provider diff --git a/packages/Shell/res/layout/confirm_repeat.xml b/packages/Shell/res/layout/confirm_repeat.xml index dc250d6..d12f467 100644 --- a/packages/Shell/res/layout/confirm_repeat.xml +++ b/packages/Shell/res/layout/confirm_repeat.xml @@ -22,13 +22,18 @@ android:paddingEnd="16dip" android:paddingTop="8dip" android:paddingBottom="16dip" - android:orientation="vertical"> - <TextView + android:orientation="vertical" + android:keepScreenOn="true"> + <ScrollView android:layout_width="match_parent" - android:layout_height="wrap_content" - android:text="@string/bugreport_confirm" - android:paddingBottom="16dip" - style="?android:attr/textAppearanceMedium" /> + android:layout_height="wrap_content"> + <TextView + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:text="@string/bugreport_confirm" + android:paddingBottom="16dip" + style="?android:attr/textAppearanceMedium" /> + </ScrollView> <CheckBox android:id="@android:id/checkbox" android:layout_width="match_parent" diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java index 02a3aeb..48ecaa5 100644 --- a/packages/Shell/src/com/android/shell/BugreportReceiver.java +++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java @@ -92,6 +92,7 @@ public class BugreportReceiver extends BroadcastReceiver { .setContentIntent(PendingIntent.getActivity( context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT)) .setAutoCancel(true) + .setLocalOnly(true) .setColor(context.getResources().getColor( com.android.internal.R.color.system_notification_accent_color)); diff --git a/packages/SystemUI/res/drawable/qs_background_primary.xml b/packages/SystemUI/res/drawable/qs_background_primary.xml index b4e311f..e33ff1e 100644 --- a/packages/SystemUI/res/drawable/qs_background_primary.xml +++ b/packages/SystemUI/res/drawable/qs_background_primary.xml @@ -13,11 +13,8 @@ See the License for the specific language governing permissions and limitations under the License. --> -<shape xmlns:android="http://schemas.android.com/apk/res/android"> +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:top="@dimen/notification_material_rounded_rect_radius_negative" > <solid android:color="@color/system_primary_color" /> - <corners - android:topLeftRadius="0dp" - android:topRightRadius="0dp" - android:bottomLeftRadius="@dimen/notification_material_rounded_rect_radius" - android:bottomRightRadius="@dimen/notification_material_rounded_rect_radius"/> + <corners android:radius="@dimen/notification_material_rounded_rect_radius"/> </shape> diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm.xml b/packages/SystemUI/res/drawable/stat_sys_alarm.xml index 5754569..48c2222 100644 --- a/packages/SystemUI/res/drawable/stat_sys_alarm.xml +++ b/packages/SystemUI/res/drawable/stat_sys_alarm.xml @@ -17,7 +17,7 @@ android:insetLeft="2.5dp" android:insetRight="2.5dp"> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="22dp" + android:width="17dp" android:height="17dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/packages/SystemUI/res/drawable/stat_sys_cast.xml b/packages/SystemUI/res/drawable/stat_sys_cast.xml index df28638..4a7cbb3 100644 --- a/packages/SystemUI/res/drawable/stat_sys_cast.xml +++ b/packages/SystemUI/res/drawable/stat_sys_cast.xml @@ -16,7 +16,7 @@ Copyright (C) 2014 The Android Open Source Project <inset xmlns:android="http://schemas.android.com/apk/res/android" android:insetLeft="2.5dp" android:insetRight="2.5dp"> - <vector android:width="22dp" + <vector android:width="17dp" android:height="17dp" android:viewportWidth="48.0" android:viewportHeight="48.0"> diff --git a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml new file mode 100644 index 0000000..01e8888 --- /dev/null +++ b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml @@ -0,0 +1,29 @@ +<!-- +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. +--> +<inset xmlns:android="http://schemas.android.com/apk/res/android" + android:insetLeft="2.5dp" + android:insetRight="2.5dp"> + <vector + android:width="17.0dp" + android:height="17.0dp" + android:viewportWidth="48.0" + android:viewportHeight="48.0"> + + <path + android:fillColor="#FFFFFFFF" + android:pathData="M24.000000,22.000000c-2.200000,0.000000 -4.000000,1.800000 -4.000000,4.000000c0.000000,2.200000 1.800000,4.000000 4.000000,4.000000c2.200000,0.000000 4.000000,-1.800000 4.000000,-4.000000C28.000000,23.799999 26.200001,22.000000 24.000000,22.000000zM36.000000,26.000000c0.000000,-6.600000 -5.400000,-12.000000 -12.000000,-12.000000c-6.600000,0.000000 -12.000000,5.400000 -12.000000,12.000000c0.000000,4.400000 2.400000,8.300000 6.000000,10.400000l2.000000,-3.500000c-2.400000,-1.400000 -4.000000,-3.900000 -4.000000,-6.900000c0.000000,-4.400000 3.600000,-8.000000 8.000000,-8.000000s8.000000,3.600000 8.000000,8.000000c0.000000,3.000000 -1.600000,5.500000 -4.000000,6.900000l2.000000,3.500000C33.599998,34.299999 36.000000,30.400000 36.000000,26.000000zM24.000000,6.000000C13.000000,6.000000 4.000000,15.000000 4.000000,26.000000c0.000000,7.400000 4.000000,13.800000 10.000000,17.299999l2.000000,-3.500000c-4.800000,-2.800000 -8.000000,-7.900000 -8.000000,-13.800000c0.000000,-8.800000 7.200000,-16.000000 16.000000,-16.000000s16.000000,7.200000 16.000000,16.000000c0.000000,5.900000 -3.200000,11.100000 -8.000000,13.800000l2.000000,3.500000c6.000000,-3.500000 10.000000,-9.900000 10.000000,-17.299999C44.000000,15.000000 35.000000,6.000000 24.000000,6.000000z"/> + </vector> +</inset> diff --git a/packages/SystemUI/res/drawable/stat_sys_location.xml b/packages/SystemUI/res/drawable/stat_sys_location.xml index 433f73b..33ac5cd 100644 --- a/packages/SystemUI/res/drawable/stat_sys_location.xml +++ b/packages/SystemUI/res/drawable/stat_sys_location.xml @@ -17,7 +17,7 @@ android:insetLeft="1.5dp" android:insetRight="1.5dp"> <vector - android:width="20dp" + android:width="17dp" android:height="17dp" android:viewportWidth="48.0" android:viewportHeight="48.0"> diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml index f017d58..eb7b4fc 100644 --- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml +++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml @@ -16,7 +16,7 @@ Copyright (C) 2014 The Android Open Source Project <inset xmlns:android="http://schemas.android.com/apk/res/android" android:insetLeft="3dp" android:insetRight="3dp"> - <vector android:width="24dp" + <vector android:width="18dp" android:height="18dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml index 9dabb03..1262617 100644 --- a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml +++ b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml @@ -16,7 +16,7 @@ Copyright (C) 2014 The Android Open Source Project <inset xmlns:android="http://schemas.android.com/apk/res/android" android:insetLeft="2.5dp" android:insetRight="2.5dp"> - <vector android:width="23dp" + <vector android:width="18dp" android:height="18dp" android:viewportWidth="24.0" android:viewportHeight="24.0"> diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml b/packages/SystemUI/res/drawable/stat_sys_zen_none.xml index 7573de0..92914a8 100644 --- a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml +++ b/packages/SystemUI/res/drawable/stat_sys_zen_none.xml @@ -16,7 +16,7 @@ Copyright (C) 2014 The Android Open Source Project <inset xmlns:android="http://schemas.android.com/apk/res/android" android:insetLeft="2.5dp" android:insetRight="2.5dp"> - <vector android:width="22dp" + <vector android:width="17dp" android:height="17dp" android:viewportWidth="48.0" android:viewportHeight="48.0"> diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml index 5889c55..f45aa85 100644 --- a/packages/SystemUI/res/layout/signal_cluster_view.xml +++ b/packages/SystemUI/res/layout/signal_cluster_view.xml @@ -24,6 +24,7 @@ android:layout_width="wrap_content" android:gravity="center_vertical" android:orientation="horizontal" + android:paddingEnd="@dimen/signal_cluster_battery_padding" > <ImageView android:id="@+id/vpn" diff --git a/packages/SystemUI/res/layout/system_icons.xml b/packages/SystemUI/res/layout/system_icons.xml index 21386ef..943e846 100644 --- a/packages/SystemUI/res/layout/system_icons.xml +++ b/packages/SystemUI/res/layout/system_icons.xml @@ -36,6 +36,5 @@ <com.android.systemui.BatteryMeterView android:id="@+id/battery" android:layout_height="14.5dp" android:layout_width="9.5dp" - android:layout_marginBottom="@dimen/battery_margin_bottom" - android:layout_marginStart="7dp"/> + android:layout_marginBottom="@dimen/battery_margin_bottom"/> </LinearLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout/zen_mode_condition.xml b/packages/SystemUI/res/layout/zen_mode_condition.xml index ad0d2dc..a9ad1fc 100644 --- a/packages/SystemUI/res/layout/zen_mode_condition.xml +++ b/packages/SystemUI/res/layout/zen_mode_condition.xml @@ -29,16 +29,34 @@ android:layout_alignParentStart="true" android:gravity="center" /> - <TextView - android:id="@android:id/title" + <LinearLayout + android:id="@android:id/content" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" + android:layout_centerVertical="true" + android:orientation="vertical" android:layout_toEndOf="@android:id/checkbox" - android:layout_toStartOf="@android:id/button1" - android:ellipsize="end" - android:gravity="center_vertical" - android:maxLines="1" - android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" /> + android:layout_toStartOf="@android:id/button1"> + + <TextView + android:id="@android:id/text1" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + android:textAlignment="viewStart" + android:maxLines="1" + android:textAppearance="@style/TextAppearance.QS.DetailItemPrimary" /> + + <TextView + android:id="@android:id/text2" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:ellipsize="end" + android:textAlignment="viewStart" + android:maxLines="1" + android:textAppearance="@style/TextAppearance.QS.DetailItemSecondary" /> + + </LinearLayout> <ImageView android:id="@android:id/button1" diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index ae9e305..c93e0e7 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -33,8 +33,8 @@ <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"مستمر"</string> <string name="status_bar_latest_events_title" msgid="6594767438577593172">"الإشعارات"</string> <string name="battery_low_title" msgid="6456385927409742437">"البطارية منخفضة"</string> - <string name="battery_low_percent_format" msgid="1077244949318261761">"المتبقي: <xliff:g id="NUMBER">%d%%</xliff:g>"</string> - <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"يتبقى <xliff:g id="NUMBER">%d%%</xliff:g>. وضع توفير الطاقة قيد التشغيل."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"المتبقي: <xliff:g id="NUMBER">%s</xliff:g>"</string> + <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"يتبقى <xliff:g id="NUMBER">%s</xliff:g>. وضع توفير الطاقة قيد التشغيل."</string> <string name="invalid_charger" msgid="4549105996740522523">"شحن USB غير معتمد.\nاستخدم الشاحن الموفر فقط."</string> <string name="invalid_charger_title" msgid="3515740382572798460">"لا يمكن إجراء الشحن عبر USB."</string> <string name="invalid_charger_text" msgid="5474997287953892710">"لا تستخدم سوى الشاحن المزوّد."</string> @@ -187,8 +187,6 @@ <string name="start_dreams" msgid="7219575858348719790">"حلم اليقظة"</string> <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string> <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"وضع الطائرة"</string> - <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"جارٍ الشحن، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> - <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"تم الشحن"</string> <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوتوث"</string> <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث (<xliff:g id="NUMBER">%d</xliff:g> من الأجهزة)"</string> <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"إيقاف البلوتوث"</string> @@ -293,7 +291,6 @@ <string name="battery_saver_notification_title" msgid="237918726750955859">"وضع توفير الطاقة قيد التشغيل"</string> <string name="battery_saver_notification_text" msgid="7796554871101546872">"تم تقليل أداء الجهاز."</string> <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"فتح إعدادات وضع توفير الطاقة"</string> - <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>%%"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"المحتويات مخفية"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> سيبدأ التقاط كل شيء يتم عرضه على الشاشة."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"عدم الإظهار مرة أخرى"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 73a5800..cbf653f 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -33,8 +33,8 @@ <string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"در حال انجام"</string> <string name="status_bar_latest_events_title" msgid="6594767438577593172">"اعلانها"</string> <string name="battery_low_title" msgid="6456385927409742437">"شارژ باتری کم است"</string> - <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%d%%</xliff:g> باقیمانده است"</string> - <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%d%%</xliff:g> باقی مانده است. ذخیره کننده باتری روشن است."</string> + <string name="battery_low_percent_format" msgid="1077244949318261761">"<xliff:g id="NUMBER">%s</xliff:g> باقیمانده است"</string> + <string name="battery_low_percent_format_saver_started" msgid="6534746636002666456">"<xliff:g id="NUMBER">%s</xliff:g> باقی مانده است. ذخیره کننده باتری روشن است."</string> <string name="invalid_charger" msgid="4549105996740522523">"شارژ USB پشتیبانی نمیشود.\nفقط از شارژر ارائه شده استفاده کنید."</string> <string name="invalid_charger_title" msgid="3515740382572798460">"شارژ با USB پشتیبانی نمیشود."</string> <string name="invalid_charger_text" msgid="5474997287953892710">"فقط از شارژر ارائه شده استفاده کنید."</string> @@ -187,8 +187,6 @@ <string name="start_dreams" msgid="7219575858348719790">"رویاپردازی"</string> <string name="ethernet_label" msgid="7967563676324087464">"اترنت"</string> <string name="quick_settings_airplane_mode_label" msgid="5510520633448831350">"حالت هواپیما"</string> - <string name="quick_settings_battery_charging_label" msgid="490074774465309209">"در حال شارژ، <xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string> - <string name="quick_settings_battery_charged_label" msgid="8865413079414246081">"شارژ شد"</string> <string name="quick_settings_bluetooth_label" msgid="6304190285170721401">"بلوتوث"</string> <string name="quick_settings_bluetooth_multiple_devices_label" msgid="3912245565613684735">"بلوتوث ( <xliff:g id="NUMBER">%d</xliff:g> دستگاه)"</string> <string name="quick_settings_bluetooth_off_label" msgid="8159652146149219937">"بلوتوث خاموش"</string> @@ -293,7 +291,6 @@ <string name="battery_saver_notification_title" msgid="237918726750955859">"ذخیره کننده باتری روشن است."</string> <string name="battery_saver_notification_text" msgid="7796554871101546872">"عملکرد دستگاه کاهش یافته است."</string> <string name="battery_saver_notification_action_text" msgid="7546297220816993504">"باز کردن تنظیمات ذخیره کننده باتری"</string> - <string name="battery_level_template" msgid="1609636980292580020">"<xliff:g id="LEVEL">%d</xliff:g>٪٪"</string> <string name="notification_hidden_text" msgid="1135169301897151909">"محتواها پنهان هستند"</string> <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> شروع به ضبط هر چیزی میکند که در صفحهنمایش شما نمایش داده میشود."</string> <string name="media_projection_remember_text" msgid="3103510882172746752">"دوباره نشان داده نشود"</string> diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml index cd82c45..4f867a0 100644 --- a/packages/SystemUI/res/values/config.xml +++ b/packages/SystemUI/res/values/config.xml @@ -238,8 +238,11 @@ <!-- Volume: time to delay dismissing the volume panel after a click is performed --> <integer name="volume_panel_dismiss_delay">200</integer> - <!-- Tiles with feature timeouts: number of days to show after feature is used. --> - <integer name="days_to_show_timeout_tiles">30</integer> + <!-- Hotspot tile: number of days to show after feature is used. --> + <integer name="days_to_show_hotspot_tile">30</integer> + + <!-- Color inversion tile: number of days to show after feature is used. --> + <integer name="days_to_show_color_inversion_tile">7</integer> <!-- Number of times to show the strong alarm warning text in the volume dialog --> <integer name="zen_mode_alarm_warning_threshold">5</integer> @@ -249,5 +252,8 @@ <!-- Zen toast visibility duration --> <integer name="zen_toast_visible_duration">500</integer> + + <!-- Enable the default volume dialog --> + <bool name="enable_volume_ui">true</bool> </resources> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 4f41cd5..07573e0 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -239,7 +239,7 @@ <dimen name="recents_search_bar_space_height">64dp</dimen> <!-- The side padding for the task stack as a percentage of the width. --> - <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.04444</item> + <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.03333</item> <!-- The overscroll percentage allowed on the stack. --> <item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item> @@ -358,6 +358,9 @@ <!-- radius of the corners of the material rounded rect background --> <dimen name="notification_material_rounded_rect_radius">2dp</dimen> + <!-- radius of the corners of the material rounded rect background but negative--> + <dimen name="notification_material_rounded_rect_radius_negative">-2dp</dimen> + <!-- end margin for multi user switch in expanded quick settings --> <dimen name="multi_user_switch_expanded_margin">8dp</dimen> @@ -505,4 +508,10 @@ <dimen name="fake_shadow_inset">1dp</dimen> <dimen name="fake_shadow_size">8dp</dimen> + + <!-- Padding between signal cluster and battery icon --> + <dimen name="signal_cluster_battery_padding">7dp</dimen> + + <!-- Padding for signal cluster and battery icon when there are not icons in signal cluster --> + <dimen name="no_signal_cluster_battery_padding">3dp</dimen> </resources> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 71b9b61..7a0d655 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -62,12 +62,12 @@ <string name="battery_low_title">Battery is low</string> <!-- A message that appears when the battery level is getting low in a dialog. This is - appened to the subtitle of the low battery alert. "number" is the percentage of battery + appened to the subtitle of the low battery alert. "percentage" is the percentage of battery remaining [CHAR LIMIT=none]--> - <string name="battery_low_percent_format"><xliff:g id="number">%d%%</xliff:g> remaining</string> + <string name="battery_low_percent_format"><xliff:g id="percentage">%s</xliff:g> remaining</string> <!-- Same as battery_low_percent_format, with a notice about battery saver if on. [CHAR LIMIT=none]--> - <string name="battery_low_percent_format_saver_started"><xliff:g id="number">%d%%</xliff:g> remaining. Battery saver is on.</string> + <string name="battery_low_percent_format_saver_started"><xliff:g id="percentage">%s</xliff:g> remaining. Battery saver is on.</string> <!-- A message that appears when a USB charger is plugged in and the device does not support charging on it. That is, a charger that fits into the USB port and goes into @@ -115,11 +115,6 @@ <!-- Label in system panel saying the device will show notifications [CHAR LIMIT=30] --> <string name="status_bar_settings_notifications">Notifications</string> - <!-- Text to display next to the graphical battery meter. [CHAR LIMIT=3] --> - <string name="status_bar_settings_battery_meter_format" translatable="false"> - <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g> - </string> - <!-- Separator for PLMN and SPN in network name. --> <string name="status_bar_network_name_separator" translatable="false">|</string> @@ -559,10 +554,6 @@ <!-- QuickSettings: Airplane mode [CHAR LIMIT=NONE] --> <string name="quick_settings_airplane_mode_label">Airplane mode</string> - <!-- QuickSettings: Battery Charging [CHAR LIMIT=NONE] --> - <string name="quick_settings_battery_charging_label">Charging, <xliff:g id="number">%d</xliff:g><xliff:g id="percent">%%</xliff:g></string> - <!-- QuickSettings: Battery Charged [CHAR LIMIT=NONE] --> - <string name="quick_settings_battery_charged_label">Charged</string> <!-- QuickSettings: Bluetooth [CHAR LIMIT=NONE] --> <string name="quick_settings_bluetooth_label">Bluetooth</string> <!-- QuickSettings: Bluetooth (Multiple) [CHAR LIMIT=NONE] --> @@ -666,8 +657,8 @@ <string name="recents_empty_message">Your recent screens appear here</string> <!-- Recents: The info panel app info button string. [CHAR LIMIT=NONE] --> <string name="recents_app_info_button_label">Application Info</string> - <!-- Recents: The lock-to-app button. [CHAR LIMIT=NONE] --> - <string name="recents_lock_to_app_button_label">lock to app</string> + <!-- Recents: The screen pinning button. [CHAR LIMIT=NONE] --> + <string name="recents_lock_to_app_button_label">screen pinning</string> <!-- Recents: Temporary string for the button in the recents search bar. [CHAR LIMIT=NONE] --> <string name="recents_search_bar_label">search</string> <!-- Recents: Launch error string. [CHAR LIMIT=NONE] --> @@ -813,9 +804,6 @@ <!-- Battery saver notification action text. [CHAR LIMIT=60] --> <string name="battery_saver_notification_action_text">Turn off battery saver</string> - <!-- Battery level for expanded quick settings [CHAR LIMIT=2] --> - <string name="battery_level_template"><xliff:g id="level" example="45">%d</xliff:g>%%</string> - <!-- Text shown in place of notification contents when the notification is hidden on a secure lockscreen --> <string name="notification_hidden_text">Contents hidden</string> diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java index f184ad2..f5df1a9 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java @@ -43,6 +43,7 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar; import com.android.systemui.statusbar.phone.SystemUIDialog; import java.io.PrintWriter; +import java.text.NumberFormat; public class PowerNotificationWarnings implements PowerUI.WarningsUI { private static final String TAG = PowerUI.TAG + ".Notification"; @@ -143,7 +144,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { showSaverNotification(); mShowing = SHOWING_SAVER; } else { - mNoMan.cancel(TAG_NOTIFICATION, ID_NOTIFICATION); + mNoMan.cancelAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, UserHandle.ALL); mShowing = SHOWING_NOTHING; } } @@ -157,7 +158,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .setContentTitle(mContext.getString(R.string.invalid_charger_title)) .setContentText(mContext.getString(R.string.invalid_charger_text)) .setPriority(Notification.PRIORITY_MAX) - .setCategory(Notification.CATEGORY_SYSTEM) .setVisibility(Notification.VISIBILITY_PUBLIC) .setColor(mContext.getResources().getColor( com.android.internal.R.color.system_notification_accent_color)); @@ -165,22 +165,22 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { if (n.headsUpContentView != null) { n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE); } - mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT); + mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL); } private void showWarningNotification() { final int textRes = mSaver ? R.string.battery_low_percent_format_saver_started : R.string.battery_low_percent_format; + final String percentage = NumberFormat.getPercentInstance().format((double) mBatteryLevel / 100.0); final Notification.Builder nb = new Notification.Builder(mContext) .setSmallIcon(R.drawable.ic_power_low) // Bump the notification when the bucket dropped. .setWhen(mBucketDroppedNegativeTimeMs) .setShowWhen(false) .setContentTitle(mContext.getString(R.string.battery_low_title)) - .setContentText(mContext.getString(textRes, mBatteryLevel)) + .setContentText(mContext.getString(textRes, percentage)) .setOnlyAlertOnce(true) .setPriority(Notification.PRIORITY_MAX) - .setCategory(Notification.CATEGORY_SYSTEM) .setVisibility(Notification.VISIBILITY_PUBLIC) .setColor(mContext.getResources().getColor( com.android.internal.R.color.battery_saver_mode_color)); @@ -202,7 +202,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { if (n.headsUpContentView != null) { n.headsUpContentView.setViewVisibility(com.android.internal.R.id.right_icon, View.GONE); } - mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.CURRENT); + mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, n, UserHandle.ALL); } private void showSaverNotification() { @@ -212,7 +212,6 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { .setContentText(mContext.getString(R.string.battery_saver_notification_text)) .setOngoing(true) .setShowWhen(false) - .setCategory(Notification.CATEGORY_SYSTEM) .setVisibility(Notification.VISIBILITY_PUBLIC) .setColor(mContext.getResources().getColor( com.android.internal.R.color.battery_saver_mode_color)); @@ -220,7 +219,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { if (hasSaverSettings()) { nb.setContentIntent(pendingActivity(mOpenSaverSettings)); } - mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.CURRENT); + mNoMan.notifyAsUser(TAG_NOTIFICATION, ID_NOTIFICATION, nb.build(), UserHandle.ALL); } private void addStopSaverAction(Notification.Builder nb) { @@ -341,6 +340,11 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { updateNotification(); } + @Override + public void userSwitched() { + updateNotification(); + } + private void showStartSaverConfirmation() { if (mSaverConfirmation != null) return; final SystemUIDialog d = new SystemUIDialog(mContext); @@ -370,7 +374,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI { filter.addAction(ACTION_SHOW_BATTERY_SETTINGS); filter.addAction(ACTION_START_SAVER); filter.addAction(ACTION_STOP_SAVER); - mContext.registerReceiver(this, filter, null, mHandler); + mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, mHandler); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java index d3c7dee..9459740 100644 --- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java +++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java @@ -137,6 +137,7 @@ public class PowerUI extends SystemUI { filter.addAction(Intent.ACTION_BATTERY_CHANGED); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); + filter.addAction(Intent.ACTION_USER_SWITCHED); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING); filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED); mContext.registerReceiver(this, filter, null, mHandler); @@ -207,6 +208,8 @@ public class PowerUI extends SystemUI { mScreenOffTime = SystemClock.elapsedRealtime(); } else if (Intent.ACTION_SCREEN_ON.equals(action)) { mScreenOffTime = -1; + } else if (Intent.ACTION_USER_SWITCHED.equals(action)) { + mWarnings.userSwitched(); } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGED.equals(action)) { updateSaverMode(); } else if (PowerManager.ACTION_POWER_SAVE_MODE_CHANGING.equals(action)) { @@ -256,6 +259,7 @@ public class PowerUI extends SystemUI { void updateLowBatteryWarning(); boolean isInvalidChargerWarningShowing(); void dump(PrintWriter pw); + void userSwitched(); } } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java index eb4560d..111484b 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSDetailClipper.java @@ -55,7 +55,6 @@ public class QSDetailClipper { if (listener != null) { mAnimator.addListener(listener); } - mDetail.setLayerType(View.LAYER_TYPE_HARDWARE, null); if (in) { mBackground.startTransition((int)(mAnimator.getDuration() * 0.6)); mAnimator.addListener(mVisibleOnStart); @@ -82,7 +81,6 @@ public class QSDetailClipper { } public void onAnimationEnd(Animator animation) { - mDetail.setLayerType(View.LAYER_TYPE_NONE, null); mAnimator = null; } }; @@ -90,7 +88,6 @@ public class QSDetailClipper { private final AnimatorListenerAdapter mGoneOnEnd = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - mDetail.setLayerType(View.LAYER_TYPE_NONE, null); mDetail.setVisibility(View.GONE); mBackground.resetTransition(); mAnimator = null; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java index 3574877..d5c90d0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java @@ -132,6 +132,7 @@ public class QSTileView extends ViewGroup { mDualLabel = new QSDualTileLabel(mContext); mDualLabel.setId(android.R.id.title); mDualLabel.setBackgroundResource(R.drawable.btn_borderless_rect); + mDualLabel.setFirstLineCaret(res.getDrawable(R.drawable.qs_dual_tile_caret)); mDualLabel.setTextColor(res.getColor(R.color.qs_tile_text)); mDualLabel.setPadding(0, mDualTileVerticalPaddingPx, 0, mDualTileVerticalPaddingPx); mDualLabel.setTypeface(CONDENSED); diff --git a/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java b/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java index ad79aba..a1092a3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java +++ b/packages/SystemUI/src/com/android/systemui/qs/UsageTracker.java @@ -22,7 +22,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; -import com.android.systemui.R; import com.android.systemui.statusbar.policy.Listenable; public class UsageTracker implements Listenable { @@ -35,11 +34,10 @@ public class UsageTracker implements Listenable { private boolean mRegistered; - public UsageTracker(Context context, Class<?> tile) { + public UsageTracker(Context context, Class<?> tile, int timeoutResource) { mContext = context; mPrefKey = tile.getSimpleName() + "LastUsed"; - mTimeToShowTile = MILLIS_PER_DAY * mContext.getResources() - .getInteger(R.integer.days_to_show_timeout_tiles); + mTimeToShowTile = MILLIS_PER_DAY * mContext.getResources().getInteger(timeoutResource); mResetAction = "com.android.systemui.qs." + tile.getSimpleName() + ".usage_reset"; } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java index e99b4c5..84bfb8f 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java @@ -77,7 +77,7 @@ public class BluetoothTile extends QSTile<QSTile.BooleanState> { @Override protected void handleSecondaryClick() { - mHost.startSettingsActivity(BLUETOOTH_SETTINGS); + showDetail(true); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java index 01849c1..7ba1dc0 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java @@ -44,7 +44,8 @@ public class ColorInversionTile extends QSTile<QSTile.BooleanState> { } } }; - mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class); + mUsageTracker = new UsageTracker(host.getContext(), ColorInversionTile.class, + R.integer.days_to_show_color_inversion_tile); if (mSetting.getValue() != 0 && !mUsageTracker.isRecentlyUsed()) { mUsageTracker.trackUsage(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java index ce99cc3..b30a1d3 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java @@ -34,7 +34,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { public HotspotTile(Host host) { super(host); mController = host.getHotspotController(); - mUsageTracker = new UsageTracker(host.getContext(), HotspotTile.class); + mUsageTracker = newUsageTracker(host.getContext()); mUsageTracker.setListening(true); } @@ -84,6 +84,10 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { } } + private static UsageTracker newUsageTracker(Context context) { + return new UsageTracker(context, HotspotTile.class, R.integer.days_to_show_hotspot_tile); + } + private final class Callback implements HotspotController.Callback { @Override public void onHotspotChanged(boolean enabled) { @@ -101,7 +105,7 @@ public class HotspotTile extends QSTile<QSTile.BooleanState> { @Override public void onReceive(Context context, Intent intent) { if (mUsageTracker == null) { - mUsageTracker = new UsageTracker(context, HotspotTile.class); + mUsageTracker = newUsageTracker(context); } mUsageTracker.trackUsage(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java index 0985812..20c4ee8 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java @@ -87,7 +87,15 @@ public class WifiTile extends QSTile<QSTile.SignalState> { @Override protected void handleSecondaryClick() { - mHost.startSettingsActivity(WIFI_SETTINGS); + if (!mController.canConfigWifi()) { + mHost.startSettingsActivity(new Intent(Settings.ACTION_WIFI_SETTINGS)); + return; + } + if (!mState.enabled) { + mController.setWifiEnabled(true); + mState.enabled = true; + } + showDetail(true); } @Override @@ -279,7 +287,9 @@ public class WifiTile extends QSTile<QSTile.SignalState> { if (item == null || item.tag == null) return; final AccessPoint ap = (AccessPoint) item.tag; if (!ap.isConnected) { - mController.connect(ap); + if (mController.connect(ap)) { + mHost.collapsePanels(); + } } showDetail(false); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java index 1283dcd..76e8181 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java +++ b/packages/SystemUI/src/com/android/systemui/recents/AlternateRecentsComponent.java @@ -54,17 +54,15 @@ import java.util.List; import java.util.concurrent.atomic.AtomicBoolean; /** A proxy implementation for the recents component */ -public class AlternateRecentsComponent implements ActivityOptions.OnAnimationStartedListener { +public class AlternateRecentsComponent { final public static String EXTRA_FROM_HOME = "recents.triggeredOverHome"; final public static String EXTRA_FROM_SEARCH_HOME = "recents.triggeredOverSearchHome"; final public static String EXTRA_FROM_APP_THUMBNAIL = "recents.animatingWithThumbnail"; - final public static String EXTRA_FROM_APP_FULL_SCREENSHOT = "recents.thumbnail"; final public static String EXTRA_FROM_TASK_ID = "recents.activeTaskId"; final public static String EXTRA_TRIGGERED_FROM_ALT_TAB = "recents.triggeredFromAltTab"; final public static String EXTRA_TRIGGERED_FROM_HOME_KEY = "recents.triggeredFromHomeKey"; - final public static String ACTION_START_ENTER_ANIMATION = "action_start_enter_animation"; final public static String ACTION_TOGGLE_RECENTS_ACTIVITY = "action_toggle_recents_activity"; final public static String ACTION_HIDE_RECENTS_ACTIVITY = "action_hide_recents_activity"; @@ -74,15 +72,12 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta final static String sRecentsPackage = "com.android.systemui"; final static String sRecentsActivity = "com.android.systemui.recents.RecentsActivity"; - static Bitmap sLastScreenshot; static RecentsComponent.Callbacks sRecentsComponentCallbacks; Context mContext; LayoutInflater mInflater; SystemServicesProxy mSystemServicesProxy; - Handler mHandler; boolean mBootCompleted; - boolean mStartAnimationTriggered; // Task launching RecentsConfiguration mConfig; @@ -108,7 +103,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta mInflater = LayoutInflater.from(context); mContext = context; mSystemServicesProxy = new SystemServicesProxy(context); - mHandler = new Handler(); mTaskStackBounds = new Rect(); } @@ -132,6 +126,9 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } } + + // When we start, preload the metadata associated with the previous tasks + RecentsTaskLoader.getInstance().preload(mContext); } public void onBootCompleted() { @@ -256,7 +253,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta public void onConfigurationChanged(Configuration newConfig) { // Reload the header bar layout reloadHeaderBarLayout(); - sLastScreenshot = null; } /** Prepares the header bar layout. */ @@ -330,7 +326,8 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta // If the user has toggled it too quickly, then just eat up the event here (it's better than // showing a janky screenshot). // NOTE: Ideally, the screenshot mechanism would take the window transform into account - if (System.currentTimeMillis() - mLastToggleTime < sMinToggleDelay) { + long currentTime = System.currentTimeMillis(); + if ((currentTime > mLastToggleTime) && (currentTime - mLastToggleTime) < sMinToggleDelay) { return; } @@ -367,47 +364,30 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta * Creates the activity options for a unknown state->recents transition. */ ActivityOptions getUnknownTransitionActivityOptions() { - mStartAnimationTriggered = false; return ActivityOptions.makeCustomAnimation(mContext, R.anim.recents_from_unknown_enter, - R.anim.recents_from_unknown_exit, mHandler, this); + R.anim.recents_from_unknown_exit); } /** * Creates the activity options for a home->recents transition. */ ActivityOptions getHomeTransitionActivityOptions(boolean fromSearchHome) { - mStartAnimationTriggered = false; if (fromSearchHome) { return ActivityOptions.makeCustomAnimation(mContext, R.anim.recents_from_search_launcher_enter, - R.anim.recents_from_search_launcher_exit, mHandler, this); + R.anim.recents_from_search_launcher_exit); } return ActivityOptions.makeCustomAnimation(mContext, R.anim.recents_from_launcher_enter, - R.anim.recents_from_launcher_exit, mHandler, this); + R.anim.recents_from_launcher_exit); } /** - * Creates the activity options for an app->recents transition. If this method sets the static - * screenshot, then we will use that for the transition. + * Creates the activity options for an app->recents transition. */ ActivityOptions getThumbnailTransitionActivityOptions(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) { - if (Constants.DebugFlags.App.EnableScreenshotAppTransition) { - // Recycle the last screenshot - consumeLastScreenshot(); - - // Take the full screenshot - sLastScreenshot = mSystemServicesProxy.takeAppScreenshot(); - if (sLastScreenshot != null) { - mStartAnimationTriggered = false; - return ActivityOptions.makeCustomAnimation(mContext, - R.anim.recents_from_app_enter, - R.anim.recents_from_app_exit, mHandler, this); - } - } - // Update the destination rect Task toTask = new Task(); TaskViewTransform toTransform = getThumbnailTransitionTransform(topTask.id, isTopTaskHome, @@ -428,10 +408,9 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta c.setBitmap(null); } - mStartAnimationTriggered = false; return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mStatusBarView, thumbnail, toTaskRect.left, toTaskRect.top, toTaskRect.width(), - toTaskRect.height(), this); + toTaskRect.height(), null); } // If both the screenshot and thumbnail fails, then just fall back to the default transition @@ -493,11 +472,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta // Try starting with a thumbnail transition ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, isTopTaskHome); if (opts != null) { - if (sLastScreenshot != null) { - startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_FULL_SCREENSHOT); - } else { - startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL); - } + startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_APP_THUMBNAIL); } else { // Fall through below to the non-thumbnail transition useThumbnailTransition = false; @@ -535,7 +510,7 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } else { // Otherwise we do the normal fade from an unknown source ActivityOptions opts = getUnknownTransitionActivityOptions(); - startAlternateRecentsActivity(topTask, opts, null); + startAlternateRecentsActivity(topTask, opts, EXTRA_FROM_HOME); } } mLastToggleTime = System.currentTimeMillis(); @@ -561,19 +536,6 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta } } - /** Returns the last screenshot taken, this will be called by the RecentsActivity. */ - public static Bitmap getLastScreenshot() { - return sLastScreenshot; - } - - /** Recycles the last screenshot taken, this will be called by the RecentsActivity. */ - public static void consumeLastScreenshot() { - if (sLastScreenshot != null) { - sLastScreenshot.recycle(); - sLastScreenshot = null; - } - } - /** Sets the RecentsComponent callbacks. */ public void setRecentsComponentCallback(RecentsComponent.Callbacks cb) { sRecentsComponentCallbacks = cb; @@ -585,42 +547,4 @@ public class AlternateRecentsComponent implements ActivityOptions.OnAnimationSta sRecentsComponentCallbacks.onVisibilityChanged(visible); } } - - /**** OnAnimationStartedListener Implementation ****/ - - @Override - public void onAnimationStarted() { - // Notify recents to start the enter animation - if (!mStartAnimationTriggered) { - // There can be a race condition between the start animation callback and - // the start of the new activity (where we register the receiver that listens - // to this broadcast, so we add our own receiver and if that gets called, then - // we know the activity has not yet started and we can retry sending the broadcast. - BroadcastReceiver fallbackReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (getResultCode() == Activity.RESULT_OK) { - mStartAnimationTriggered = true; - return; - } - - // Schedule for the broadcast to be sent again after some time - mHandler.postDelayed(new Runnable() { - @Override - public void run() { - onAnimationStarted(); - } - }, 75); - } - }; - - // Send the broadcast to notify Recents that the animation has started - Intent intent = new Intent(ACTION_START_ENTER_ANIMATION); - intent.setPackage(mContext.getPackageName()); - intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT | - Intent.FLAG_RECEIVER_FOREGROUND); - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.CURRENT, null, - fallbackReceiver, null, Activity.RESULT_CANCELED, null, null); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java index 85cf077..9b84d2e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java @@ -25,8 +25,6 @@ public class Constants { public static final boolean Verbose = false; public static class App { - // Enables the screenshot app->Recents transition - public static final boolean EnableScreenshotAppTransition = false; // Enables debug drawing for the transition thumbnail public static final boolean EnableTransitionThumbnailDebugMode = false; // Enables the filtering of tasks according to their grouping diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 01ba5a2..d2c55f7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -28,6 +28,8 @@ import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; import android.os.UserHandle; import android.util.Pair; import android.view.KeyEvent; @@ -102,8 +104,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void run() { // Mark Recents as no longer visible - AlternateRecentsComponent.notifyVisibilityChanged(false); - mVisible = false; + onRecentsActivityVisibilityChanged(false); // Finish Recents if (mLaunchIntent != null) { if (mLaunchOpts != null) { @@ -141,14 +142,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } else if (action.equals(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY)) { // If we are toggling Recents, then first unfilter any filtered stacks first dismissRecentsToFocusedTaskOrHome(true); - } else if (action.equals(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION)) { - // Try and start the enter animation (or restart it on configuration changed) - ReferenceCountedTrigger t = new ReferenceCountedTrigger(context, null, null, null); - mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t)); - onEnterAnimationTriggered(); - // Notify the fallback receiver that we have successfully got the broadcast - // See AlternateRecentsComponent.onAnimationStarted() - setResultCode(Activity.RESULT_OK); } } }; @@ -163,6 +156,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView if (action.equals(Intent.ACTION_SCREEN_OFF)) { // When the screen turns off, dismiss Recents to Home dismissRecentsToHome(false); + // Start preloading some tasks in the background + RecentsTaskLoader.getInstance().preload(RecentsActivity.this); } else if (action.equals(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED)) { // When the search activity changes, update the Search widget refreshSearchWidget(); @@ -189,8 +184,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView AlternateRecentsComponent.EXTRA_FROM_HOME, false); mConfig.launchedFromAppWithThumbnail = launchIntent.getBooleanExtra( AlternateRecentsComponent.EXTRA_FROM_APP_THUMBNAIL, false); - mConfig.launchedFromAppWithScreenshot = launchIntent.getBooleanExtra( - AlternateRecentsComponent.EXTRA_FROM_APP_FULL_SCREENSHOT, false); mConfig.launchedToTaskId = launchIntent.getIntExtra( AlternateRecentsComponent.EXTRA_FROM_TASK_ID, -1); mConfig.launchedWithAltTab = launchIntent.getBooleanExtra( @@ -435,6 +428,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } + /** Called when the configuration changes. */ void onConfigurationChange() { // Update RecentsConfiguration mConfig = RecentsConfiguration.reinitialize(this, @@ -443,7 +437,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView // Try and start the enter animation (or restart it on configuration changed) ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null); mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t)); - onEnterAnimationTriggered(); + // Animate the SystemUI scrim views + mScrimViews.startEnterRecentsAnimation(); + } + + /** Handles changes to the activity visibility. */ + void onRecentsActivityVisibilityChanged(boolean visible) { + if (!visible) { + AlternateRecentsComponent.notifyVisibilityChanged(visible); + } + mVisible = visible; } @Override @@ -471,7 +474,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView IntentFilter filter = new IntentFilter(); filter.addAction(AlternateRecentsComponent.ACTION_HIDE_RECENTS_ACTIVITY); filter.addAction(AlternateRecentsComponent.ACTION_TOGGLE_RECENTS_ACTIVITY); - filter.addAction(AlternateRecentsComponent.ACTION_START_ENTER_ANIMATION); registerReceiver(mServiceBroadcastReceiver, filter); // Register any broadcast receivers for the task loader @@ -483,7 +485,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView super.onResume(); // Mark Recents as visible - mVisible = true; + onRecentsActivityVisibilityChanged(true); } @Override @@ -514,6 +516,16 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } @Override + public void onEnterAnimationComplete() { + // Try and start the enter animation (or restart it on configuration changed) + ReferenceCountedTrigger t = new ReferenceCountedTrigger(this, null, null, null); + mRecentsView.startEnterRecentsAnimation(new ViewAnimation.TaskViewEnterContext(t)); + + // Animate the SystemUI scrim views + mScrimViews.startEnterRecentsAnimation(); + } + + @Override public void onTrimMemory(int level) { RecentsTaskLoader loader = RecentsTaskLoader.getInstance(); if (loader != null) { @@ -594,12 +606,6 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView } } - /** Called when the enter recents animation is triggered. */ - public void onEnterAnimationTriggered() { - // Animate the SystemUI scrim views - mScrimViews.startEnterRecentsAnimation(); - } - /**** RecentsView.RecentsViewCallbacks Implementation ****/ @Override @@ -611,8 +617,7 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView @Override public void onTaskViewClicked() { // Mark recents as no longer visible - AlternateRecentsComponent.notifyVisibilityChanged(false); - mVisible = false; + onRecentsActivityVisibilityChanged(false); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index 2aca576..bfea3f7 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -307,7 +307,6 @@ public class RecentsConfiguration { launchedWithAltTab = false; launchedWithNoRecentTasks = false; launchedFromAppWithThumbnail = false; - launchedFromAppWithScreenshot = false; launchedFromHome = false; launchedToTaskId = -1; } 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 f01d17c..a0dee07 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -16,6 +16,7 @@ package com.android.systemui.recents.misc; +import android.animation.Animator; import android.content.Intent; import android.graphics.Color; import android.graphics.Matrix; @@ -188,4 +189,15 @@ public class Utilities { int flags = intent.getFlags(); return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT; } + + /** + * Cancels an animation ensuring that if it has listeners, onCancel and onEnd + * are not called. + */ + public static void cancelAnimationWithoutCallbacks(Animator animator) { + if (animator != null) { + animator.removeAllListeners(); + animator.cancel(); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java index 7ccefc6..97e0916 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/KeyStoreLruCache.java @@ -21,15 +21,16 @@ import android.util.LruCache; import java.util.HashMap; /** - * An LRU cache that support querying the keys as well as values. By using the Task's key, we can - * prevent holding onto a reference to the Task resource data, while keeping the cache data in - * memory where necessary. + * An LRU cache that internally support querying the keys as well as values. We use this to keep + * track of the task metadata to determine when to invalidate the cache when tasks have been + * updated. Generally, this cache will return the last known cache value for the requested task + * key. */ public class KeyStoreLruCache<V> { // We keep a set of keys that are associated with the LRU cache, so that we can find out // information about the Task that was previously in the cache. HashMap<Integer, Task.TaskKey> mTaskKeys = new HashMap<Integer, Task.TaskKey>(); - // The cache implementation + // The cache implementation, mapping task id -> value LruCache<Integer, V> mCache; public KeyStoreLruCache(int cacheSize) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java index 60e89bf..e48e5f0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsPackageMonitor.java @@ -19,6 +19,7 @@ package com.android.systemui.recents.model; import android.content.ComponentName; import android.content.Context; import android.os.Looper; +import android.os.UserHandle; import com.android.internal.content.PackageMonitor; import com.android.systemui.recents.misc.SystemServicesProxy; @@ -26,16 +27,16 @@ import java.util.HashSet; import java.util.List; /** - * The package monitor listens for changes from PackageManager to update the contents of the Recents - * list. + * The package monitor listens for changes from PackageManager to update the contents of the + * Recents list. */ public class RecentsPackageMonitor extends PackageMonitor { public interface PackageCallbacks { - public void onComponentRemoved(HashSet<ComponentName> cns); + public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, + int userId); } PackageCallbacks mCb; - List<Task.TaskKey> mTasks; SystemServicesProxy mSystemServicesProxy; /** Registers the broadcast receivers with the specified callbacks. */ @@ -43,7 +44,9 @@ public class RecentsPackageMonitor extends PackageMonitor { mSystemServicesProxy = new SystemServicesProxy(context); mCb = cb; try { - register(context, Looper.getMainLooper(), true); + // We register for events from all users, but will cross-reference them with + // packages for the current user and any profiles they have + register(context, Looper.getMainLooper(), UserHandle.ALL, true); } catch (IllegalStateException e) { e.printStackTrace(); } @@ -59,29 +62,15 @@ public class RecentsPackageMonitor extends PackageMonitor { } mSystemServicesProxy = null; mCb = null; - mTasks.clear(); - } - - /** Sets the list of tasks to match against package broadcast changes. */ - void setTasks(List<Task.TaskKey> tasks) { - mTasks = tasks; } @Override public void onPackageRemoved(String packageName, int uid) { if (mCb == null) return; - // Identify all the tasks that should be removed as a result of the package being removed. - // Using a set to ensure that we callback once per unique component. - HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>(); - for (Task.TaskKey t : mTasks) { - ComponentName cn = t.baseIntent.getComponent(); - if (cn.getPackageName().equals(packageName)) { - componentsToRemove.add(cn); - } - } - // Notify our callbacks that the components no longer exist - mCb.onComponentRemoved(componentsToRemove); + // Notify callbacks that a package has changed + final int eventUserId = getChangingUserId(); + mCb.onPackagesChanged(this, packageName, eventUserId); } @Override @@ -94,25 +83,38 @@ public class RecentsPackageMonitor extends PackageMonitor { public void onPackageModified(String packageName) { if (mCb == null) return; + // Notify callbacks that a package has changed + final int eventUserId = getChangingUserId(); + mCb.onPackagesChanged(this, packageName, eventUserId); + } + + /** + * Computes the components that have been removed as a result of a change in the specified + * package. + */ + public HashSet<ComponentName> computeComponentsRemoved(List<Task.TaskKey> taskKeys, + String packageName, int userId) { // Identify all the tasks that should be removed as a result of the package being removed. // Using a set to ensure that we callback once per unique component. - HashSet<ComponentName> componentsKnownToExist = new HashSet<ComponentName>(); - HashSet<ComponentName> componentsToRemove = new HashSet<ComponentName>(); - for (Task.TaskKey t : mTasks) { + HashSet<ComponentName> existingComponents = new HashSet<ComponentName>(); + HashSet<ComponentName> removedComponents = new HashSet<ComponentName>(); + for (Task.TaskKey t : taskKeys) { + // Skip if this doesn't apply to the current user + if (t.userId != userId) continue; + ComponentName cn = t.baseIntent.getComponent(); if (cn.getPackageName().equals(packageName)) { - if (componentsKnownToExist.contains(cn)) { + if (existingComponents.contains(cn)) { // If we know that the component still exists in the package, then skip continue; } - if (mSystemServicesProxy.getActivityInfo(cn) != null) { - componentsKnownToExist.add(cn); + if (mSystemServicesProxy.getActivityInfo(cn, userId) != null) { + existingComponents.add(cn); } else { - componentsToRemove.add(cn); + removedComponents.add(cn); } } } - // Notify our callbacks that the components no longer exist - mCb.onComponentRemoved(componentsToRemove); + return removedComponents; } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java index d40e847..b4f62d5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java @@ -171,6 +171,9 @@ class TaskResourceLoader implements Runnable { } } else { SystemServicesProxy ssp = mSystemServicesProxy; + // If we've stopped the loader, then fall thorugh to the above logic to wait on + // the load thread + if (ssp == null) continue; // Load the next item from the queue final Task t = mLoadQueue.nextTask(); @@ -418,17 +421,25 @@ public class RecentsTaskLoader { root.setStack(stack); // Start the task loader and add all the tasks we need to load - mLoader.start(context); mLoadQueue.addTasks(tasksToLoad); - - // Update the package monitor with the list of packages to listen for - mPackageMonitor.setTasks(taskKeys); + mLoader.start(context); return root; } + /** Preloads the set of recent tasks (not including thumbnails). */ + public void preload(Context context) { + ArrayList<Task> tasksToLoad = new ArrayList<Task>(); + getTaskStack(mSystemServicesProxy, context.getResources(), + -1, -1, true, true, null, tasksToLoad); + + // Start the task loader and add all the tasks we need to load + mLoadQueue.addTasks(tasksToLoad); + mLoader.start(context); + } + /** Creates a lightweight stack of the current recent tasks, without thumbnails and icons. */ - public TaskStack getTaskStack(SystemServicesProxy ssp, Resources res, + public synchronized TaskStack getTaskStack(SystemServicesProxy ssp, Resources res, int preloadTaskId, int preloadTaskCount, boolean loadTaskThumbnails, boolean isTopTaskHome, List<Task.TaskKey> taskKeysOut, List<Task> tasksToLoadOut) { 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 a7e2b0b..55dfe45 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java @@ -129,7 +129,7 @@ public class Task { TaskCallbacks mCb; public Task() { - // Only used by RecentsService for task rect calculations. + // Do nothing } public Task(TaskKey key, boolean isActive, int taskAffiliation, int taskAffiliationColor, 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 1e47b50..a37b9e6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -255,6 +255,17 @@ public class TaskStack { return mTaskList.getTasks().get(mTaskList.size() - 1); } + /** Gets the task keys */ + public ArrayList<Task.TaskKey> getTaskKeys() { + ArrayList<Task.TaskKey> taskKeys = new ArrayList<Task.TaskKey>(); + ArrayList<Task> tasks = mTaskList.getTasks(); + int taskCount = tasks.size(); + for (int i = 0; i < taskCount; i++) { + taskKeys.add(tasks.get(i).key); + } + return taskKeys; + } + /** Gets the tasks */ public ArrayList<Task> getTasks() { return mTaskList.getTasks(); 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 d2fdaff..5f8f3f2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimateableViewBounds.java @@ -17,12 +17,10 @@ package com.android.systemui.recents.views; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.graphics.Outline; import android.graphics.Rect; import android.view.View; import android.view.ViewOutlineProvider; - import com.android.systemui.recents.RecentsConfiguration; /* An outline provider that has a clip and outline that can be animated. */ @@ -31,35 +29,27 @@ public class AnimateableViewBounds extends ViewOutlineProvider { RecentsConfiguration mConfig; TaskView mSourceView; - Rect mTmpRect = new Rect(); Rect mClipRect = new Rect(); Rect mClipBounds = new Rect(); - Rect mOutlineClipRect = new Rect(); int mCornerRadius; float mAlpha = 1f; final float mMinAlpha = 0.25f; - ObjectAnimator mClipTopAnimator; - ObjectAnimator mClipRightAnimator; ObjectAnimator mClipBottomAnimator; public AnimateableViewBounds(TaskView source, int cornerRadius) { mConfig = RecentsConfiguration.getInstance(); mSourceView = source; mCornerRadius = cornerRadius; - setClipTop(getClipTop()); - setClipRight(getClipRight()); setClipBottom(getClipBottom()); - setOutlineClipBottom(getOutlineClipBottom()); } @Override public void getOutline(View view, Outline outline) { outline.setAlpha(mMinAlpha + mAlpha / (1f - mMinAlpha)); - outline.setRoundRect(Math.max(mClipRect.left, mOutlineClipRect.left), - Math.max(mClipRect.top, mOutlineClipRect.top), - mSourceView.getWidth() - Math.max(mClipRect.right, mOutlineClipRect.right), - mSourceView.getHeight() - Math.max(mClipRect.bottom, mOutlineClipRect.bottom), + outline.setRoundRect(mClipRect.left, mClipRect.top, + mSourceView.getWidth() - mClipRect.right, + mSourceView.getHeight() - mClipRect.bottom, mCornerRadius); } @@ -71,73 +61,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider { } } - /** Animates the top clip. */ - void animateClipTop(int top, int duration, ValueAnimator.AnimatorUpdateListener updateListener) { - if (mClipTopAnimator != null) { - mClipTopAnimator.removeAllListeners(); - mClipTopAnimator.cancel(); - } - mClipTopAnimator = ObjectAnimator.ofInt(this, "clipTop", top); - mClipTopAnimator.setDuration(duration); - mClipTopAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - if (updateListener != null) { - mClipTopAnimator.addUpdateListener(updateListener); - } - mClipTopAnimator.start(); - } - - /** Sets the top clip. */ - public void setClipTop(int top) { - if (top != mClipRect.top) { - mClipRect.top = top; - mSourceView.invalidateOutline(); - updateClipBounds(); - } - } - - /** Returns the top clip. */ - public int getClipTop() { - return mClipRect.top; - } - - /** Animates the right clip. */ - void animateClipRight(int right, int duration) { - if (mClipRightAnimator != null) { - mClipRightAnimator.removeAllListeners(); - mClipRightAnimator.cancel(); - } - mClipRightAnimator = ObjectAnimator.ofInt(this, "clipRight", right); - mClipRightAnimator.setDuration(duration); - mClipRightAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mClipRightAnimator.start(); - } - - /** Sets the right clip. */ - public void setClipRight(int right) { - if (right != mClipRect.right) { - mClipRect.right = right; - mSourceView.invalidateOutline(); - updateClipBounds(); - } - } - - /** Returns the right clip. */ - public int getClipRight() { - return mClipRect.right; - } - - /** Animates the bottom clip. */ - void animateClipBottom(int bottom, int duration) { - if (mClipBottomAnimator != null) { - mClipBottomAnimator.removeAllListeners(); - mClipBottomAnimator.cancel(); - } - mClipBottomAnimator = ObjectAnimator.ofInt(this, "clipBottom", bottom); - mClipBottomAnimator.setDuration(duration); - mClipBottomAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mClipBottomAnimator.start(); - } - /** Sets the bottom clip. */ public void setClipBottom(int bottom) { if (bottom != mClipRect.bottom) { @@ -145,7 +68,7 @@ public class AnimateableViewBounds extends ViewOutlineProvider { mSourceView.invalidateOutline(); updateClipBounds(); if (!mConfig.useHardwareLayers) { - mSourceView.mThumbnailView.updateVisibility( + mSourceView.mThumbnailView.updateThumbnailVisibility( bottom - mSourceView.getPaddingBottom()); } } @@ -156,19 +79,6 @@ public class AnimateableViewBounds extends ViewOutlineProvider { return mClipRect.bottom; } - /** Sets the outline bottom clip. */ - public void setOutlineClipBottom(int bottom) { - if (bottom != mOutlineClipRect.bottom) { - mOutlineClipRect.bottom = bottom; - mSourceView.invalidateOutline(); - } - } - - /** Gets the outline bottom clip. */ - public int getOutlineClipBottom() { - return mOutlineClipRect.bottom; - } - private void updateClipBounds() { mClipBounds.set(mClipRect.left, mClipRect.top, mSourceView.getWidth() - mClipRect.right, 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 6c22a3b..6b0d306 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -18,8 +18,6 @@ package com.android.systemui.recents.views; import android.app.ActivityOptions; import android.app.TaskStackBuilder; -import android.content.ActivityNotFoundException; -import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.graphics.Bitmap; @@ -35,7 +33,6 @@ import android.view.WindowInsets; import android.widget.FrameLayout; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.misc.Console; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.RecentsPackageMonitor; @@ -44,7 +41,6 @@ import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; -import java.util.HashSet; /** * This view is the the top level layout that contains TaskStacks (which are laid out according @@ -339,7 +335,7 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV View child = getChildAt(i); if (child != mSearchBar) { TaskStackView stackView = (TaskStackView) child; - stackView.focusNextTask(forward); + stackView.focusNextTask(forward, true); break; } } @@ -566,14 +562,14 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ @Override - public void onComponentRemoved(HashSet<ComponentName> cns) { + public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) { // Propagate this event down to each task stack view int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child != mSearchBar) { TaskStackView stackView = (TaskStackView) child; - stackView.onComponentRemoved(cns); + stackView.onPackagesChanged(monitor, packageName, userId); } } } 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 40134da..dee26e6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -24,7 +24,6 @@ import android.graphics.Rect; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewTreeObserver; import android.view.accessibility.AccessibilityEvent; import android.widget.FrameLayout; import com.android.systemui.R; @@ -415,7 +414,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } /** Focuses the task at the specified index in the stack */ - void focusTask(int taskIndex, boolean scrollToNewPosition) { + void focusTask(int taskIndex, boolean scrollToNewPosition, final boolean animateFocusedState) { // Return early if the task is already focused if (taskIndex == mFocusedTaskIndex) return; @@ -427,7 +426,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView tv = getChildViewForTask(t); Runnable postScrollRunnable = null; if (tv != null) { - tv.setFocusedTask(); + tv.setFocusedTask(animateFocusedState); } else { postScrollRunnable = new Runnable() { @Override @@ -435,7 +434,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Task t = mStack.getTasks().get(mFocusedTaskIndex); TaskView tv = getChildViewForTask(t); if (tv != null) { - tv.setFocusedTask(); + tv.setFocusedTask(animateFocusedState); } } }; @@ -455,18 +454,50 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } - /** Focuses the next task in the stack */ - void focusNextTask(boolean forward) { + /** + * Ensures that there is a task focused, if nothign is focused, then we will use the task + * at the center of the visible stack. + */ + public boolean ensureFocusedTask() { + if (mFocusedTaskIndex < 0) { + // If there is no task focused, then find the task that is closes to the center + // of the screen and use that as the currently focused task + int x = mLayoutAlgorithm.mStackVisibleRect.centerX(); + int y = mLayoutAlgorithm.mStackVisibleRect.centerY(); + int childCount = getChildCount(); + for (int i = childCount - 1; i >= 0; i--) { + TaskView tv = (TaskView) getChildAt(i); + tv.getHitRect(mTmpRect); + if (mTmpRect.contains(x, y)) { + mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); + break; + } + } + // If we can't find the center task, then use the front most index + if (mFocusedTaskIndex < 0 && childCount > 0) { + mFocusedTaskIndex = childCount - 1; + } + } + return mFocusedTaskIndex >= 0; + } + + /** + * Focuses the next task in the stack. + * @param animateFocusedState determines whether to actually draw the highlight along with + * the change in focus, as well as whether to scroll to fit the + * task into view. + */ + public void focusNextTask(boolean forward, boolean animateFocusedState) { // Find the next index to focus int numTasks = mStack.getTaskCount(); if (numTasks == 0) return; - int nextFocusIndex = numTasks - 1; - if (0 <= mFocusedTaskIndex && mFocusedTaskIndex < numTasks) { - nextFocusIndex = Math.max(0, Math.min(numTasks - 1, - mFocusedTaskIndex + (forward ? -1 : 1))); + int direction = (forward ? -1 : 1); + int newIndex = mFocusedTaskIndex + direction; + if (newIndex >= 0 && newIndex <= (numTasks - 1)) { + newIndex = Math.max(0, Math.min(numTasks - 1, newIndex)); + focusTask(newIndex, true, animateFocusedState); } - focusTask(nextFocusIndex, true); } /** Dismisses the focused task. */ @@ -506,6 +537,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } @Override + public boolean onGenericMotionEvent(MotionEvent ev) { + return mTouchHandler.onGenericMotionEvent(ev); + } + + @Override public void computeScroll() { mStackScroller.computeScroll(); // Synchronize the views @@ -562,22 +598,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); - if (tv.isFullScreenView()) { - tv.measure(widthMeasureSpec, heightMeasureSpec); + if (tv.getBackground() != null) { + tv.getBackground().getPadding(mTmpRect); } else { - if (tv.getBackground() != null) { - tv.getBackground().getPadding(mTmpRect); - } else { - mTmpRect.setEmpty(); - } - tv.measure( - MeasureSpec.makeMeasureSpec( - mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right, - MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec( - mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom + - tv.getMaxFooterHeight(), MeasureSpec.EXACTLY)); + mTmpRect.setEmpty(); } + tv.measure( + MeasureSpec.makeMeasureSpec( + mLayoutAlgorithm.mTaskRect.width() + mTmpRect.left + mTmpRect.right, + MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec( + mLayoutAlgorithm.mTaskRect.height() + mTmpRect.top + mTmpRect.bottom, + MeasureSpec.EXACTLY)); } setMeasuredDimension(width, height); @@ -594,20 +626,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { TaskView tv = (TaskView) getChildAt(i); - if (tv.isFullScreenView()) { - tv.layout(left, top, left + tv.getMeasuredWidth(), top + tv.getMeasuredHeight()); + if (tv.getBackground() != null) { + tv.getBackground().getPadding(mTmpRect); } else { - if (tv.getBackground() != null) { - tv.getBackground().getPadding(mTmpRect); - } else { - mTmpRect.setEmpty(); - } - tv.layout(mLayoutAlgorithm.mTaskRect.left - mTmpRect.left, - mLayoutAlgorithm.mTaskRect.top - mTmpRect.top, - mLayoutAlgorithm.mTaskRect.right + mTmpRect.right, - mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom + - tv.getMaxFooterHeight()); + mTmpRect.setEmpty(); } + tv.layout(mLayoutAlgorithm.mTaskRect.left - mTmpRect.left, + mLayoutAlgorithm.mTaskRect.top - mTmpRect.top, + mLayoutAlgorithm.mTaskRect.right + mTmpRect.right, + mLayoutAlgorithm.mTaskRect.bottom + mTmpRect.bottom); } if (mAwaitingFirstLayout) { @@ -653,9 +680,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // When Alt-Tabbing, we scroll to and focus the previous task if (mConfig.launchedWithAltTab) { if (mConfig.launchedFromHome) { - focusTask(Math.max(0, mStack.getTaskCount() - 1), false); + focusTask(Math.max(0, mStack.getTaskCount() - 1), false, true); } else { - focusTask(Math.max(0, mStack.getTaskCount() - 2), false); + focusTask(Math.max(0, mStack.getTaskCount() - 2), false, true); } } } @@ -811,6 +838,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal TaskView frontTv = getChildViewForTask(newFrontMostTask); if (frontTv != null) { frontTv.onTaskBound(newFrontMostTask); + frontTv.fadeInActionButton(false); } } @@ -923,13 +951,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Rebind the task and request that this task's data be filled into the TaskView tv.onTaskBound(task); - // Mark the launch task as fullscreen - if (Constants.DebugFlags.App.EnableScreenshotAppTransition && mAwaitingFirstLayout) { - if (task.isLaunchTarget) { - tv.setIsFullScreen(true); - } - } - // Load the task data RecentsTaskLoader.getInstance().loadTaskData(task); @@ -1018,14 +1039,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal tv.getTask().activityLabel)); // Remove the task from the view mStack.removeTask(task); - // If the dismissed task was focused, then we should focus the next task in front + // If the dismissed task was focused, then we should focus the new task in the same index if (taskWasFocused) { ArrayList<Task> tasks = mStack.getTasks(); - int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex); + int nextTaskIndex = Math.min(tasks.size() - 1, taskIndex - 1); if (nextTaskIndex >= 0) { Task nextTask = tasks.get(nextTaskIndex); TaskView nextTv = getChildViewForTask(nextTask); - nextTv.setFocusedTask(); + if (nextTv != null) { + // Focus the next task, and only animate the visible state if we are launched + // from Alt-Tab + nextTv.setFocusedTask(mConfig.launchedWithAltTab); + } } } } @@ -1038,11 +1063,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } @Override - public void onTaskViewFullScreenTransitionCompleted() { - requestSynchronizeStackViewsWithModel(); - } - - @Override public void onTaskViewFocusChanged(TaskView tv, boolean focused) { if (focused) { mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); @@ -1061,12 +1081,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /**** RecentsPackageMonitor.PackageCallbacks Implementation ****/ @Override - public void onComponentRemoved(HashSet<ComponentName> cns) { + public void onPackagesChanged(RecentsPackageMonitor monitor, String packageName, int userId) { + // Compute which components need to be removed + HashSet<ComponentName> removedComponents = monitor.computeComponentsRemoved( + mStack.getTaskKeys(), packageName, userId); + // For other tasks, just remove them directly if they no longer exist ArrayList<Task> tasks = mStack.getTasks(); for (int i = tasks.size() - 1; i >= 0; i--) { final Task t = tasks.get(i); - if (cns.contains(t.key.baseIntent.getComponent())) { + if (removedComponents.contains(t.key.baseIntent.getComponent())) { TaskView tv = getChildViewForTask(t); if (tv != null) { // For visible children, defer removing the task until after the animation diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java index 31fc701..c549d2b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java @@ -199,18 +199,14 @@ public class TaskStackViewLayoutAlgorithm { return transformOut; } - /** - * Returns the untransformed task view size. - */ + /** Returns the untransformed task view size. */ public Rect getUntransformedTaskViewSize() { Rect tvSize = new Rect(mTaskRect); tvSize.offsetTo(0, 0); return tvSize; } - /** - * Returns the scroll to such task top = 1f; - */ + /** Returns the scroll to such task top = 1f; */ float getStackScrollForTask(Task t) { return mTaskProgressMap.get(t.key); } 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 5852b88..04f7c6f 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java @@ -23,6 +23,7 @@ import android.animation.ValueAnimator; import android.content.Context; import android.widget.OverScroller; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.misc.Utilities; /* The scrolling logic for a TaskStackView */ public class TaskStackViewScroller { @@ -38,6 +39,7 @@ public class TaskStackViewScroller { OverScroller mScroller; ObjectAnimator mScrollAnimator; + float mFinalAnimatedScroll; public TaskStackViewScroller(Context context, RecentsConfiguration config, TaskStackViewLayoutAlgorithm layoutAlgorithm) { mConfig = config; @@ -128,10 +130,15 @@ public class TaskStackViewScroller { /** Animates the stack scroll */ void animateScroll(float curScroll, float newScroll, final Runnable postRunnable) { - // Abort any current animations + // Finish any current scrolling animations + if (mScrollAnimator != null && mScrollAnimator.isRunning()) { + setStackScroll(mFinalAnimatedScroll); + mScroller.startScroll(0, progressToScrollRange(mFinalAnimatedScroll), 0, 0, 0); + } stopScroller(); stopBoundScrollAnimation(); + mFinalAnimatedScroll = newScroll; mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll); mScrollAnimator.setDuration(mConfig.taskStackScrollDuration); mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator); @@ -155,10 +162,7 @@ public class TaskStackViewScroller { /** Aborts any current stack scrolls */ void stopBoundScrollAnimation() { - if (mScrollAnimator != null) { - mScrollAnimator.removeAllListeners(); - mScrollAnimator.cancel(); - } + Utilities.cancelAnimationWithoutCallbacks(mScrollAnimator); } /**** OverScroller ****/ 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 8f9b4c2..2b173a9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -17,6 +17,7 @@ package com.android.systemui.recents.views; import android.content.Context; +import android.view.InputDevice; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; @@ -189,7 +190,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { /** Handles touch events once we have intercepted them */ public boolean onTouchEvent(MotionEvent ev) { - // Short circuit if we have no children boolean hasChildren = (mSv.getChildCount() > 0); if (!hasChildren) { @@ -336,6 +336,30 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { return true; } + /** Handles generic motion events */ + public boolean onGenericMotionEvent(MotionEvent ev) { + if ((ev.getSource() & InputDevice.SOURCE_CLASS_POINTER) == + InputDevice.SOURCE_CLASS_POINTER) { + int action = ev.getAction(); + switch (action & MotionEvent.ACTION_MASK) { + case MotionEvent.ACTION_SCROLL: + // Find the front most task and scroll the next task to the front + float vScroll = ev.getAxisValue(MotionEvent.AXIS_VSCROLL); + if (vScroll > 0) { + if (mSv.ensureFocusedTask()) { + mSv.focusNextTask(true, false); + } + } else { + if (mSv.ensureFocusedTask()) { + mSv.focusNextTask(false, false); + } + } + return true; + } + } + return false; + } + /**** SwipeHelper Implementation ****/ @Override @@ -355,8 +379,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { tv.setClipViewInStack(false); // Disallow touch events from this task view tv.setTouchEnabled(false); - // Hide the footer - tv.animateFooterVisibility(false, mSv.mConfig.taskViewLockToAppShortAnimDuration); // Disallow parents from intercepting touch events final ViewParent parent = mSv.getParent(); if (parent != null) { @@ -387,8 +409,6 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { tv.setClipViewInStack(true); // Re-enable touch events from this task view tv.setTouchEnabled(true); - // Restore the footer - tv.animateFooterVisibility(true, mSv.mConfig.taskViewLockToAppShortAnimDuration); } @Override 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 2658176..7b4e10a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -21,23 +21,22 @@ import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.graphics.*; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.LayerDrawable; import android.util.AttributeSet; import android.view.View; import android.view.ViewOutlineProvider; +import android.view.ViewPropertyAnimator; import android.view.animation.AccelerateInterpolator; import android.widget.FrameLayout; import com.android.systemui.R; -import com.android.systemui.recents.AlternateRecentsComponent; import com.android.systemui.recents.Constants; import com.android.systemui.recents.RecentsConfiguration; -import com.android.systemui.recents.model.RecentsTaskLoader; +import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; +import com.android.systemui.statusbar.phone.PhoneStatusBar; /* A task view */ public class TaskView extends FrameLayout implements Task.TaskCallbacks, - TaskViewFooter.TaskFooterViewCallbacks, View.OnClickListener, View.OnLongClickListener { + View.OnClickListener, View.OnLongClickListener { /** The TaskView callbacks */ interface TaskViewCallbacks { @@ -46,7 +45,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, public void onTaskViewClicked(TaskView tv, Task task, boolean lockToTask); public void onTaskViewDismissed(TaskView tv); public void onTaskViewClipStateChanged(TaskView tv); - public void onTaskViewFullScreenTransitionCompleted(); public void onTaskViewFocusChanged(TaskView tv, boolean focused); } @@ -54,25 +52,22 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, float mTaskProgress; ObjectAnimator mTaskProgressAnimator; - ObjectAnimator mDimAnimator; float mMaxDimScale; - int mDim; + int mDimAlpha; AccelerateInterpolator mDimInterpolator = new AccelerateInterpolator(1f); - PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.MULTIPLY); + PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); + Paint mDimLayerPaint = new Paint(); Task mTask; boolean mTaskDataLoaded; boolean mIsFocused; boolean mFocusAnimationsEnabled; - boolean mIsFullScreenView; boolean mClipViewInStack; AnimateableViewBounds mViewBounds; - Paint mLayerPaint = new Paint(); View mContent; TaskViewThumbnail mThumbnailView; TaskViewHeader mHeaderView; - TaskViewFooter mFooterView; View mActionButtonView; TaskViewCallbacks mCb; @@ -133,7 +128,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mContent = findViewById(R.id.task_view_content); mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar); mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail); - mThumbnailView.enableTaskBarClip(mHeaderView); + mThumbnailView.updateClipToTaskBar(mHeaderView); mActionButtonView = findViewById(R.id.lock_to_app_fab); mActionButtonView.setOutlineProvider(new ViewOutlineProvider() { @Override @@ -142,9 +137,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight()); } }); - if (mFooterView != null) { - mFooterView.setCallbacks(this); - } } @Override @@ -159,29 +151,16 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY)); - // Measure the bar view, thumbnail, and footer + // Measure the bar view, and action button mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY)); - if (mFooterView != null) { - mFooterView.measure( - MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(mConfig.taskViewLockToAppButtonHeight, - MeasureSpec.EXACTLY)); - } mActionButtonView.measure( MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST)); - if (mIsFullScreenView) { - // Measure the thumbnail height to be the full dimensions - mThumbnailView.measure( - MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY)); - } else { - // Measure the thumbnail to be square - mThumbnailView.measure( - MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY)); - } + // Measure the thumbnail to be square + mThumbnailView.measure( + MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY)); setMeasuredDimension(width, height); invalidateOutline(); } @@ -193,25 +172,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration, ValueAnimator.AnimatorUpdateListener updateCallback) { - // If we are a full screen view, then only update the Z to keep it in order - // XXX: Also update/animate the dim as well - if (mIsFullScreenView) { - if (!mConfig.fakeShadows && - toTransform.hasTranslationZChangedFrom(getTranslationZ())) { - setTranslationZ(toTransform.translationZ); - } - return; - } - // Apply the transform toTransform.applyToTaskView(this, duration, mConfig.fastOutSlowInInterpolator, false, !mConfig.fakeShadows, updateCallback); // Update the task progress - if (mTaskProgressAnimator != null) { - mTaskProgressAnimator.removeAllListeners(); - mTaskProgressAnimator.cancel(); - } + Utilities.cancelAnimationWithoutCallbacks(mTaskProgressAnimator); if (duration <= 0) { setTaskProgress(toTransform.p); } else { @@ -253,22 +219,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean occludesLaunchTarget, int offscreenY) { int initialDim = getDim(); - if (mConfig.launchedFromAppWithScreenshot) { + if (mConfig.launchedFromAppWithThumbnail) { if (isTaskViewLaunchTargetTask) { - // Hide the footer during the transition in, and animate it out afterwards? - if (mFooterView != null) { - mFooterView.animateFooterVisibility(false, 0); - } - } else { - // Don't do anything for the side views when animating in - } - - } else if (mConfig.launchedFromAppWithThumbnail) { - if (isTaskViewLaunchTargetTask) { - // Hide the action button if it exists - mActionButtonView.setAlpha(0f); // 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); @@ -292,74 +248,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, final TaskViewTransform transform = ctx.currentTaskTransform; int startDelay = 0; - if (mConfig.launchedFromAppWithScreenshot) { - if (mTask.isLaunchTarget) { - Rect taskRect = ctx.currentTaskRect; - int duration = mConfig.taskViewEnterFromHomeDuration * 10; - int windowInsetTop = mConfig.systemInsets.top; // XXX: Should be for the window - float taskScale = ((float) taskRect.width() / getMeasuredWidth()) * transform.scale; - float scaledYOffset = ((1f - taskScale) * getMeasuredHeight()) / 2; - float scaledWindowInsetTop = (int) (taskScale * windowInsetTop); - float scaledTranslationY = taskRect.top + transform.translationY - - (scaledWindowInsetTop + scaledYOffset); - startDelay = mConfig.taskViewEnterFromHomeStaggerDelay; - - // Animate the top clip - mViewBounds.animateClipTop(windowInsetTop, duration, - new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - int y = (Integer) animation.getAnimatedValue(); - mHeaderView.setTranslationY(y); - } - }); - // Animate the bottom or right clip - int size = Math.round((taskRect.width() / taskScale)); - if (mConfig.hasHorizontalLayout()) { - mViewBounds.animateClipRight(getMeasuredWidth() - size, duration); - } else { - mViewBounds.animateClipBottom(getMeasuredHeight() - (windowInsetTop + size), duration); - } - // Animate the task bar of the first task view - animate() - .scaleX(taskScale) - .scaleY(taskScale) - .translationY(scaledTranslationY) - .setDuration(duration) - .withEndAction(new Runnable() { - @Override - public void run() { - setIsFullScreen(false); - requestLayout(); - - // Reset the clip - mViewBounds.setClipTop(0); - mViewBounds.setClipBottom(0); - mViewBounds.setClipRight(0); - // Reset the bar translation - mHeaderView.setTranslationY(0); - // Animate the footer into view (if it is the front most task) - animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration); - - // Unbind the thumbnail from the screenshot - RecentsTaskLoader.getInstance().loadTaskData(mTask); - // Recycle the full screen screenshot - AlternateRecentsComponent.consumeLastScreenshot(); - - mCb.onTaskViewFullScreenTransitionCompleted(); - - // Decrement the post animation trigger - ctx.postAnimationTrigger.decrement(); - } - }) - .start(); - } else { - // Animate the footer into view - animateFooterVisibility(true, 0); - } - ctx.postAnimationTrigger.increment(); - - } else if (mConfig.launchedFromAppWithThumbnail) { + if (mConfig.launchedFromAppWithThumbnail) { if (mTask.isLaunchTarget) { // Animate the dim/overlay if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) { @@ -381,16 +270,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } ctx.postAnimationTrigger.increment(); - // Animate the footer into view - animateFooterVisibility(true, mConfig.taskBarEnterAnimDuration); - // Animate the action button in - mActionButtonView.animate().alpha(1f) - .setStartDelay(mConfig.taskBarEnterAnimDelay) - .setDuration(mConfig.taskBarEnterAnimDuration) - .setInterpolator(mConfig.fastOutLinearInInterpolator) - .withLayer() - .start(); + fadeInActionButton(true); } else { // Animate the task up if it was occluding the launch target if (ctx.currentTaskOccludesLaunchTarget) { @@ -442,14 +323,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, }) .start(); ctx.postAnimationTrigger.increment(); - - // Animate the footer into view - animateFooterVisibility(true, mConfig.taskViewEnterFromHomeDuration); startDelay = delay; - - } else { - // Animate the footer into view - animateFooterVisibility(true, 0); } // Enable the focus animations from this point onwards so that they aren't affected by the @@ -462,6 +336,21 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, }, (startDelay / 2)); } + public void fadeInActionButton(boolean withDelay) { + // Hide the action button + mActionButtonView.setAlpha(0f); + + // Animate the action button in + ViewPropertyAnimator animator = mActionButtonView.animate().alpha(1f) + .setDuration(mConfig.taskBarEnterAnimDuration) + .setInterpolator(PhoneStatusBar.ALPHA_IN) + .withLayer(); + if (withDelay) { + animator.setStartDelay(mConfig.taskBarEnterAnimDelay); + } + animator.start(); + } + /** Animates this task view as it leaves recents by pressing home. */ void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) { animate() @@ -483,7 +372,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mThumbnailView.startLaunchTaskAnimation(postAnimRunnable); // Animate the dim - if (mDim > 0) { + if (mDimAlpha > 0) { ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0); anim.setDuration(mConfig.taskBarExitAnimDuration); anim.setInterpolator(mConfig.fastOutLinearInInterpolator); @@ -569,23 +458,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mCb.onTaskViewDismissed(tv); } }); - // Hide the footer - animateFooterVisibility(false, mConfig.taskViewRemoveAnimDuration); - } - - /** Sets whether this task view is full screen or not. */ - void setIsFullScreen(boolean isFullscreen) { - mIsFullScreenView = isFullscreen; - mHeaderView.setIsFullscreen(isFullscreen); - if (isFullscreen) { - // If we are full screen, then disable the bottom outline clip for the footer - mViewBounds.setOutlineClipBottom(0); - } - } - - /** Returns whether this task view should currently be drawn as a full screen view. */ - boolean isFullScreenView() { - return mIsFullScreenView; } /** @@ -593,7 +465,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, * view. */ boolean shouldClipViewInStack() { - return mClipViewInStack && !mIsFullScreenView && (getVisibility() == View.VISIBLE); + return mClipViewInStack && (getVisibility() == View.VISIBLE); } /** Sets whether this view should be clipped, or clipped against. */ @@ -604,27 +476,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, } } - /** Gets the max footer height. */ - public int getMaxFooterHeight() { - if (mFooterView != null) { - return mFooterView.mMaxFooterHeight; - } else { - return 0; - } - } - - /** Animates the footer into and out of view. */ - void animateFooterVisibility(boolean visible, int duration) { - // Hide the footer if we are a full screen view - if (mIsFullScreenView) return; - // Hide the footer if the current task can not be locked to - if (!mTask.lockToTaskEnabled || !mTask.lockToThisTask) return; - // Otherwise, animate the visibility - if (mFooterView != null) { - mFooterView.animateFooterVisibility(visible, duration); - } - } - /** Sets the current task progress. */ public void setTaskProgress(float p) { mTaskProgress = p; @@ -639,26 +490,16 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Returns the current dim. */ public void setDim(int dim) { - mDim = dim; - if (mDimAnimator != null) { - mDimAnimator.removeAllListeners(); - mDimAnimator.cancel(); - } + mDimAlpha = dim; if (mConfig.useHardwareLayers) { // Defer setting hardware layers if we have not yet measured, or there is no dim to draw if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) { - if (mDimAnimator != null) { - mDimAnimator.removeAllListeners(); - mDimAnimator.cancel(); - } - - int inverse = 255 - mDim; - mDimColorFilter.setColor(Color.argb(0xFF, inverse, inverse, inverse)); - mLayerPaint.setColorFilter(mDimColorFilter); - mContent.setLayerType(LAYER_TYPE_HARDWARE, mLayerPaint); + mDimColorFilter.setColor(Color.argb(mDimAlpha, 0, 0, 0)); + mDimLayerPaint.setColorFilter(mDimColorFilter); + mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint); } } else { - float dimAlpha = mDim / 255.0f; + float dimAlpha = mDimAlpha / 255.0f; if (mThumbnailView != null) { mThumbnailView.setDimAlpha(dimAlpha); } @@ -670,7 +511,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, /** Returns the current dim. */ public int getDim() { - return mDim; + return mDimAlpha; } /** Animates the dim to the task progress. */ @@ -706,11 +547,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, * if the view is not currently visible, or we are in touch state (where we still want to keep * track of focus). */ - public void setFocusedTask() { + public void setFocusedTask(boolean animateFocusedState) { mIsFocused = true; if (mFocusAnimationsEnabled) { // Focus the header bar - mHeaderView.onTaskViewFocusChanged(true); + mHeaderView.onTaskViewFocusChanged(true, animateFocusedState); } // Update the thumbnail alpha with the focus mThumbnailView.onFocusChanged(true); @@ -732,7 +573,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mIsFocused = false; if (mFocusAnimationsEnabled) { // Un-focus the header bar - mHeaderView.onTaskViewFocusChanged(false); + mHeaderView.onTaskViewFocusChanged(false, true); } // Update the thumbnail alpha with the focus @@ -766,7 +607,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, mFocusAnimationsEnabled = true; if (mIsFocused && !wasFocusAnimationsEnabled) { // Re-notify the header if we were focused and animations were not previously enabled - mHeaderView.onTaskViewFocusChanged(true); + mHeaderView.onTaskViewFocusChanged(true, true); } } @@ -776,15 +617,12 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, public void onTaskBound(Task t) { mTask = t; mTask.setCallbacks(this); - if (getMeasuredWidth() == 0) { - // If we haven't yet measured, we should just set the footer height with any animation - animateFooterVisibility(t.lockToThisTask, 0); - } else { - animateFooterVisibility(t.lockToThisTask, mConfig.taskViewLockToAppLongAnimDuration); - } - // Hide the action button if lock to app is disabled - if (!t.lockToTaskEnabled && mActionButtonView.getVisibility() != View.GONE) { - mActionButtonView.setVisibility(View.GONE); + + // Hide the action button if lock to app is disabled for this view + int lockButtonVisibility = (!t.lockToTaskEnabled || !t.lockToThisTask) ? GONE : VISIBLE; + if (mActionButtonView.getVisibility() != lockButtonVisibility) { + mActionButtonView.setVisibility(lockButtonVisibility); + requestLayout(); } } @@ -792,18 +630,11 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, public void onTaskDataLoaded() { if (mThumbnailView != null && mHeaderView != null) { // Bind each of the views to the new task data - if (mIsFullScreenView) { - mThumbnailView.bindToScreenshot(AlternateRecentsComponent.getLastScreenshot()); - } else { - mThumbnailView.rebindToTask(mTask); - } + mThumbnailView.rebindToTask(mTask); mHeaderView.rebindToTask(mTask); // Rebind any listeners mHeaderView.mApplicationIcon.setOnClickListener(this); mHeaderView.mDismissButton.setOnClickListener(this); - if (mFooterView != null) { - mFooterView.setOnClickListener(this); - } mActionButtonView.setOnClickListener(this); if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) { if (mConfig.developerOptionsEnabled) { @@ -824,9 +655,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // Unbind any listeners mHeaderView.mApplicationIcon.setOnClickListener(null); mHeaderView.mDismissButton.setOnClickListener(null); - if (mFooterView != null) { - mFooterView.setOnClickListener(null); - } mActionButtonView.setOnClickListener(null); if (Constants.DebugFlags.App.EnableDevAppInfoOnLongPress) { mHeaderView.mApplicationIcon.setOnLongClickListener(null); @@ -840,19 +668,6 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, setOnClickListener(enabled ? this : null); } - /**** TaskViewFooter.TaskFooterViewCallbacks ****/ - - @Override - public void onTaskFooterHeightChanged(int height, int maxHeight) { - if (mIsFullScreenView) { - // Disable the bottom outline clip when fullscreen - mViewBounds.setOutlineClipBottom(0); - } else { - // Update the bottom clip in our outline provider - mViewBounds.setOutlineClipBottom(maxHeight - height); - } - } - /**** View.OnClickListener Implementation ****/ @Override @@ -876,8 +691,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, // Reset the translation of the action button before we animate it out mActionButtonView.setTranslationZ(0f); } - mCb.onTaskViewClicked(tv, tv.getTask(), - (v == mFooterView || v == mActionButtonView)); + mCb.onTaskViewClicked(tv, tv.getTask(), (v == mActionButtonView)); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java deleted file mode 100644 index 324169e..0000000 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewFooter.java +++ /dev/null @@ -1,98 +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.ObjectAnimator; -import android.content.Context; -import android.util.AttributeSet; -import android.widget.FrameLayout; -import com.android.systemui.recents.RecentsConfiguration; - - -/** The task footer view */ -public class TaskViewFooter extends FrameLayout { - - interface TaskFooterViewCallbacks { - public void onTaskFooterHeightChanged(int height, int maxHeight); - } - - RecentsConfiguration mConfig; - - TaskFooterViewCallbacks mCb; - int mFooterHeight; - int mMaxFooterHeight; - ObjectAnimator mFooterAnimator; - - public TaskViewFooter(Context context) { - this(context, null); - } - - public TaskViewFooter(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public TaskViewFooter(Context context, AttributeSet attrs, int defStyleAttr) { - this(context, attrs, defStyleAttr, 0); - } - - public TaskViewFooter(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(context, attrs, defStyleAttr, defStyleRes); - mConfig = RecentsConfiguration.getInstance(); - mMaxFooterHeight = mConfig.taskViewLockToAppButtonHeight; - setFooterHeight(getFooterHeight()); - } - - /** Sets the callbacks for when the footer height changes. */ - void setCallbacks(TaskFooterViewCallbacks cb) { - mCb = cb; - mCb.onTaskFooterHeightChanged(mFooterHeight, mMaxFooterHeight); - } - - /** Sets the footer height. */ - public void setFooterHeight(int footerHeight) { - if (footerHeight != mFooterHeight) { - mFooterHeight = footerHeight; - mCb.onTaskFooterHeightChanged(footerHeight, mMaxFooterHeight); - } - } - - /** Gets the footer height. */ - public int getFooterHeight() { - return mFooterHeight; - } - - /** Animates the footer into and out of view. */ - void animateFooterVisibility(final boolean visible, int duration) { - // Return early if there is no footer - if (mMaxFooterHeight <= 0) return; - - // Cancel the previous animation - if (mFooterAnimator != null) { - mFooterAnimator.removeAllListeners(); - mFooterAnimator.cancel(); - } - int finalHeight = visible ? mMaxFooterHeight : 0; - if (duration > 0) { - mFooterAnimator = ObjectAnimator.ofInt(this, "footerHeight", finalHeight); - mFooterAnimator.setDuration(duration); - mFooterAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mFooterAnimator.start(); - } else { - setFooterHeight(finalHeight); - } - } -} 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 396d441..ba868f5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -36,7 +36,6 @@ import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.RippleDrawable; -import android.graphics.drawable.ShapeDrawable; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; @@ -56,25 +55,27 @@ public class TaskViewHeader extends FrameLayout { RecentsConfiguration mConfig; + // Header views ImageView mDismissButton; ImageView mApplicationIcon; TextView mActivityDescription; - RippleDrawable mBackground; - GradientDrawable mBackgroundColorDrawable; + // Header drawables + boolean mCurrentPrimaryColorIsDark; + int mCurrentPrimaryColor; int mBackgroundColor; Drawable mLightDismissDrawable; Drawable mDarkDismissDrawable; + RippleDrawable mBackground; + GradientDrawable mBackgroundColorDrawable; AnimatorSet mFocusAnimator; - ValueAnimator backgroundColorAnimator; - PorterDuffColorFilter mDimFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); - - boolean mIsFullscreen; - boolean mCurrentPrimaryColorIsDark; - int mCurrentPrimaryColor; + // Static highlight that we draw at the top of each view static Paint sHighlightPaint; - private Paint mDimPaint = new Paint(); + + // Header dim, which is only used when task view hardware layers are not used + Paint mDimLayerPaint = new Paint(); + PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP); public TaskViewHeader(Context context) { this(context, null); @@ -159,21 +160,14 @@ public class TaskViewHeader extends FrameLayout { @Override protected void onDraw(Canvas canvas) { - if (!mIsFullscreen) { - // Draw the highlight at the top edge (but put the bottom edge just out of view) - float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f); - float radius = mConfig.taskViewRoundedCornerRadiusPx; - int count = canvas.save(Canvas.CLIP_SAVE_FLAG); - canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); - canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset, - getMeasuredHeight() + radius, radius, radius, sHighlightPaint); - canvas.restoreToCount(count); - } - } - - /** Sets whether the current task is full screen or not. */ - void setIsFullscreen(boolean isFullscreen) { - mIsFullscreen = isFullscreen; + // Draw the highlight at the top edge (but put the bottom edge just out of view) + float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f); + float radius = mConfig.taskViewRoundedCornerRadiusPx; + int count = canvas.save(Canvas.CLIP_SAVE_FLAG); + canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight()); + canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset, + getMeasuredHeight() + radius, radius, radius, sHighlightPaint); + canvas.restoreToCount(count); } @Override @@ -181,6 +175,16 @@ public class TaskViewHeader extends FrameLayout { return false; } + /** + * Sets the dim alpha, only used when we are not using hardware layers. + * (see RecentsConfiguration.useHardwareLayers) + */ + void setDimAlpha(int alpha) { + mDimColorFilter.setColor(Color.argb(alpha, 0, 0, 0)); + mDimLayerPaint.setColorFilter(mDimColorFilter); + setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint); + } + /** Returns the secondary color for a primary color. */ int getSecondaryColor(int primaryColor, boolean useLightOverlayColor) { int overlayColor = useLightOverlayColor ? Color.WHITE : Color.BLACK; @@ -268,13 +272,16 @@ public class TaskViewHeader extends FrameLayout { } /** Notifies the associated TaskView has been focused. */ - void onTaskViewFocusChanged(boolean focused) { + void onTaskViewFocusChanged(boolean focused, boolean animateFocusedState) { + // If we are not animating the visible state, just return + if (!animateFocusedState) return; + boolean isRunning = false; if (mFocusAnimator != null) { isRunning = mFocusAnimator.isRunning(); - mFocusAnimator.removeAllListeners(); - mFocusAnimator.cancel(); + Utilities.cancelAnimationWithoutCallbacks(mFocusAnimator); } + if (focused) { int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark); int[][] states = new int[][] { @@ -349,11 +356,4 @@ public class TaskViewHeader extends FrameLayout { } } } - - public void setDimAlpha(int alpha) { - int color = Color.argb(alpha, 0, 0, 0); - mDimFilter.setColor(color); - mDimPaint.setColorFilter(mDimFilter); - setLayerType(LAYER_TYPE_HARDWARE, mDimPaint); - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java index a946a84..c83248e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java @@ -33,37 +33,48 @@ import android.graphics.Shader; import android.util.AttributeSet; import android.view.View; import com.android.systemui.recents.RecentsConfiguration; +import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; -/** The task thumbnail view */ +/** + * The task thumbnail view. It implements an image view that allows for animating the dim and + * alpha of the thumbnail image. + */ public class TaskViewThumbnail extends View { - private final int mCornerRadius; - private final Matrix mScaleMatrix = new Matrix(); RecentsConfiguration mConfig; - // Task bar clipping - Rect mClipRect = new Rect(); + // Drawing + float mDimAlpha; + Matrix mScaleMatrix = new Matrix(); Paint mDrawPaint = new Paint(); + RectF mBitmapRect = new RectF(); + RectF mLayoutRect = new RectF(); + BitmapShader mBitmapShader; LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0); - private final RectF mBitmapRect = new RectF(); - private final RectF mLayoutRect = new RectF(); - private BitmapShader mBitmapShader; - private float mBitmapAlpha; - private float mDimAlpha; - private View mTaskBar; - private boolean mInvisible; - private ValueAnimator mAlphaAnimator; - private ValueAnimator.AnimatorUpdateListener mAlphaUpdateListener + + // Thumbnail alpha + float mThumbnailAlpha; + ValueAnimator mThumbnailAlphaAnimator; + ValueAnimator.AnimatorUpdateListener mThumbnailAlphaUpdateListener = new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { - mBitmapAlpha = (float) animation.getAnimatedValue(); - updateFilter(); + mThumbnailAlpha = (float) animation.getAnimatedValue(); + updateThumbnailPaintFilter(); } }; + // Task bar clipping, the top of this thumbnail can be clipped against the opaque header + // bar that overlaps this thumbnail + View mTaskBar; + Rect mClipRect = new Rect(); + + // Visibility optimization, if the thumbnail height is less than the height of the header + // bar for the task view, then just mark this thumbnail view as invisible + boolean mInvisible; + public TaskViewThumbnail(Context context) { this(context, null); } @@ -79,53 +90,82 @@ public class TaskViewThumbnail extends View { public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); mConfig = RecentsConfiguration.getInstance(); - mCornerRadius = mConfig.taskViewRoundedCornerRadiusPx; mDrawPaint.setColorFilter(mLightingColorFilter); mDrawPaint.setFilterBitmap(true); mDrawPaint.setAntiAlias(true); } @Override + protected void onFinishInflate() { + mThumbnailAlpha = mConfig.taskViewThumbnailAlpha; + updateThumbnailPaintFilter(); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + mLayoutRect.set(0, 0, getWidth(), getHeight()); + updateThumbnailScale(); + } + } + + @Override protected void onDraw(Canvas canvas) { if (mInvisible) { return; } - canvas.drawRoundRect(0, - 0, - getWidth(), - getHeight(), - mCornerRadius, - mCornerRadius, - mDrawPaint); + // Draw the thumbnail with the rounded corners + canvas.drawRoundRect(0, 0, getWidth(), getHeight(), + mConfig.taskViewRoundedCornerRadiusPx, + mConfig.taskViewRoundedCornerRadiusPx, mDrawPaint); } - @Override - protected void onFinishInflate() { - mBitmapAlpha = 0.9f; - updateFilter(); + /** Sets the thumbnail to a given bitmap. */ + void setThumbnail(Bitmap bm) { + if (bm != null) { + mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, + Shader.TileMode.CLAMP); + mDrawPaint.setShader(mBitmapShader); + mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight()); + updateThumbnailScale(); + } else { + mBitmapShader = null; + mDrawPaint.setShader(null); + } + updateThumbnailPaintFilter(); } - private void updateFilter() { + /** Updates the paint to draw the thumbnail. */ + void updateThumbnailPaintFilter() { if (mInvisible) { return; } - int mul = (int) ((1.0f - mDimAlpha) * mBitmapAlpha * 255); - int add = (int) ((1.0f - mDimAlpha) * (1 - mBitmapAlpha) * 255); + int mul = (int) ((1.0f - mDimAlpha) * mThumbnailAlpha * 255); + int add = (int) ((1.0f - mDimAlpha) * (1 - mThumbnailAlpha) * 255); if (mBitmapShader != null) { mLightingColorFilter.setColorMultiply(Color.argb(255, mul, mul, mul)); mLightingColorFilter.setColorAdd(Color.argb(0, add, add, add)); mDrawPaint.setColorFilter(mLightingColorFilter); mDrawPaint.setColor(0xffffffff); } else { - mDrawPaint.setColorFilter(null); int grey = mul + add; + mDrawPaint.setColorFilter(null); mDrawPaint.setColor(Color.argb(255, grey, grey, grey)); } invalidate(); } + /** Updates the thumbnail shader's scale transform. */ + void updateThumbnailScale() { + if (mBitmapShader != null) { + mScaleMatrix.setRectToRect(mBitmapRect, mLayoutRect, Matrix.ScaleToFit.FILL); + mBitmapShader.setLocalMatrix(mScaleMatrix); + } + } + /** Updates the clip rect based on the given task bar. */ - void enableTaskBarClip(View taskBar) { + void updateClipToTaskBar(View taskBar) { mTaskBar = taskBar; int top = (int) Math.max(0, taskBar.getTranslationY() + taskBar.getMeasuredHeight() - 1); @@ -133,75 +173,39 @@ public class TaskViewThumbnail extends View { setClipBounds(mClipRect); } - void updateVisibility(int clipBottom) { - boolean invisible = mTaskBar != null && getHeight() - clipBottom < mTaskBar.getHeight(); + /** Updates the visibility of the the thumbnail. */ + void updateThumbnailVisibility(int clipBottom) { + boolean invisible = mTaskBar != null && (getHeight() - clipBottom) <= mTaskBar.getHeight(); if (invisible != mInvisible) { mInvisible = invisible; if (!mInvisible) { - updateFilter(); + updateThumbnailPaintFilter(); } invalidate(); } } - /** Binds the thumbnail view to the screenshot. */ - boolean bindToScreenshot(Bitmap ss) { - setImageBitmap(ss); - return ss != null; - } - - /** Unbinds the thumbnail view from the screenshot. */ - void unbindFromScreenshot() { - setImageBitmap(null); + /** + * Sets the dim alpha, only used when we are not using hardware layers. + * (see RecentsConfiguration.useHardwareLayers) + */ + public void setDimAlpha(float dimAlpha) { + mDimAlpha = dimAlpha; + updateThumbnailPaintFilter(); } /** Binds the thumbnail view to the task */ void rebindToTask(Task t) { if (t.thumbnail != null) { - setImageBitmap(t.thumbnail); + setThumbnail(t.thumbnail); } else { - setImageBitmap(null); + setThumbnail(null); } } - public void setImageBitmap(Bitmap bm) { - if (bm != null) { - mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, - Shader.TileMode.CLAMP); - mDrawPaint.setShader(mBitmapShader); - mBitmapRect.set(0, 0, bm.getWidth(), bm.getHeight()); - updateBitmapScale(); - } else { - mBitmapShader = null; - mDrawPaint.setShader(null); - } - updateFilter(); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (changed) { - mLayoutRect.set(0, 0, getWidth(), getHeight()); - updateBitmapScale(); - } - } - - private void updateBitmapScale() { - if (mBitmapShader != null) { - mScaleMatrix.setRectToRect(mBitmapRect, mLayoutRect, Matrix.ScaleToFit.FILL); - mBitmapShader.setLocalMatrix(mScaleMatrix); - } - } - - public void setDimAlpha(float dimAlpha) { - mDimAlpha = dimAlpha; - updateFilter(); - } - /** Unbinds the thumbnail view from the task */ void unbindFromTask() { - setImageBitmap(null); + setThumbnail(null); } /** Handles focus changes. */ @@ -217,54 +221,46 @@ public class TaskViewThumbnail extends View { } } - /** Prepares for the enter recents animation. */ + /** + * Prepares for the enter recents animation, this gets called before the the view + * is first visible and will be followed by a startEnterRecentsAnimation() call. + */ void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask) { if (isTaskViewLaunchTargetTask) { - mBitmapAlpha = 1f; + mThumbnailAlpha = 1f; } else { - mBitmapAlpha = mConfig.taskViewThumbnailAlpha; + mThumbnailAlpha = mConfig.taskViewThumbnailAlpha; } - updateFilter(); + updateThumbnailPaintFilter(); } - /** Animates this task thumbnail as it enters recents */ + /** Animates this task thumbnail as it enters Recents. */ void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) { startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay, mConfig.taskBarEnterAnimDuration, postAnimRunnable); } - /** Animates this task thumbnail as it exits recents */ + /** Animates this task thumbnail as it exits Recents. */ void startLaunchTaskAnimation(Runnable postAnimRunnable) { startFadeAnimation(1f, 0, mConfig.taskBarExitAnimDuration, postAnimRunnable); } - /** Animates the thumbnail alpha. */ + /** Starts a new thumbnail alpha animation. */ void startFadeAnimation(float finalAlpha, int delay, int duration, final Runnable postAnimRunnable) { - if (mAlphaAnimator != null) { - mAlphaAnimator.cancel(); - } - mAlphaAnimator = ValueAnimator.ofFloat(mBitmapAlpha, finalAlpha); - mAlphaAnimator.addUpdateListener(mAlphaUpdateListener); - mAlphaAnimator.setStartDelay(delay); - mAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); - mAlphaAnimator.setDuration(duration); - mAlphaAnimator.start(); + Utilities.cancelAnimationWithoutCallbacks(mThumbnailAlphaAnimator); + mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha); + mThumbnailAlphaAnimator.setStartDelay(delay); + mThumbnailAlphaAnimator.setDuration(duration); + mThumbnailAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator); + mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener); if (postAnimRunnable != null) { - mAlphaAnimator.addListener(new AnimatorListenerAdapter() { - public boolean mCancelled; - - @Override - public void onAnimationCancel(Animator animation) { - mCancelled = true; - } - + mThumbnailAlphaAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { - if (!mCancelled) { - postAnimRunnable.run(); - } + postAnimRunnable.run(); } }); } + mThumbnailAlphaAnimator.start(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index f5e5517..1b4bdf8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -69,6 +69,7 @@ import android.view.View; import android.view.ViewAnimationUtils; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.ViewParent; import android.view.ViewStub; import android.view.WindowManager; import android.view.WindowManagerGlobal; @@ -266,6 +267,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (DEBUG) { Log.v(TAG, "Notification click handler invoked for intent: " + pendingIntent); } + logActionClick(view); // The intent we are sending is for the application, which // won't have permission to immediately start an activity after // the user switches to home. We know it is safe to do at this @@ -295,7 +297,8 @@ public abstract class BaseStatusBar extends SystemUI implements // close the shade if it was open if (handled) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, + true /* force */); visibilityChanged(false); } // Wait for activity start. @@ -308,6 +311,37 @@ public abstract class BaseStatusBar extends SystemUI implements } } + private void logActionClick(View view) { + ViewParent parent = view.getParent(); + String key = getNotificationKeyForParent(parent); + if (key == null) { + Log.w(TAG, "Couldn't determine notification for click."); + return; + } + int index = -1; + // If this is a default template, determine the index of the button. + if (view.getId() == com.android.internal.R.id.action0 && + parent != null && parent instanceof ViewGroup) { + ViewGroup actionGroup = (ViewGroup) parent; + index = actionGroup.indexOfChild(view); + } + try { + mBarService.onNotificationActionClick(key, index); + } catch (RemoteException e) { + // Ignore + } + } + + private String getNotificationKeyForParent(ViewParent parent) { + while (parent != null) { + if (parent instanceof ExpandableNotificationRow) { + return ((ExpandableNotificationRow) parent).getStatusBarNotification().getKey(); + } + parent = parent.getParent(); + } + return null; + } + private boolean superOnClickHandler(View view, PendingIntent pendingIntent, Intent fillInIntent) { return super.onClickHandler(view, pendingIntent, fillInIntent); @@ -341,7 +375,8 @@ public abstract class BaseStatusBar extends SystemUI implements Settings.Secure.putInt(mContext.getContentResolver(), Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0); if (BANNER_ACTION_SETUP.equals(action)) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, + true /* force */); mContext.startActivity(new Intent(Settings.ACTION_APP_NOTIFICATION_REDACTION) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) @@ -766,7 +801,7 @@ public abstract class BaseStatusBar extends SystemUI implements } } }); - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); return true; } }, false /* afterKeyguardGone */); @@ -1531,7 +1566,8 @@ public abstract class BaseStatusBar extends SystemUI implements }.start(); // close the shade if it was open - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, + true /* force */); visibilityChanged(false); return mIntent != null && mIntent.isActivity(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java index 9196dc8..556c423 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java @@ -158,6 +158,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView { public void resetHeight() { mMaxExpandHeight = 0; mWasReset = true; + mActualHeight = 0; onHeightReset(); requestLayout(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index b71c9bf..9154a48 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -49,7 +49,6 @@ public class SignalClusterView private boolean mIsAirplaneMode = false; private int mAirplaneIconId = 0; private String mWifiDescription, mMobileDescription, mMobileTypeDescription; - private boolean mRoaming; private boolean mIsMobileTypeIconWide; ViewGroup mWifiGroup, mMobileGroup; @@ -58,6 +57,8 @@ public class SignalClusterView View mWifiSignalSpacer; private int mWideTypeIconStartPadding; + private int mEndPadding; + private int mEndPaddingNothingVisible; public SignalClusterView(Context context) { this(context, null); @@ -88,6 +89,10 @@ public class SignalClusterView super.onFinishInflate(); mWideTypeIconStartPadding = getContext().getResources().getDimensionPixelSize( R.dimen.wide_type_icon_start_padding); + mEndPadding = getContext().getResources().getDimensionPixelSize( + R.dimen.signal_cluster_battery_padding); + mEndPaddingNothingVisible = getContext().getResources().getDimensionPixelSize( + R.dimen.no_signal_cluster_battery_padding); } @Override @@ -143,14 +148,12 @@ public class SignalClusterView @Override public void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon, - String contentDescription, String typeContentDescription, boolean roaming, - boolean isTypeIconWide) { + String contentDescription, String typeContentDescription, boolean isTypeIconWide) { mMobileVisible = visible; mMobileStrengthId = strengthIcon; mMobileTypeId = typeIcon; mMobileDescription = contentDescription; mMobileTypeDescription = typeContentDescription; - mRoaming = roaming; mIsMobileTypeIconWide = isTypeIconWide; apply(); @@ -244,7 +247,7 @@ public class SignalClusterView mWifiAirplaneSpacer.setVisibility(View.GONE); } - if (mRoaming && mMobileVisible && mWifiVisible) { + if (mMobileVisible && mMobileTypeId != 0 && mWifiVisible) { mWifiSignalSpacer.setVisibility(View.VISIBLE); } else { mWifiSignalSpacer.setVisibility(View.GONE); @@ -257,7 +260,10 @@ public class SignalClusterView (mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId)); - mMobileType.setVisibility((mRoaming || mMobileTypeId != 0) ? View.VISIBLE : View.GONE); + mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE); + + boolean anythingVisible = mWifiVisible || mIsAirplaneMode || mMobileVisible || mVpnVisible; + setPaddingRelative(0, 0, anythingVisible ? mEndPadding : mEndPaddingNothingVisible, 0); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java index c5d06b9..682c01c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -122,9 +122,14 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { } String cast = args.getString("cast"); if (cast != null) { - int iconId = cast.equals("cast") ? R.drawable.stat_sys_cast : 0; + int iconId = cast.equals("show") ? R.drawable.stat_sys_cast : 0; updateSlot("cast", null, iconId); } + String hotspot = args.getString("hotspot"); + if (hotspot != null) { + int iconId = hotspot.equals("show") ? R.drawable.stat_sys_hotspot : 0; + updateSlot("hotspot", null, iconId); + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java index dd5df12..598a35c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java @@ -133,7 +133,7 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL if (action == ACTION_CLICK) { if (host == mLockIcon) { mPhoneStatusBar.animateCollapsePanels( - CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); return true; } else if (host == mCameraImageView) { launchCamera(); @@ -477,6 +477,11 @@ public class KeyguardBottomAreaView extends FrameLayout implements View.OnClickL public void onScreenTurnedOff(int why) { updateLockIcon(); } + + @Override + public void onKeyguardVisibilityChanged(boolean showing) { + updateLockIcon(); + } }; public void setKeyguardIndicationController( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java index 650a14f..40c9134 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java @@ -36,6 +36,8 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.KeyguardUserSwitcher; import com.android.systemui.statusbar.policy.UserInfoController; +import java.text.NumberFormat; + /** * The header group on Keyguard. */ @@ -150,7 +152,8 @@ public class KeyguardStatusBarView extends RelativeLayout @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { - mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); + String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); + mBatteryLevel.setText(percentage); boolean changed = mBatteryCharging != charging; mBatteryCharging = charging; if (changed) { 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 a6fccb6..c19bdff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -802,6 +802,7 @@ public class NotificationPanelView extends PanelView implements requestPanelHeightUpdate(); mNotificationStackScroller.setInterceptDelegateEnabled(expanded); mStatusBar.setQsExpanded(expanded); + mQsPanel.setExpanded(expanded); } } 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 f74d2f4..3efaaff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -236,4 +236,8 @@ public class PanelBar extends FrameLayout { public void onExpandingFinished() { } + + public void onClosingFinished() { + + } } 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 a7ff0bd..0ddda8a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -68,7 +68,6 @@ public abstract class PanelView extends FrameLayout { protected int mTouchSlop; protected boolean mHintAnimationRunning; private boolean mOverExpandedBeforeFling; - private float mOriginalIndicationY; private boolean mTouchAboveFalsingThreshold; private int mUnlockFalsingThreshold; @@ -107,7 +106,7 @@ public abstract class PanelView extends FrameLayout { }; protected void onExpandingFinished() { - mClosing = false; + endClosing(); mBar.onExpandingFinished(); } @@ -250,9 +249,7 @@ public abstract class PanelView extends FrameLayout { trackMovement(event); if (!waitForTouchSlop || (mHeightAnimator != null && !mHintAnimationRunning) || mPeekPending || mPeekAnimator != null) { - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); // end any outstanding animations - } + cancelHeightAnimator(); cancelPeek(); mTouchSlopExceeded = (mHeightAnimator != null && !mHintAnimationRunning) || mPeekPending || mPeekAnimator != null; @@ -293,9 +290,7 @@ public abstract class PanelView extends FrameLayout { mInitialTouchY = y; h = 0; } - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); // end any outstanding animations - } + cancelHeightAnimator(); removeCallbacks(mPeekRunnable); mPeekPending = false; onTrackingStarted(); @@ -372,7 +367,7 @@ public abstract class PanelView extends FrameLayout { } protected void onTrackingStarted() { - mClosing = false; + endClosing(); mTracking = true; mCollapseAfterPeek = false; mBar.onTrackingStarted(PanelView.this); @@ -407,9 +402,7 @@ public abstract class PanelView extends FrameLayout { mStatusBar.userActivity(); if (mHeightAnimator != null && !mHintAnimationRunning || mPeekPending || mPeekAnimator != null) { - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); // end any outstanding animations - } + cancelHeightAnimator(); cancelPeek(); mTouchSlopExceeded = true; return true; @@ -441,9 +434,7 @@ public abstract class PanelView extends FrameLayout { trackMovement(event); if (scrolledToBottom) { if (h < -mTouchSlop && h < -Math.abs(x - mInitialTouchX)) { - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); - } + cancelHeightAnimator(); mInitialOffsetOnTouch = mExpandedHeight; mInitialTouchY = y; mInitialTouchX = x; @@ -461,6 +452,20 @@ public abstract class PanelView extends FrameLayout { return false; } + private void cancelHeightAnimator() { + if (mHeightAnimator != null) { + mHeightAnimator.cancel(); + } + endClosing(); + } + + private void endClosing() { + if (mClosing) { + mClosing = false; + onClosingFinished(); + } + } + private void initVelocityTracker() { if (mVelocityTracker != null) { mVelocityTracker.recycle(); @@ -700,9 +705,7 @@ public abstract class PanelView extends FrameLayout { mPeekRunnable.run(); } } else if (!isFullyCollapsed() && !mTracking && !mClosing) { - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); - } + cancelHeightAnimator(); mClosing = true; notifyExpandingStarted(); if (delayed) { @@ -785,13 +788,16 @@ public abstract class PanelView extends FrameLayout { private void abortAnimations() { cancelPeek(); - if (mHeightAnimator != null) { - mHeightAnimator.cancel(); - } + cancelHeightAnimator(); removeCallbacks(mPostCollapseRunnable); removeCallbacks(mFlingCollapseRunnable); } + protected void onClosingFinished() { + mBar.onClosingFinished(); + } + + protected void startUnlockHintAnimation() { // We don't need to hint the user if an animation is already running or the user is changing @@ -841,16 +847,15 @@ public abstract class PanelView extends FrameLayout { }); animator.start(); mHeightAnimator = animator; - mOriginalIndicationY = mKeyguardBottomArea.getIndicationView().getY(); mKeyguardBottomArea.getIndicationView().animate() - .y(mOriginalIndicationY - mHintDistance) + .translationY(-mHintDistance) .setDuration(250) .setInterpolator(mFastOutSlowInInterpolator) .withEndAction(new Runnable() { @Override public void run() { mKeyguardBottomArea.getIndicationView().animate() - .y(mOriginalIndicationY) + .translationY(0) .setDuration(450) .setInterpolator(mBounceInterpolator) .start(); 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 9e3f0f6..9a33a36 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -40,6 +40,7 @@ import android.app.Notification; import android.app.PendingIntent; import android.app.StatusBarManager; import android.content.BroadcastReceiver; +import android.content.ComponentCallbacks2; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; @@ -95,6 +96,7 @@ import android.view.ViewPropertyAnimator; import android.view.ViewStub; import android.view.ViewTreeObserver; import android.view.WindowManager; +import android.view.WindowManagerGlobal; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityManager; import android.view.animation.AccelerateDecelerateInterpolator; @@ -173,6 +175,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Map; public class PhoneStatusBar extends BaseStatusBar implements DemoMode, DragDownHelper.DragDownCallback, ActivityStarter { @@ -581,7 +584,7 @@ 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); + mIconPolicy = new PhoneStatusBarPolicy(mContext, mCastController, mHotspotController); mSettingsObserver.onChange(false); // set up mHeadsUpObserver.onChange(true); // set up @@ -798,7 +801,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } mUserInfoController = new UserInfoController(mContext); mVolumeComponent = getComponent(VolumeComponent.class); - mZenModeController = mVolumeComponent.getZenController(); + if (mVolumeComponent != null) { + mZenModeController = mVolumeComponent.getZenController(); + } mCastController = new CastControllerImpl(mContext); final SignalClusterView signalCluster = (SignalClusterView) mStatusBarView.findViewById(R.id.signal_cluster); @@ -2413,6 +2418,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false); showBouncer(); disable(mDisabledUnmodified, true /* animate */); + + // Trimming will happen later if Keyguard is showing - doing it here might cause a jank in + // the bouncer appear animation. + if (!mStatusBarKeyguardViewManager.isShowing()) { + WindowManagerGlobal.getInstance().trimMemory(ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); + } } public boolean interceptTouchEvent(MotionEvent event) { @@ -2955,6 +2966,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, if (mSecurityController != null) { mSecurityController.dump(fd, pw, args); } + pw.println("SharedPreferences:"); + for (Map.Entry<String, ?> entry : mContext.getSharedPreferences(mContext.getPackageName(), + Context.MODE_PRIVATE).getAll().entrySet()) { + pw.print(" "); pw.print(entry.getKey()); pw.print("="); pw.println(entry.getValue()); + } } private String hunStateToString(Entry entry) { @@ -3036,7 +3052,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, } }); if (dismissShade) { - animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */); + animateCollapsePanels( + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */); } return true; } @@ -3725,7 +3742,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, public boolean onSpacePressed() { if (mScreenOn != null && mScreenOn && (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)) { - animateCollapsePanels(0 /* flags */, true /* force */); + animateCollapsePanels( + CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL /* flags */, true /* force */); return true; } return false; @@ -3779,6 +3797,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, runPostCollapseRunnables(); } + public void onClosingFinished() { + runPostCollapseRunnables(); + } + public void onUnlockHintStarted() { mKeyguardIndicationController.showTransientIndication(R.string.keyguard_unlock); } 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 47e1ab5..60d23ce 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -35,6 +35,7 @@ import com.android.internal.telephony.TelephonyIntents; import com.android.systemui.R; import com.android.systemui.statusbar.policy.CastController; import com.android.systemui.statusbar.policy.CastController.CastDevice; +import com.android.systemui.statusbar.policy.HotspotController; /** * This class contains all of the policy about which icons are installed in the status @@ -49,6 +50,7 @@ public class PhoneStatusBarPolicy { private static final String SLOT_SYNC_ACTIVE = "sync_active"; private static final String SLOT_CAST = "cast"; + private static final String SLOT_HOTSPOT = "hotspot"; private static final String SLOT_BLUETOOTH = "bluetooth"; private static final String SLOT_TTY = "tty"; private static final String SLOT_ZEN = "zen"; @@ -60,6 +62,7 @@ public class PhoneStatusBarPolicy { private final StatusBarManager mService; private final Handler mHandler = new Handler(); private final CastController mCast; + private final HotspotController mHotspot; // Assume it's all good unless we hear otherwise. We don't always seem // to get broadcasts that it *is* there. @@ -102,9 +105,10 @@ public class PhoneStatusBarPolicy { } }; - public PhoneStatusBarPolicy(Context context, CastController cast) { + public PhoneStatusBarPolicy(Context context, CastController cast, HotspotController hotspot) { mContext = context; mCast = cast; + mHotspot = hotspot; mService = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); // listen for broadcasts @@ -152,6 +156,11 @@ public class PhoneStatusBarPolicy { mService.setIcon(SLOT_CAST, R.drawable.stat_sys_cast, 0, null); mService.setIconVisibility(SLOT_CAST, false); mCast.addCallback(mCastCallback); + + // hotspot + mService.setIcon(SLOT_HOTSPOT, R.drawable.stat_sys_hotspot, 0, null); + mService.setIconVisibility(SLOT_HOTSPOT, mHotspot.isHotspotEnabled()); + mHotspot.addCallback(mHotspotCallback); } public void setZenMode(int zen) { @@ -300,6 +309,13 @@ public class PhoneStatusBarPolicy { mService.setIconVisibility(SLOT_CAST, isCasting); } + private final HotspotController.Callback mHotspotCallback = new HotspotController.Callback() { + @Override + public void onHotspotChanged(boolean enabled) { + mService.setIconVisibility(SLOT_HOTSPOT, enabled); + } + }; + private final CastController.Callback mCastCallback = new CastController.Callback() { @Override public void onCastDevicesChanged() { 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 6411fb8..e4eae38 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -20,7 +20,6 @@ import android.content.Context; import android.content.res.Resources; import android.util.AttributeSet; import android.util.EventLog; -import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; @@ -152,6 +151,12 @@ public class PhoneStatusBarView extends PanelBar { } @Override + public void onClosingFinished() { + super.onClosingFinished(); + mBar.onClosingFinished(); + } + + @Override public void onTrackingStopped(PanelView panel, boolean expand) { super.onTrackingStopped(panel, expand); mBar.onTrackingStopped(expand); 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 2dc08d4..a4db46a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java @@ -120,6 +120,7 @@ public class QSTileHost implements QSTile.Host { tile.userSwitch(newUserId); } mSecurity.onUserSwitched(newUserId); + mNetwork.onUserSwitched(newUserId); mObserver.register(); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java index b0f3ea1..247252c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java @@ -48,6 +48,8 @@ import com.android.systemui.statusbar.policy.BatteryController; import com.android.systemui.statusbar.policy.NextAlarmController; import com.android.systemui.statusbar.policy.UserInfoController; +import java.text.NumberFormat; + /** * The view to manage the header area in the expanded status bar. */ @@ -300,9 +302,6 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL updateSystemIconsLayoutParams(); updateClickTargets(); updateMultiUserSwitch(); - if (mQSPanel != null) { - mQSPanel.setExpanded(mExpanded); - } updateClockScale(); updateAvatarScale(); updateClockLp(); @@ -395,7 +394,8 @@ public class StatusBarHeaderView extends RelativeLayout implements View.OnClickL @Override public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) { - mBatteryLevel.setText(getResources().getString(R.string.battery_level_template, level)); + String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0); + mBatteryLevel.setText(percentage); } @Override 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 55c861a..65d231e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.phone; +import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Bundle; import android.os.RemoteException; @@ -24,6 +25,7 @@ import android.util.Slog; import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; +import android.view.WindowManagerGlobal; import com.android.internal.policy.IKeyguardShowCallback; import com.android.internal.widget.LockPatternUtils; @@ -268,6 +270,8 @@ public class StatusBarKeyguardViewManager { public void run() { mStatusBarWindowManager.setKeyguardFadingAway(false); mPhoneStatusBar.finishKeyguardFadingAway(); + WindowManagerGlobal.getInstance().trimMemory( + ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN); } }); } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java index dcda2c7..b89aa8f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/TrustDrawable.java @@ -133,6 +133,7 @@ public class TrustDrawable extends Drawable { if (!mAnimating) { mAnimating = true; updateState(true); + invalidateSelf(); } } @@ -146,18 +147,21 @@ public class TrustDrawable extends Drawable { mState = STATE_UNSET; mCurAlpha = 0; mCurInnerRadius = mInnerRadiusEnter; + invalidateSelf(); } } public void setTrustManaged(boolean trustManaged) { if (trustManaged == mTrustManaged && mState != STATE_UNSET) return; mTrustManaged = trustManaged; - if (mAnimating) { - updateState(true); - } + updateState(true); } - private void updateState(boolean animate) { + private void updateState(boolean allowTransientState) { + if (!mAnimating) { + return; + } + int nextState = mState; if (mState == STATE_UNSET) { nextState = mTrustManaged ? STATE_ENTERING : STATE_GONE; @@ -170,7 +174,7 @@ public class TrustDrawable extends Drawable { } else if (mState == STATE_EXITING) { if (mTrustManaged) nextState = STATE_ENTERING; } - if (!animate) { + if (!allowTransientState) { if (nextState == STATE_ENTERING) nextState = STATE_VISIBLE; if (nextState == STATE_EXITING) nextState = STATE_GONE; } @@ -200,9 +204,8 @@ public class TrustDrawable extends Drawable { mState = nextState; if (mCurAnimator != null) { mCurAnimator.start(); - } else { - invalidateSelf(); } + invalidateSelf(); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiAccessPointController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java index b800fbf..0a385d7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiAccessPointController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointController.java @@ -16,15 +16,20 @@ package com.android.systemui.statusbar.policy; +import android.app.ActivityManager; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.ScanResult; import android.net.wifi.WifiConfiguration; +import android.net.wifi.WifiConfiguration.KeyMgmt; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager.ActionListener; +import android.os.UserHandle; +import android.os.UserManager; +import android.provider.Settings; import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; @@ -39,9 +44,13 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; -public class WifiAccessPointController { - private static final String TAG = "WifiAccessPointController"; - private static final boolean DEBUG = false; +public class AccessPointController { + private static final String TAG = "AccessPointController"; + private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); + + // This string extra specifies a network to open the connect dialog on, so the user can enter + // network credentials. This is used by quick settings for secured networks. + private static final String EXTRA_START_CONNECT_SSID = "wifi_start_connect_ssid"; private static final int[] ICONS = { R.drawable.ic_qs_wifi_0, @@ -54,13 +63,26 @@ public class WifiAccessPointController { private final Context mContext; private final ArrayList<AccessPointCallback> mCallbacks = new ArrayList<AccessPointCallback>(); private final WifiManager mWifiManager; + private final UserManager mUserManager; private final Receiver mReceiver = new Receiver(); private boolean mScanning; + private int mCurrentUser; - public WifiAccessPointController(Context context) { + public AccessPointController(Context context) { mContext = context; mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE); + mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); + mCurrentUser = ActivityManager.getCurrentUser(); + } + + public boolean canConfigWifi() { + return !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_WIFI, + new UserHandle(mCurrentUser)); + } + + void onUserSwitched(int newUserId) { + mCurrentUser = newUserId; } public void addCallback(AccessPointCallback callback) { @@ -81,22 +103,31 @@ public class WifiAccessPointController { if (mScanning) return; if (DEBUG) Log.d(TAG, "scan!"); mScanning = mWifiManager.startScan(); + // Grab current networks immediately while we wait for scan. + updateAccessPoints(); } - public void connect(AccessPoint ap) { - if (ap == null || ap.networkId < 0) return; + public boolean connect(AccessPoint ap) { + if (ap == null) return false; if (DEBUG) Log.d(TAG, "connect networkId=" + ap.networkId); - mWifiManager.connect(ap.networkId, new ActionListener() { - @Override - public void onSuccess() { - if (DEBUG) Log.d(TAG, "connect success"); - } - - @Override - public void onFailure(int reason) { - if (DEBUG) Log.d(TAG, "connect failure reason=" + reason); + if (ap.networkId < 0) { + // Unknown network, need to add it. + if (ap.hasSecurity) { + Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); + intent.putExtra(EXTRA_START_CONNECT_SSID, ap.ssid); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mContext.startActivity(intent); + return true; + } else { + WifiConfiguration config = new WifiConfiguration(); + config.SSID = "\"" + ap.ssid + "\""; + config.allowedKeyManagement.set(KeyMgmt.NONE); + mWifiManager.connect(config, mConnectListener); } - }); + } else { + mWifiManager.connect(ap.networkId, mConnectListener); + } + return false; } private void fireCallback(AccessPoint[] aps) { @@ -139,23 +170,40 @@ public class WifiAccessPointController { } final String ssid = scanResult.SSID; if (TextUtils.isEmpty(ssid) || ssids.contains(ssid)) continue; - if (!configured.containsKey(ssid)) continue; ssids.add(ssid); final WifiConfiguration config = configured.get(ssid); final int level = WifiManager.calculateSignalLevel(scanResult.level, ICONS.length); final AccessPoint ap = new AccessPoint(); + ap.isConfigured = config != null; ap.networkId = config != null ? config.networkId : AccessPoint.NO_NETWORK; ap.ssid = ssid; ap.iconId = ICONS[level]; ap.isConnected = ap.networkId != AccessPoint.NO_NETWORK && ap.networkId == connectedNetworkId; ap.level = level; + // Based on Settings AccessPoint#getSecurity, keep up to date + // with better methods of determining no security or not. + ap.hasSecurity = scanResult.capabilities.contains("WEP") + || scanResult.capabilities.contains("PSK") + || scanResult.capabilities.contains("EAP"); aps.add(ap); } Collections.sort(aps, mByStrength); fireCallback(aps.toArray(new AccessPoint[aps.size()])); } + private final ActionListener mConnectListener = new ActionListener() { + @Override + public void onSuccess() { + if (DEBUG) Log.d(TAG, "connect success"); + } + + @Override + public void onFailure(int reason) { + if (DEBUG) Log.d(TAG, "connect failure reason=" + reason); + } + }; + private final Comparator<AccessPoint> mByStrength = new Comparator<AccessPoint> () { @Override public int compare(AccessPoint lhs, AccessPoint rhs) { @@ -163,7 +211,7 @@ public class WifiAccessPointController { } private int score(AccessPoint ap) { - return ap.level + (ap.isConnected ? 10 : 0); + return ap.level + (ap.isConnected ? 20 : 0) + (ap.isConfigured ? 10 : 0); } }; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java index 6f021ac..33f7aff 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java @@ -308,7 +308,11 @@ public class FlashlightController { new CameraCaptureSession.StateListener() { @Override public void onConfigured(CameraCaptureSession session) { - mSession = session; + if (session.getDevice() == mCameraDevice) { + mSession = session; + } else { + session.close(); + } postUpdateFlashlight(); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java index 2ed9366..bb29d01 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java @@ -39,11 +39,13 @@ public interface NetworkController { void addAccessPointCallback(AccessPointCallback callback); void removeAccessPointCallback(AccessPointCallback callback); void scanForAccessPoints(); - void connect(AccessPoint ap); + boolean connect(AccessPoint ap); boolean isMobileDataSupported(); boolean isMobileDataEnabled(); void setMobileDataEnabled(boolean enabled); DataUsageInfo getDataUsageInfo(); + boolean canConfigWifi(); + void onUserSwitched(int newUserId); public interface AccessPointCallback { void onAccessPointsChanged(AccessPoint[] accessPoints); @@ -56,6 +58,8 @@ public interface NetworkController { public int iconId; public String ssid; public boolean isConnected; + public boolean isConfigured; + public boolean hasSecurity; public int level; // 0 - 5 } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 3625997..6c0b425 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -164,12 +164,11 @@ public class NetworkControllerImpl extends BroadcastReceiver public interface SignalCluster { void setWifiIndicators(boolean visible, int strengthIcon, String contentDescription); void setMobileDataIndicators(boolean visible, int strengthIcon, int typeIcon, - String contentDescription, String typeContentDescription, boolean roaming, - boolean isTypeIconWide); + String contentDescription, String typeContentDescription, boolean isTypeIconWide); void setIsAirplaneMode(boolean is, int airplaneIcon); } - private final WifiAccessPointController mAccessPoints; + private final AccessPointController mAccessPoints; private final MobileDataController mMobileDataController; /** @@ -240,7 +239,7 @@ public class NetworkControllerImpl extends BroadcastReceiver updateAirplaneMode(); mLastLocale = mContext.getResources().getConfiguration().locale; - mAccessPoints = new WifiAccessPointController(mContext); + mAccessPoints = new AccessPointController(mContext); mMobileDataController = new MobileDataController(mContext); mMobileDataController.setCallback(new MobileDataController.Callback() { @Override @@ -250,6 +249,16 @@ public class NetworkControllerImpl extends BroadcastReceiver }); } + @Override + public boolean canConfigWifi() { + return mAccessPoints.canConfigWifi(); + } + + @Override + public void onUserSwitched(int newUserId) { + mAccessPoints.onUserSwitched(newUserId); + } + private void notifyMobileDataEnabled(boolean enabled) { for (NetworkSignalChangedCallback cb : mSignalsChangedCallbacks) { cb.onMobileDataEnabled(enabled); @@ -314,8 +323,8 @@ public class NetworkControllerImpl extends BroadcastReceiver } @Override - public void connect(AccessPoint ap) { - mAccessPoints.connect(ap); + public boolean connect(AccessPoint ap) { + return mAccessPoints.connect(ap); } @Override @@ -386,7 +395,6 @@ public class NetworkControllerImpl extends BroadcastReceiver mDataTypeIconId, mContentDescriptionWimax, mContentDescriptionDataType, - mDataTypeIconId == TelephonyIcons.ROAMING_ICON, false /* isTypeIconWide */ ); } else { // normal mobile data @@ -396,7 +404,6 @@ public class NetworkControllerImpl extends BroadcastReceiver mDataTypeIconId, mContentDescriptionPhoneSignal, mContentDescriptionDataType, - mDataTypeIconId == TelephonyIcons.ROAMING_ICON, isTypeIconWide(mDataTypeIconId)); } cluster.setIsAirplaneMode(mAirplaneMode, mAirplaneIconId); @@ -1606,7 +1613,6 @@ public class NetworkControllerImpl extends BroadcastReceiver mDemoDataTypeIconId, "Demo", "Demo", - mDemoDataTypeIconId == TelephonyIcons.ROAMING_ICON, isTypeIconWide(mDemoDataTypeIconId)); } refreshViews(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index eb808c2..5c7909a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -571,6 +571,9 @@ public class UserSwitcherController { cancel(); } else { dismiss(); + if (ActivityManager.isUserAMonkey()) { + return; + } UserInfo user = mUserManager.createSecondaryUser( mContext.getString(R.string.user_new_user_name), 0 /* flags */); if (user == null) { diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java index 0586a83..0fe6d89 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeUI.java @@ -1,7 +1,6 @@ package com.android.systemui.volume; import android.content.Context; -import android.content.Intent; import android.content.res.Configuration; import android.database.ContentObserver; import android.media.AudioManager; @@ -11,13 +10,10 @@ import android.media.session.ISessionController; import android.media.session.MediaController; import android.media.session.MediaSessionManager; import android.net.Uri; -import android.os.AsyncTask; import android.os.Handler; import android.os.RemoteException; -import android.os.UserHandle; import android.provider.Settings; import android.util.Log; -import android.view.WindowManagerGlobal; import com.android.systemui.R; import com.android.systemui.SystemUI; @@ -53,6 +49,7 @@ public class VolumeUI extends SystemUI { private final Handler mHandler = new Handler(); + private boolean mEnabled; private AudioManager mAudioManager; private MediaSessionManager mMediaSessionManager; private VolumeController mVolumeController; @@ -63,6 +60,8 @@ public class VolumeUI extends SystemUI { @Override public void start() { + mEnabled = mContext.getResources().getBoolean(R.bool.enable_volume_ui); + if (!mEnabled) return; mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE); mMediaSessionManager = (MediaSessionManager) mContext .getSystemService(Context.MEDIA_SESSION_SERVICE); @@ -84,6 +83,7 @@ public class VolumeUI extends SystemUI { @Override public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { + pw.print("mEnabled="); pw.println(mEnabled); if (mPanel != null) { mPanel.dump(fd, pw, args); } diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java index ea431ae..c840f17 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java +++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java @@ -31,6 +31,7 @@ import android.provider.Settings; import android.provider.Settings.Global; import android.service.notification.Condition; import android.service.notification.ZenModeConfig; +import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.util.MathUtils; @@ -220,7 +221,8 @@ public class ZenModePanel extends LinearLayout { mBucketIndex = -1; } else { mBucketIndex = DEFAULT_BUCKET_INDEX; - mTimeCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]); + mTimeCondition = ZenModeConfig.toTimeCondition(mContext, + MINUTE_BUCKETS[mBucketIndex]); } if (DEBUG) Log.d(mTag, "Initial bucket index: " + mBucketIndex); mConditions = null; // reset conditions @@ -339,9 +341,11 @@ public class ZenModePanel extends LinearLayout { if (condition == null) return null; final long time = ZenModeConfig.tryParseCountdownConditionId(condition.id); if (time == 0) return null; - final long span = time - System.currentTimeMillis(); + final long now = System.currentTimeMillis(); + final long span = time - now; if (span <= 0 || span > MAX_BUCKET_MINUTES * MINUTES_MS) return null; - return ZenModeConfig.toTimeCondition(time, Math.round(span / (float) MINUTES_MS)); + return ZenModeConfig.toTimeCondition(mContext, + time, Math.round(span / (float) MINUTES_MS), now); } private void handleUpdateConditions(Condition[] conditions) { @@ -395,7 +399,7 @@ public class ZenModePanel extends LinearLayout { if (favoriteIndex == -1) { getConditionTagAt(FOREVER_CONDITION_INDEX).rb.setChecked(true); } else { - mTimeCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[favoriteIndex]); + mTimeCondition = ZenModeConfig.toTimeCondition(mContext, MINUTE_BUCKETS[favoriteIndex]); mBucketIndex = favoriteIndex; bind(mTimeCondition, mZenConditions.getChildAt(TIME_CONDITION_INDEX)); getConditionTagAt(TIME_CONDITION_INDEX).rb.setChecked(true); @@ -430,7 +434,8 @@ public class ZenModePanel extends LinearLayout { } tag.condition = condition; tag.rb.setEnabled(enabled); - if (sameConditionId(mSessionExitCondition, tag.condition)) { + if (mSessionExitCondition != null + && sameConditionId(mSessionExitCondition, tag.condition)) { tag.rb.setChecked(true); } tag.rb.setOnCheckedChangeListener(new OnCheckedChangeListener() { @@ -450,16 +455,32 @@ public class ZenModePanel extends LinearLayout { } }); - if (tag.title == null) { - tag.title = (TextView) row.findViewById(android.R.id.title); + if (tag.lines == null) { + tag.lines = row.findViewById(android.R.id.content); } + if (tag.line1 == null) { + tag.line1 = (TextView) row.findViewById(android.R.id.text1); + } + if (tag.line2 == null) { + tag.line2 = (TextView) row.findViewById(android.R.id.text2); + } + final String line1, line2; if (condition == null) { - tag.title.setText(mContext.getString(com.android.internal.R.string.zen_mode_forever)); + line1 = mContext.getString(com.android.internal.R.string.zen_mode_forever); + line2 = null; + } else { + line1 = !TextUtils.isEmpty(condition.line1) ? condition.line1 : condition.summary; + line2 = condition.line2; + } + tag.line1.setText(line1); + if (TextUtils.isEmpty(line2)) { + tag.line2.setVisibility(GONE); } else { - tag.title.setText(condition.summary); + tag.line2.setVisibility(VISIBLE); + tag.line2.setText(line2); } - tag.title.setEnabled(enabled); - tag.title.setAlpha(enabled ? 1 : .4f); + tag.lines.setEnabled(enabled); + tag.lines.setAlpha(enabled ? 1 : .4f); final ImageView button1 = (ImageView) row.findViewById(android.R.id.button1); button1.setOnClickListener(new OnClickListener() { @@ -476,7 +497,7 @@ public class ZenModePanel extends LinearLayout { onClickTimeButton(row, tag, true /*up*/); } }); - tag.title.setOnClickListener(new OnClickListener() { + tag.lines.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { tag.rb.setChecked(true); @@ -491,7 +512,8 @@ public class ZenModePanel extends LinearLayout { } else { final long span = time - System.currentTimeMillis(); button1.setEnabled(span > MIN_BUCKET_MINUTES * MINUTES_MS); - final Condition maxCondition = ZenModeConfig.toTimeCondition(MAX_BUCKET_MINUTES); + final Condition maxCondition = ZenModeConfig.toTimeCondition(mContext, + MAX_BUCKET_MINUTES); button2.setEnabled(!Objects.equals(condition.summary, maxCondition.summary)); } @@ -504,7 +526,7 @@ public class ZenModePanel extends LinearLayout { // wire up interaction callbacks for newly-added condition rows if (convertView == null) { Interaction.register(tag.rb, mInteractionCallback); - Interaction.register(tag.title, mInteractionCallback); + Interaction.register(tag.lines, mInteractionCallback); Interaction.register(button1, mInteractionCallback); Interaction.register(button2, mInteractionCallback); } @@ -524,7 +546,7 @@ public class ZenModePanel extends LinearLayout { return; } announceForAccessibility(mContext.getString(R.string.zen_mode_and_condition, modeText, - tag.title.getText())); + tag.line1.getText())); } private void onClickTimeButton(View row, ConditionTag tag, boolean up) { @@ -541,18 +563,21 @@ public class ZenModePanel extends LinearLayout { final long bucketTime = now + bucketMinutes * MINUTES_MS; if (up && bucketTime > time || !up && bucketTime < time) { mBucketIndex = j; - newCondition = ZenModeConfig.toTimeCondition(bucketTime, bucketMinutes); + newCondition = ZenModeConfig.toTimeCondition(mContext, + bucketTime, bucketMinutes, now); break; } } if (newCondition == null) { mBucketIndex = DEFAULT_BUCKET_INDEX; - newCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]); + newCondition = ZenModeConfig.toTimeCondition(mContext, + MINUTE_BUCKETS[mBucketIndex]); } } else { // on a known index, simply increment or decrement mBucketIndex = Math.max(0, Math.min(N - 1, mBucketIndex + (up ? 1 : -1))); - newCondition = ZenModeConfig.toTimeCondition(MINUTE_BUCKETS[mBucketIndex]); + newCondition = ZenModeConfig.toTimeCondition(mContext, + MINUTE_BUCKETS[mBucketIndex]); } mTimeCondition = newCondition; bind(mTimeCondition, row); @@ -639,7 +664,9 @@ public class ZenModePanel extends LinearLayout { // used as the view tag on condition rows private static class ConditionTag { RadioButton rb; - TextView title; + View lines; + TextView line1; + TextView line2; Condition condition; } @@ -690,7 +717,7 @@ public class ZenModePanel extends LinearLayout { } private SharedPreferences prefs() { - return mContext.getSharedPreferences(ZenModePanel.class.getSimpleName(), 0); + return mContext.getSharedPreferences(mContext.getPackageName(), 0); } private void updateMinuteIndex() { diff --git a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java index 8c8209f..fc65793 100644 --- a/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java +++ b/policy/src/com/android/internal/policy/impl/GlobalKeyManager.java @@ -73,6 +73,7 @@ final class GlobalKeyManager { if (component != null) { Intent intent = new Intent(Intent.ACTION_GLOBAL_BUTTON) .setComponent(component) + .setFlags(Intent.FLAG_RECEIVER_FOREGROUND) .putExtra(Intent.EXTRA_KEY_EVENT, event); context.sendBroadcastAsUser(intent, UserHandle.CURRENT, null); return true; diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 9c81f0a..1ed61fd 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -3342,9 +3342,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { final boolean noActionBar = !hasFeature(FEATURE_ACTION_BAR) || hasFeature(FEATURE_NO_TITLE); if (targetPreHoneycomb || (targetPreIcs && targetHcNeedsOptions && noActionBar)) { - addFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY); + setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE); } else { - clearFlags(WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY); + setNeedsMenuKey(WindowManager.LayoutParams.NEEDS_MENU_SET_FALSE); } // Non-floating windows on high end devices must put up decor beneath the system bars and diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java index 2699d13..04e2fd1 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java @@ -503,6 +503,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { // What we do when the user double-taps on home private int mDoubleTapOnHomeBehavior; + // Allowed theater mode wake actions + private boolean mAllowTheaterModeWakeFromKey; + private boolean mAllowTheaterModeWakeFromPowerKey; + private boolean mAllowTheaterModeWakeFromMotion; + private boolean mAllowTheaterModeWakeFromCameraLens; + private boolean mAllowTheaterModeWakeFromLidSwitch; + private boolean mAllowTheaterModeWakeFromWakeGesture; + // Screenshot trigger states // Time to volume and power must be pressed within this interval of each other. private static final long SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS = 150; @@ -656,7 +664,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { synchronized (mLock) { if (shouldEnableWakeGestureLp()) { performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false); - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture); } } } @@ -1022,6 +1030,21 @@ public class PhoneWindowManager implements WindowManagerPolicy { com.android.internal.R.bool.config_lidControlsSleep); mTranslucentDecorEnabled = mContext.getResources().getBoolean( com.android.internal.R.bool.config_enableTranslucentDecor); + + mAllowTheaterModeWakeFromKey = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromKey); + mAllowTheaterModeWakeFromPowerKey = mAllowTheaterModeWakeFromKey + || mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromPowerKey); + mAllowTheaterModeWakeFromMotion = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromMotion); + mAllowTheaterModeWakeFromCameraLens = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromCameraLens); + mAllowTheaterModeWakeFromLidSwitch = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromLidSwitch); + mAllowTheaterModeWakeFromWakeGesture = mContext.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromGesture); + readConfigurationDependentBehaviors(); mAccessibilityManager = (AccessibilityManager) context.getSystemService( @@ -1408,6 +1431,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_WALLPAPER: case TYPE_PRIVATE_PRESENTATION: case TYPE_VOICE_INTERACTION: + case TYPE_ACCESSIBILITY_OVERLAY: // The window manager will check these. break; case TYPE_PHONE: @@ -1461,7 +1485,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_PHONE: case TYPE_POINTER: case TYPE_PRIORITY_PHONE: - case TYPE_RECENTS_OVERLAY: case TYPE_SEARCH_BAR: case TYPE_STATUS_BAR: case TYPE_STATUS_BAR_PANEL: @@ -1580,7 +1603,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { case TYPE_VOICE_INTERACTION: // voice interaction layer is almost immediately above apps. return 5; - case TYPE_RECENTS_OVERLAY: case TYPE_SYSTEM_DIALOG: return 6; case TYPE_TOAST: @@ -1639,15 +1661,18 @@ public class PhoneWindowManager implements WindowManagerPolicy { // the drag layer: input for drag-and-drop is associated with this window, // which sits above all other focusable windows return 25; - case TYPE_SECURE_SYSTEM_OVERLAY: + case TYPE_ACCESSIBILITY_OVERLAY: + // overlay put by accessibility services to intercept user interaction return 26; - case TYPE_BOOT_PROGRESS: + case TYPE_SECURE_SYSTEM_OVERLAY: return 27; + case TYPE_BOOT_PROGRESS: + return 28; case TYPE_POINTER: // the (mouse) pointer layer - return 28; - case TYPE_HIDDEN_NAV_CONSUMER: return 29; + case TYPE_HIDDEN_NAV_CONSUMER: + return 30; } Log.e(TAG, "Unknown window type: " + type); return 2; @@ -1951,7 +1976,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { } mKeyguardScrim = win; break; - } return WindowManagerGlobal.ADD_OKAY; } @@ -2208,15 +2232,6 @@ public class PhoneWindowManager implements WindowManagerPolicy { return -1; } - // If an incoming call is ringing, HOME is totally disabled. - // (The user is already on the InCallUI at this point, - // and his ONLY options are to answer or reject the call.) - TelecomManager telecomManager = getTelecommService(); - if (telecomManager != null && telecomManager.isRinging()) { - Log.i(TAG, "Ignoring HOME; there's a ringing incoming call."); - return -1; - } - // Delay handling home if a double-tap is possible. if (mDoubleTapOnHomeBehavior != DOUBLE_TAP_HOME_NOTHING) { mHandler.removeCallbacks(mHomeDoubleTapTimeoutRunnable); // just in case @@ -3192,10 +3207,15 @@ public class PhoneWindowManager implements WindowManagerPolicy { // whether it is taking care of insetting its content. If not, // we need to use the parent's content frame so that the entire // window is positioned within that content. Otherwise we can use - // the display frame and let the attached window take care of + // the overscan frame and let the attached window take care of // positioning its content appropriately. if (adjust != SOFT_INPUT_ADJUST_RESIZE) { - cf.set(attached.getOverscanFrameLw()); + // Set the content frame of the attached window to the parent's decor frame + // (same as content frame when IME isn't present) if specifically requested by + // setting {@link WindowManager.LayoutParams#FLAG_LAYOUT_ATTACHED_IN_DECOR} flag. + // Otherwise, use the overscan frame. + cf.set((fl & FLAG_LAYOUT_ATTACHED_IN_DECOR) != 0 + ? attached.getContentFrameLw() : attached.getOverscanFrameLw()); } else { // If the window is resizing, then we want to base the content // frame on our attached content frame to resize... however, @@ -4071,7 +4091,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { updateRotation(true); if (lidOpen) { - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch); } else if (!mLidControlsSleep) { mPowerManager.userActivity(SystemClock.uptimeMillis(), false); } @@ -4093,7 +4113,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { } else { intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA); } - mPowerManager.wakeUp(whenNanos / 1000000); + wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens); mContext.startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF); } mCameraLensCoverState = lensCoverState; @@ -4271,7 +4291,8 @@ public class PhoneWindowManager implements WindowManagerPolicy { // key processing. if (mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) { if (isWakeKey) { - mPowerManager.wakeUp(event.getEventTime()); + wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER + ? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey); } return result; } @@ -4520,8 +4541,10 @@ public class PhoneWindowManager implements WindowManagerPolicy { } if (isWakeKey) { - mPowerManager.wakeUp(event.getEventTime()); + wakeUp(event.getEventTime(), keyCode == KeyEvent.KEYCODE_POWER + ? mAllowTheaterModeWakeFromPowerKey : mAllowTheaterModeWakeFromKey); } + return result; } @@ -4564,7 +4587,7 @@ public class PhoneWindowManager implements WindowManagerPolicy { @Override public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) { if ((policyFlags & FLAG_WAKE) != 0) { - mPowerManager.wakeUp(whenNanos / 1000000); + wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion); return 0; } if (shouldDispatchInputWhenNonInteractive()) { @@ -4742,6 +4765,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { } } + private void wakeUp(long wakeTime, boolean wakeInTheaterMode) { + if (!wakeInTheaterMode && isTheaterModeEnabled()) { + return; + } + + mPowerManager.wakeUp(wakeTime); + } + // Called on the PowerManager's Notifier thread. @Override public void wakingUp() { @@ -5620,6 +5651,11 @@ public class PhoneWindowManager implements WindowManagerPolicy { ringTone.play(); } + private boolean isTheaterModeEnabled() { + return Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0) == 1; + } + private boolean isGlobalAccessibilityGestureEnabled() { return Settings.Global.getInt(mContext.getContentResolver(), Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1; diff --git a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java b/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java deleted file mode 100644 index bc55ed1..0000000 --- a/policy/src/com/android/internal/policy/impl/RecentApplicationsDialog.java +++ /dev/null @@ -1,347 +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.internal.policy.impl; - -import android.app.ActivityManager; -import android.app.Dialog; -import android.app.StatusBarManager; -import android.content.ActivityNotFoundException; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.pm.ActivityInfo; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.os.Handler; -import android.util.Log; -import android.view.KeyEvent; -import android.view.SoundEffectConstants; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.view.View.OnClickListener; -import android.widget.TextView; - -import java.util.List; - -public class RecentApplicationsDialog extends Dialog implements OnClickListener { - // Elements for debugging support -// private static final String LOG_TAG = "RecentApplicationsDialog"; - private static final boolean DBG_FORCE_EMPTY_LIST = false; - - static private StatusBarManager sStatusBar; - - private static final int NUM_BUTTONS = 8; - private static final int MAX_RECENT_TASKS = NUM_BUTTONS * 2; // allow for some discards - - final TextView[] mIcons = new TextView[NUM_BUTTONS]; - View mNoAppsText; - IntentFilter mBroadcastIntentFilter = new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS); - - class RecentTag { - ActivityManager.RecentTaskInfo info; - Intent intent; - } - - Handler mHandler = new Handler(); - Runnable mCleanup = new Runnable() { - public void run() { - // dump extra memory we're hanging on to - for (TextView icon: mIcons) { - icon.setCompoundDrawables(null, null, null, null); - icon.setTag(null); - } - } - }; - - public RecentApplicationsDialog(Context context) { - super(context, com.android.internal.R.style.Theme_Dialog_RecentApplications); - - } - - /** - * We create the recent applications dialog just once, and it stays around (hidden) - * until activated by the user. - * - * @see PhoneWindowManager#showRecentAppsDialog - */ - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Context context = getContext(); - - if (sStatusBar == null) { - sStatusBar = (StatusBarManager)context.getSystemService(Context.STATUS_BAR_SERVICE); - } - - Window window = getWindow(); - window.requestFeature(Window.FEATURE_NO_TITLE); - window.setType(WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY); - window.setFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM, - WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM); - window.setTitle("Recents"); - - setContentView(com.android.internal.R.layout.recent_apps_dialog); - - final WindowManager.LayoutParams params = window.getAttributes(); - params.width = WindowManager.LayoutParams.MATCH_PARENT; - params.height = WindowManager.LayoutParams.MATCH_PARENT; - window.setAttributes(params); - window.setFlags(0, WindowManager.LayoutParams.FLAG_DIM_BEHIND); - - mIcons[0] = (TextView)findViewById(com.android.internal.R.id.button0); - mIcons[1] = (TextView)findViewById(com.android.internal.R.id.button1); - mIcons[2] = (TextView)findViewById(com.android.internal.R.id.button2); - mIcons[3] = (TextView)findViewById(com.android.internal.R.id.button3); - mIcons[4] = (TextView)findViewById(com.android.internal.R.id.button4); - mIcons[5] = (TextView)findViewById(com.android.internal.R.id.button5); - mIcons[6] = (TextView)findViewById(com.android.internal.R.id.button6); - mIcons[7] = (TextView)findViewById(com.android.internal.R.id.button7); - mNoAppsText = findViewById(com.android.internal.R.id.no_applications_message); - - for (TextView b: mIcons) { - b.setOnClickListener(this); - } - } - - @Override - public boolean onKeyDown(int keyCode, KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_TAB) { - // Ignore all meta keys other than SHIFT. The app switch key could be a - // fallback action chorded with ALT, META or even CTRL depending on the key map. - // DPad navigation is handled by the ViewRoot elsewhere. - final boolean backward = event.isShiftPressed(); - final int numIcons = mIcons.length; - int numButtons = 0; - while (numButtons < numIcons && mIcons[numButtons].getVisibility() == View.VISIBLE) { - numButtons += 1; - } - if (numButtons != 0) { - int nextFocus = backward ? numButtons - 1 : 0; - for (int i = 0; i < numButtons; i++) { - if (mIcons[i].hasFocus()) { - if (backward) { - nextFocus = (i + numButtons - 1) % numButtons; - } else { - nextFocus = (i + 1) % numButtons; - } - break; - } - } - final int direction = backward ? View.FOCUS_BACKWARD : View.FOCUS_FORWARD; - if (mIcons[nextFocus].requestFocus(direction)) { - mIcons[nextFocus].playSoundEffect( - SoundEffectConstants.getContantForFocusDirection(direction)); - } - } - - // The dialog always handles the key to prevent the ViewRoot from - // performing the default navigation itself. - return true; - } - - return super.onKeyDown(keyCode, event); - } - - /** - * Dismiss the dialog and switch to the selected application. - */ - public void dismissAndSwitch() { - final int numIcons = mIcons.length; - RecentTag tag = null; - for (int i = 0; i < numIcons; i++) { - if (mIcons[i].getVisibility() != View.VISIBLE) { - break; - } - if (i == 0 || mIcons[i].hasFocus()) { - tag = (RecentTag) mIcons[i].getTag(); - if (mIcons[i].hasFocus()) { - break; - } - } - } - if (tag != null) { - switchTo(tag); - } - dismiss(); - } - - /** - * Handler for user clicks. If a button was clicked, launch the corresponding activity. - */ - public void onClick(View v) { - for (TextView b: mIcons) { - if (b == v) { - RecentTag tag = (RecentTag)b.getTag(); - switchTo(tag); - break; - } - } - dismiss(); - } - - private void switchTo(RecentTag tag) { - if (tag.info.id >= 0) { - // This is an active task; it should just go to the foreground. - final ActivityManager am = (ActivityManager) - getContext().getSystemService(Context.ACTIVITY_SERVICE); - am.moveTaskToFront(tag.info.id, ActivityManager.MOVE_TASK_WITH_HOME); - } else if (tag.intent != null) { - tag.intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY - | Intent.FLAG_ACTIVITY_TASK_ON_HOME); - try { - getContext().startActivity(tag.intent); - } catch (ActivityNotFoundException e) { - Log.w("Recent", "Unable to launch recent task", e); - } - } - } - - /** - * Set up and show the recent activities dialog. - */ - @Override - public void onStart() { - super.onStart(); - reloadButtons(); - if (sStatusBar != null) { - sStatusBar.disable(StatusBarManager.DISABLE_EXPAND); - } - - // receive broadcasts - getContext().registerReceiver(mBroadcastReceiver, mBroadcastIntentFilter); - - mHandler.removeCallbacks(mCleanup); - } - - /** - * Dismiss the recent activities dialog. - */ - @Override - public void onStop() { - super.onStop(); - - if (sStatusBar != null) { - sStatusBar.disable(StatusBarManager.DISABLE_NONE); - } - - // stop receiving broadcasts - getContext().unregisterReceiver(mBroadcastReceiver); - - mHandler.postDelayed(mCleanup, 100); - } - - /** - * Reload the 6 buttons with recent activities - */ - private void reloadButtons() { - - final Context context = getContext(); - final PackageManager pm = context.getPackageManager(); - final ActivityManager am = (ActivityManager) - context.getSystemService(Context.ACTIVITY_SERVICE); - final List<ActivityManager.RecentTaskInfo> recentTasks = - am.getRecentTasks(MAX_RECENT_TASKS, ActivityManager.RECENT_IGNORE_UNAVAILABLE); - - ActivityInfo homeInfo = - new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME) - .resolveActivityInfo(pm, 0); - - IconUtilities iconUtilities = new IconUtilities(getContext()); - - // Performance note: Our android performance guide says to prefer Iterator when - // using a List class, but because we know that getRecentTasks() always returns - // an ArrayList<>, we'll use a simple index instead. - int index = 0; - int numTasks = recentTasks.size(); - for (int i = 0; i < numTasks && (index < NUM_BUTTONS); ++i) { - final ActivityManager.RecentTaskInfo info = recentTasks.get(i); - - // for debug purposes only, disallow first result to create empty lists - if (DBG_FORCE_EMPTY_LIST && (i == 0)) continue; - - Intent intent = new Intent(info.baseIntent); - if (info.origActivity != null) { - intent.setComponent(info.origActivity); - } - - // Skip the current home activity. - if (homeInfo != null) { - if (homeInfo.packageName.equals( - intent.getComponent().getPackageName()) - && homeInfo.name.equals( - intent.getComponent().getClassName())) { - continue; - } - } - - intent.setFlags((intent.getFlags()&~Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) - | Intent.FLAG_ACTIVITY_NEW_TASK); - final ResolveInfo resolveInfo = pm.resolveActivity(intent, 0); - if (resolveInfo != null) { - final ActivityInfo activityInfo = resolveInfo.activityInfo; - final String title = activityInfo.loadLabel(pm).toString(); - Drawable icon = activityInfo.loadIcon(pm); - - if (title != null && title.length() > 0 && icon != null) { - final TextView tv = mIcons[index]; - tv.setText(title); - icon = iconUtilities.createIconDrawable(icon); - tv.setCompoundDrawables(null, icon, null, null); - RecentTag tag = new RecentTag(); - tag.info = info; - tag.intent = intent; - tv.setTag(tag); - tv.setVisibility(View.VISIBLE); - tv.setPressed(false); - tv.clearFocus(); - ++index; - } - } - } - - // handle the case of "no icons to show" - mNoAppsText.setVisibility((index == 0) ? View.VISIBLE : View.GONE); - - // hide the rest - for (; index < NUM_BUTTONS; ++index) { - mIcons[index].setVisibility(View.GONE); - } - } - - /** - * This is the listener for the ACTION_CLOSE_SYSTEM_DIALOGS intent. It's an indication that - * we should close ourselves immediately, in order to allow a higher-priority UI to take over - * (e.g. phone call received). - */ - private BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) { - String reason = intent.getStringExtra(PhoneWindowManager.SYSTEM_DIALOG_REASON_KEY); - if (! PhoneWindowManager.SYSTEM_DIALOG_REASON_RECENT_APPS.equals(reason)) { - dismiss(); - } - } - } - }; -} diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index bfbf0ac..2781890 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1040,7 +1040,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private void addServiceLocked(Service service, UserState userState) { try { - service.linkToOwnDeathLocked(); + service.onAdded(); userState.mBoundServices.add(service); userState.mComponentNameToServiceMap.put(service.mComponentName, service); } catch (RemoteException re) { @@ -1056,7 +1056,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { private void removeServiceLocked(Service service, UserState userState) { userState.mBoundServices.remove(service); userState.mComponentNameToServiceMap.remove(service.mComponentName); - service.unlinkToOwnDeathLocked(); + service.onRemoved(); } /** @@ -1931,6 +1931,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { final ResolveInfo mResolveInfo; + final IBinder mOverlayWindowToken = new Binder(); + // the events pending events to be dispatched to this service final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>(); @@ -2112,7 +2114,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { userState.mBindingServices.remove(mComponentName); mWasConnectedAndDied = false; try { - mServiceInterface.setConnection(this, mId); + mServiceInterface.init(this, mId, mOverlayWindowToken); onUserStateChangedLocked(userState); } catch (RemoteException re) { Slog.w(LOG_TAG, "Error while setting connection for service: " @@ -2602,6 +2604,27 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { /* do nothing - #binderDied takes care */ } + public void onAdded() throws RemoteException { + linkToOwnDeathLocked(); + final long identity = Binder.clearCallingIdentity(); + try { + mWindowManagerService.addWindowToken(mOverlayWindowToken, + WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + public void onRemoved() { + final long identity = Binder.clearCallingIdentity(); + try { + mWindowManagerService.removeWindowToken(mOverlayWindowToken, true); + } finally { + Binder.restoreCallingIdentity(identity); + } + unlinkToOwnDeathLocked(); + } + public void linkToOwnDeathLocked() throws RemoteException { mService.linkToDeath(this, 0); } @@ -2614,7 +2637,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { try { // Clear the proxy in the other process so this // IAccessibilityServiceConnection can be garbage collected. - mServiceInterface.setConnection(null, mId); + mServiceInterface.init(null, mId, null); } catch (RemoteException re) { /* ignore */ } @@ -3156,7 +3179,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { case WindowManager.LayoutParams.TYPE_STATUS_BAR: case WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL: case WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL: - case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT: case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG: @@ -3165,6 +3187,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { return AccessibilityWindowInfo.TYPE_SYSTEM; } + case WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY: { + return AccessibilityWindowInfo.TYPE_ACCESSIBILITY_OVERLAY; + } + default: { return -1; } diff --git a/services/core/java/com/android/server/DockObserver.java b/services/core/java/com/android/server/DockObserver.java index d05c280..41ce25d 100644 --- a/services/core/java/com/android/server/DockObserver.java +++ b/services/core/java/com/android/server/DockObserver.java @@ -65,11 +65,15 @@ final class DockObserver extends SystemService { private boolean mUpdatesStopped; + private final boolean mAllowTheaterModeWakeFromDock; + public DockObserver(Context context) { super(context); mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE); mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); + mAllowTheaterModeWakeFromDock = context.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromDock); init(); // set initial status @@ -126,8 +130,12 @@ final class DockObserver extends SystemService { if (newState != mReportedDockState) { mReportedDockState = newState; if (mSystemReady) { - // Wake up immediately when docked or undocked. - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + // Wake up immediately when docked or undocked except in theater mode. + if (mAllowTheaterModeWakeFromDock + || Settings.Global.getInt(getContext().getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0) == 0) { + mPowerManager.wakeUp(SystemClock.uptimeMillis()); + } updateLocked(); } } diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags index 99a1254..8417ccc 100644 --- a/services/core/java/com/android/server/EventLogTags.logtags +++ b/services/core/java/com/android/server/EventLogTags.logtags @@ -52,7 +52,7 @@ option java_package com.android.server # NotificationManagerService.java # --------------------------- # when a NotificationManager.notify is called -2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3) +2750 notification_enqueue (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(notification|3),(update|1) # when someone tries to cancel a notification, the notification manager sometimes # calls this with flags too 2751 notification_cancel (uid|1|5),(pid|1|5),(pkg|3),(id|1|5),(tag|3),(userid|1|5),(required_flags|1),(forbidden_flags|1),(reason|1|5),(listener|3) @@ -69,6 +69,10 @@ option java_package com.android.server 27511 notification_expansion (key|3),(user_action|1),(expanded|1) # when a notification has been clicked 27520 notification_clicked (key|3) +# when a notification action button has been clicked +27521 notification_action_clicked (key|3),(action_index|1) +# when a notification has been canceled +27530 notification_canceled (key|3),(reason|1) # --------------------------- # Watchdog.java @@ -165,6 +169,12 @@ option java_package com.android.server # --------------------------- +# WallpaperManagerService.java +# --------------------------- +33000 wp_wallpaper_crashed (component|3) + + +# --------------------------- # ConnectivityService.java # --------------------------- # Connectivity state changed diff --git a/services/core/java/com/android/server/IntentResolver.java b/services/core/java/com/android/server/IntentResolver.java index 07cc864..387eabc 100644 --- a/services/core/java/com/android/server/IntentResolver.java +++ b/services/core/java/com/android/server/IntentResolver.java @@ -21,7 +21,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -30,6 +29,7 @@ import java.util.Set; import android.net.Uri; import android.util.FastImmutableArraySet; import android.util.ArrayMap; +import android.util.ArraySet; import android.util.Log; import android.util.PrintWriterPrinter; import android.util.Slog; @@ -736,7 +736,7 @@ public abstract class IntentResolver<F extends IntentFilter, R extends Object> { /** * All filters that have been registered. */ - private final HashSet<F> mFilters = new HashSet<F>(); + private final ArraySet<F> mFilters = new ArraySet<F>(); /** * All of the MIME types that have been registered, such as "image/jpeg", diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index 28a6917..d9c96e4 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -1796,9 +1796,6 @@ public class LocationManagerService extends ILocationManager.Stub { @Override public boolean addGpsStatusListener(IGpsStatusListener listener, String packageName) { - if (mGpsStatusProvider == null) { - return false; - } int allowedResolutionLevel = getCallerAllowedResolutionLevel(); checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel, LocationManager.GPS_PROVIDER); @@ -1813,6 +1810,10 @@ public class LocationManagerService extends ILocationManager.Stub { Binder.restoreCallingIdentity(ident); } + if (mGpsStatusProvider == null) { + return false; + } + try { mGpsStatusProvider.addGpsStatusListener(listener); } catch (RemoteException e) { diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java index 926235f..9596b57 100644 --- a/services/core/java/com/android/server/MmsServiceBroker.java +++ b/services/core/java/com/android/server/MmsServiceBroker.java @@ -219,7 +219,7 @@ public class MmsServiceBroker extends SystemService { // Service API calls implementation, proxied to the real MmsService in "com.android.mms.service" private final class BinderService extends IMms.Stub { @Override - public void sendMessage(long subId, String callingPkg, Uri contentUri, + public void sendMessage(int subId, String callingPkg, Uri contentUri, String locationUrl, Bundle configOverrides, PendingIntent sentIntent) throws RemoteException { mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message"); @@ -232,7 +232,7 @@ public class MmsServiceBroker extends SystemService { } @Override - public void downloadMessage(long subId, String callingPkg, String locationUrl, + public void downloadMessage(int subId, String callingPkg, String locationUrl, Uri contentUri, Bundle configOverrides, PendingIntent downloadedIntent) throws RemoteException { mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS, @@ -259,7 +259,7 @@ public class MmsServiceBroker extends SystemService { } @Override - public Bundle getCarrierConfigValues(long subId) throws RemoteException { + public Bundle getCarrierConfigValues(int subId) throws RemoteException { return getServiceGuarded().getCarrierConfigValues(subId); } @@ -360,7 +360,7 @@ public class MmsServiceBroker extends SystemService { } @Override - public void sendStoredMessage(long subId, String callingPkg, Uri messageUri, + public void sendStoredMessage(int subId, String callingPkg, Uri messageUri, Bundle configOverrides, PendingIntent sentIntent) throws RemoteException { mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send stored MMS message"); diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java index 24d81a0..e400fb6 100644 --- a/services/core/java/com/android/server/MountService.java +++ b/services/core/java/com/android/server/MountService.java @@ -826,7 +826,9 @@ class MountService extends IMountService.Stub // On an encrypted device we can't see system properties yet, so pull // the system locale out of the mount service. - copyLocaleFromMountService(); + if ("".equals(SystemProperties.get("vold.encrypt_progress"))) { + copyLocaleFromMountService(); + } // Let package manager load internal ASECs. mPms.scanAvailableAsecs(); diff --git a/services/core/java/com/android/server/SystemConfig.java b/services/core/java/com/android/server/SystemConfig.java index cf2a49f..f4fb519 100644 --- a/services/core/java/com/android/server/SystemConfig.java +++ b/services/core/java/com/android/server/SystemConfig.java @@ -32,8 +32,6 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; -import java.util.HashMap; -import java.util.HashSet; import static com.android.internal.util.ArrayUtils.appendInt; @@ -50,7 +48,7 @@ public class SystemConfig { // These are the built-in uid -> permission mappings that were read from the // system configuration files. - final SparseArray<HashSet<String>> mSystemPermissions = new SparseArray<>(); + final SparseArray<ArraySet<String>> mSystemPermissions = new SparseArray<>(); // These are the built-in shared libraries that were read from the // system configuration files. Keys are the library names; strings are the @@ -59,7 +57,7 @@ public class SystemConfig { // These are the features this devices supports that were read from the // system configuration files. - final HashMap<String, FeatureInfo> mAvailableFeatures = new HashMap<>(); + final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>(); public static final class PermissionEntry { public final String name; @@ -94,7 +92,7 @@ public class SystemConfig { return mGlobalGids; } - public SparseArray<HashSet<String>> getSystemPermissions() { + public SparseArray<ArraySet<String>> getSystemPermissions() { return mSystemPermissions; } @@ -102,7 +100,7 @@ public class SystemConfig { return mSharedLibraries; } - public HashMap<String, FeatureInfo> getAvailableFeatures() { + public ArrayMap<String, FeatureInfo> getAvailableFeatures() { return mAvailableFeatures; } @@ -252,9 +250,9 @@ public class SystemConfig { continue; } perm = perm.intern(); - HashSet<String> perms = mSystemPermissions.get(uid); + ArraySet<String> perms = mSystemPermissions.get(uid); if (perms == null) { - perms = new HashSet<String>(); + perms = new ArraySet<String>(); mSystemPermissions.put(uid, perms); } perms.add(perm); diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java index fe005ec..fcc5339 100644 --- a/services/core/java/com/android/server/TelephonyRegistry.java +++ b/services/core/java/com/android/server/TelephonyRegistry.java @@ -72,7 +72,7 @@ import com.android.server.am.BatteryStatsService; * and 15973975 by saving the phoneId of the registrant and then using the * phoneId when deciding to to make a callback. This is necessary because * a subId changes from to a dummy value when a SIM is removed and thus won't - * compare properly. Because SubscriptionManager.getPhoneId(long subId) handles + * compare properly. Because SubscriptionManager.getPhoneId(int subId) handles * the dummy value conversion we properly do the callbacks. * * Eventually we may want to remove the notion of dummy value but for now this @@ -95,7 +95,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { int events; - long subId; + int subId; int phoneId; @@ -154,6 +154,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private VoLteServiceState mVoLteServiceState = new VoLteServiceState(); + private int mDefaultSubId = SubscriptionManager.INVALID_SUB_ID; + + private int mDefaultPhoneId = SubscriptionManager.INVALID_PHONE_ID; + private DataConnectionRealTimeInfo mDcRtInfo = new DataConnectionRealTimeInfo(); private int mRingingCallState = PreciseCallState.PRECISE_CALL_STATE_IDLE; @@ -195,8 +199,28 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } break; } - case MSG_UPDATE_DEFAULT_SUB: {// do nothing - if (VDBG) log(TAG + "MSG_UPDATE_DEFAULT_SUB"); + case MSG_UPDATE_DEFAULT_SUB: { + int newDefaultPhoneId = msg.arg1; + int newDefaultSubId = (Integer)(msg.obj); + if (VDBG) { + log("MSG_UPDATE_DEFAULT_SUB:current mDefaultSubId=" + mDefaultSubId + + " current mDefaultPhoneId=" + mDefaultPhoneId + " newDefaultSubId= " + + newDefaultSubId + " newDefaultPhoneId=" + newDefaultPhoneId); + } + + //Due to possible risk condition,(notify call back using the new + //defaultSubId comes before new defaultSubId update) we need to recall all + //possible missed notify callback + synchronized (mRecords) { + for (Record r : mRecords) { + if(r.subId == SubscriptionManager.DEFAULT_SUB_ID) { + checkPossibleMissNotify(r, newDefaultPhoneId); + } + } + handleRemoveListLocked(); + } + mDefaultSubId = newDefaultSubId; + mDefaultPhoneId = newDefaultPhoneId; } } } @@ -212,10 +236,21 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { if (DBG) log("onReceive: userHandle=" + userHandle); mHandler.sendMessage(mHandler.obtainMessage(MSG_USER_SWITCHED, userHandle, 0)); } else if (action.equals(TelephonyIntents.ACTION_DEFAULT_SUBSCRIPTION_CHANGED)) { + Integer newDefaultSubIdObj = new Integer(intent.getIntExtra( + PhoneConstants.SUBSCRIPTION_KEY, SubscriptionManager.getDefaultSubId())); + int newDefaultPhoneId = intent.getIntExtra(PhoneConstants.SLOT_KEY, + SubscriptionManager.getPhoneId(mDefaultSubId)); if (DBG) { - log(TAG + "onReceive: ACTION_DEFAULT_SUBSCRIPTION_CHANGED"); + log("onReceive:current mDefaultSubId=" + mDefaultSubId + + " current mDefaultPhoneId=" + mDefaultPhoneId + " newDefaultSubId= " + + newDefaultSubIdObj + " newDefaultPhoneId=" + newDefaultPhoneId); + } + + if(validatePhoneId(newDefaultPhoneId) && (newDefaultSubIdObj.equals(mDefaultSubId) + || (newDefaultPhoneId != mDefaultPhoneId))) { + mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, + newDefaultPhoneId, 0, newDefaultSubIdObj)); } - mHandler.sendMessage(mHandler.obtainMessage(MSG_UPDATE_DEFAULT_SUB, 0, 0)); } } }; @@ -297,13 +332,13 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override - public void listenForSubscriber(long subId, String pkgForDebug, IPhoneStateListener callback, + public void listenForSubscriber(int subId, String pkgForDebug, IPhoneStateListener callback, int events, boolean notifyNow) { listen(pkgForDebug, callback, events, notifyNow, subId); } private void listen(String pkgForDebug, IPhoneStateListener callback, int events, - boolean notifyNow, long subId) { + boolean notifyNow, int subId) { int callerUid = UserHandle.getCallingUserId(); int myUid = UserHandle.myUserId(); if (VDBG) { @@ -311,10 +346,10 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + " notifyNow=" + notifyNow + " subId=" + subId + " myUid=" + myUid + " callerUid=" + callerUid); } - if (events != 0) { + + if (events != PhoneStateListener.LISTEN_NONE) { /* Checks permission and throws Security exception */ checkListenerPermission(events); - synchronized (mRecords) { // register Record r = null; @@ -329,26 +364,26 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } r = new Record(); r.binder = b; - r.callback = callback; - r.pkgForDebug = pkgForDebug; - r.callerUid = callerUid; - // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, - // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID - if (!SubscriptionManager.isValidSubId(subId)) { - r.subId = SubscriptionManager.DEFAULT_SUB_ID; - } else {//APP specify subID - r.subId = subId; - } - r.phoneId = SubscriptionManager.getPhoneId(r.subId); - mRecords.add(r); if (DBG) log("listen: add new record"); } + r.callback = callback; + r.pkgForDebug = pkgForDebug; + r.callerUid = callerUid; + // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID, + // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID + if (!SubscriptionManager.isValidSubId(subId)) { + r.subId = SubscriptionManager.DEFAULT_SUB_ID; + } else {//APP specify subID + r.subId = subId; + } + r.phoneId = SubscriptionManager.getPhoneId(r.subId); + int phoneId = r.phoneId; r.events = events; if (DBG) { - log("listen: r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId); + log("listen: Register r=" + r + " r.subId=" + r.subId + " phoneId=" + phoneId); } if (VDBG) toStringLogSSC("listen"); if (notifyNow && validatePhoneId(phoneId)) { @@ -468,6 +503,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } } else { + if(DBG) log("listen: Unregister"); remove(callback.asBinder()); } } @@ -509,7 +545,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { broadcastCallStateChanged(state, incomingNumber, SubscriptionManager.DEFAULT_SUB_ID); } - public void notifyCallStateForSubscriber(long subId, int state, String incomingNumber) { + public void notifyCallStateForSubscriber(int subId, int state, String incomingNumber) { if (!checkNotifyPermission("notifyCallState()")) { return; } @@ -539,7 +575,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { broadcastCallStateChanged(state, incomingNumber, subId); } - public void notifyServiceStateForPhoneId(int phoneId, long subId, ServiceState state) { + public void notifyServiceStateForPhoneId(int phoneId, int subId, ServiceState state) { if (!checkNotifyPermission("notifyServiceState()")){ return; } @@ -560,8 +596,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + " phoneId=" + phoneId + " state=" + state); } if (((r.events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) && - ((r.subId == subId) || - (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) { + subIdMatch(r.subId, subId)) { try { if (DBG) { log("notifyServiceStateForSubscriber: callback.onSSC r=" + r @@ -586,7 +621,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { notifySignalStrengthForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, signalStrength); } - public void notifySignalStrengthForSubscriber(long subId, SignalStrength signalStrength) { + public void notifySignalStrengthForSubscriber(int subId, SignalStrength signalStrength) { if (!checkNotifyPermission("notifySignalStrength()")) { return; } @@ -606,8 +641,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { + " phoneId=" + phoneId + " ss=" + signalStrength); } if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) && - ((r.subId == subId) || - (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) { + subIdMatch(r.subId, subId)) { try { if (DBG) { log("notifySignalStrengthForSubscriber: callback.onSsS r=" + r @@ -620,8 +654,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } if (((r.events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) && - ((r.subId == subId) || - (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) { + subIdMatch(r.subId, subId)){ try { int gsmSignalStrength = signalStrength.getGsmSignalStrength(); int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength); @@ -648,7 +681,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { notifyCellInfoForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cellInfo); } - public void notifyCellInfoForSubscriber(long subId, List<CellInfo> cellInfo) { + public void notifyCellInfoForSubscriber(int subId, List<CellInfo> cellInfo) { if (!checkNotifyPermission("notifyCellInfo()")) { return; } @@ -663,8 +696,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCellInfo.set(phoneId, cellInfo); for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO) && - ((r.subId == subId) || - (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) { + subIdMatch(r.subId, subId)) { try { if (DBG_LOC) { log("notifyCellInfo: mCellInfo=" + cellInfo + " r=" + r); @@ -706,7 +738,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } @Override - public void notifyMessageWaitingChangedForPhoneId(int phoneId, long subId, boolean mwi) { + public void notifyMessageWaitingChangedForPhoneId(int phoneId, int subId, boolean mwi) { if (!checkNotifyPermission("notifyMessageWaitingChanged()")) { return; } @@ -719,8 +751,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mMessageWaiting[phoneId] = mwi; for (Record r : mRecords) { if (((r.events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) && - ((r.subId == subId) || - (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) { + subIdMatch(r.subId, subId)) { try { r.callback.onMessageWaitingIndicatorChanged(mwi); } catch (RemoteException ex) { @@ -737,7 +768,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { notifyCallForwardingChangedForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cfi); } - public void notifyCallForwardingChangedForSubscriber(long subId, boolean cfi) { + public void notifyCallForwardingChangedForSubscriber(int subId, boolean cfi) { if (!checkNotifyPermission("notifyCallForwardingChanged()")) { return; } @@ -751,8 +782,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCallForwarding[phoneId] = cfi; for (Record r : mRecords) { if (((r.events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) && - ((r.subId == subId) || - (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) { + subIdMatch(r.subId, subId)) { try { r.callback.onCallForwardingIndicatorChanged(cfi); } catch (RemoteException ex) { @@ -769,7 +799,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { notifyDataActivityForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, state); } - public void notifyDataActivityForSubscriber(long subId, int state) { + public void notifyDataActivityForSubscriber(int subId, int state) { if (!checkNotifyPermission("notifyDataActivity()" )) { return; } @@ -797,7 +827,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { networkCapabilities, networkType, roaming); } - public void notifyDataConnectionForSubscriber(long subId, int state, + public void notifyDataConnectionForSubscriber(int subId, int state, boolean isDataConnectivityPossible, String reason, String apn, String apnType, LinkProperties linkProperties, NetworkCapabilities networkCapabilities, int networkType, boolean roaming) { @@ -849,8 +879,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } for (Record r : mRecords) { if (((r.events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) && - ((r.subId == subId) || - (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) { + subIdMatch(r.subId, subId)) { try { log("Notify data connection state changed on sub: " + subId); @@ -887,7 +916,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { reason, apnType); } - public void notifyDataConnectionFailedForSubscriber(long subId, + public void notifyDataConnectionFailedForSubscriber(int subId, String reason, String apnType) { if (!checkNotifyPermission("notifyDataConnectionFailed()")) { return; @@ -920,7 +949,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { notifyCellLocationForSubscriber(SubscriptionManager.DEFAULT_SUB_ID, cellLocation); } - public void notifyCellLocationForSubscriber(long subId, Bundle cellLocation) { + public void notifyCellLocationForSubscriber(int subId, Bundle cellLocation) { log("notifyCellLocationForSubscriber: subId=" + subId + " cellLocation=" + cellLocation); if (!checkNotifyPermission("notifyCellLocation()")) { @@ -936,8 +965,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mCellLocation[phoneId] = cellLocation; for (Record r : mRecords) { if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION) && - ((r.subId == subId) || - (r.subId == SubscriptionManager.DEFAULT_SUB_ID))) { + subIdMatch(r.subId, subId)) { try { if (DBG_LOC) { log("notifyCellLocation: cellLocation=" + cellLocation @@ -1068,7 +1096,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } } - public void notifyOemHookRawEventForSubscriber(long subId, byte[] rawData) { + public void notifyOemHookRawEventForSubscriber(int subId, byte[] rawData) { if (!checkNotifyPermission("notifyOemHookRawEventForSubscriber")) { return; } @@ -1134,7 +1162,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { // the legacy intent broadcasting // - private void broadcastServiceStateChanged(ServiceState state, long subId) { + private void broadcastServiceStateChanged(ServiceState state, int subId) { long ident = Binder.clearCallingIdentity(); try { mBatteryStats.notePhoneState(state.getState()); @@ -1153,7 +1181,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private void broadcastSignalStrengthChanged(SignalStrength signalStrength, long subId) { + private void broadcastSignalStrengthChanged(SignalStrength signalStrength, int subId) { long ident = Binder.clearCallingIdentity(); try { mBatteryStats.notePhoneSignalStrength(signalStrength); @@ -1172,7 +1200,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL); } - private void broadcastCallStateChanged(int state, String incomingNumber, long subId) { + private void broadcastCallStateChanged(int state, String incomingNumber, int subId) { long ident = Binder.clearCallingIdentity(); try { if (state == TelephonyManager.CALL_STATE_IDLE) { @@ -1200,7 +1228,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private void broadcastDataConnectionStateChanged(int state, boolean isDataConnectivityPossible, String reason, String apn, String apnType, LinkProperties linkProperties, - NetworkCapabilities networkCapabilities, boolean roaming, long subId) { + NetworkCapabilities networkCapabilities, boolean roaming, int subId) { // Note: not reporting to the battery stats service here, because the // status bar takes care of that after taking into account all of the // required info. @@ -1232,7 +1260,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { } private void broadcastDataConnectionFailed(String reason, String apnType, - long subId) { + int subId) { Intent intent = new Intent(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); intent.putExtra(PhoneConstants.FAILURE_REASON_KEY, reason); intent.putExtra(PhoneConstants.DATA_APN_TYPE_KEY, apnType); @@ -1348,11 +1376,11 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private static class LogSSC { private Time mTime; private String mS; - private long mSubId; + private int mSubId; private int mPhoneId; private ServiceState mState; - public void set(Time t, String s, long subId, int phoneId, ServiceState state) { + public void set(Time t, String s, int subId, int phoneId, ServiceState state) { mTime = t; mS = s; mSubId = subId; mPhoneId = phoneId; mState = state; } @@ -1365,7 +1393,7 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { private LogSSC logSSC [] = new LogSSC[10]; private int next = 0; - private void logServiceStateChanged(String s, long subId, int phoneId, ServiceState state) { + private void logServiceStateChanged(String s, int subId, int phoneId, ServiceState state) { if (logSSC == null || logSSC.length == 0) { return; } @@ -1400,4 +1428,117 @@ class TelephonyRegistry extends ITelephonyRegistry.Stub { log(prompt + ": ----------------"); } } + + boolean subIdMatch(int rSubId, int subId) { + if(rSubId == SubscriptionManager.DEFAULT_SUB_ID) { + return (subId == mDefaultSubId); + } else { + return (rSubId == subId); + } + } + + private void checkPossibleMissNotify(Record r, int phoneId) { + int events = r.events; + + if ((events & PhoneStateListener.LISTEN_SERVICE_STATE) != 0) { + try { + if (VDBG) log("checkPossibleMissNotify: onServiceStateChanged state=" + + mServiceState[phoneId]); + r.callback.onServiceStateChanged( + new ServiceState(mServiceState[phoneId])); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + + if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) { + try { + SignalStrength signalStrength = mSignalStrength[phoneId]; + if (DBG) { + log("checkPossibleMissNotify: onSignalStrengthsChanged SS=" + signalStrength); + } + r.callback.onSignalStrengthsChanged(new SignalStrength(signalStrength)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + + if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTH) != 0) { + try { + int gsmSignalStrength = mSignalStrength[phoneId] + .getGsmSignalStrength(); + if (DBG) { + log("checkPossibleMissNotify: onSignalStrengthChanged SS=" + + gsmSignalStrength); + } + r.callback.onSignalStrengthChanged((gsmSignalStrength == 99 ? -1 + : gsmSignalStrength)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + + if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) { + try { + if (DBG_LOC) { + log("checkPossibleMissNotify: onCellInfoChanged[" + phoneId + "] = " + + mCellInfo.get(phoneId)); + } + r.callback.onCellInfoChanged(mCellInfo.get(phoneId)); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + + if ((events & PhoneStateListener.LISTEN_MESSAGE_WAITING_INDICATOR) != 0) { + try { + if (VDBG) { + log("checkPossibleMissNotify: onMessageWaitingIndicatorChanged phoneId=" + + phoneId + " mwi=" + mMessageWaiting[phoneId]); + } + r.callback.onMessageWaitingIndicatorChanged( + mMessageWaiting[phoneId]); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + + if ((events & PhoneStateListener.LISTEN_CALL_FORWARDING_INDICATOR) != 0) { + try { + if (VDBG) { + log("checkPossibleMissNotify: onCallForwardingIndicatorChanged phoneId=" + + phoneId + " cfi=" + mCallForwarding[phoneId]); + } + r.callback.onCallForwardingIndicatorChanged( + mCallForwarding[phoneId]); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + + if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_LOCATION)) { + try { + if (DBG_LOC) log("checkPossibleMissNotify: onCellLocationChanged mCellLocation = " + + mCellLocation[phoneId]); + r.callback.onCellLocationChanged(new Bundle(mCellLocation[phoneId])); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + + if ((events & PhoneStateListener.LISTEN_DATA_CONNECTION_STATE) != 0) { + try { + if (DBG) { + log("checkPossibleMissNotify: onDataConnectionStateChanged(mDataConnectionState" + + "=" + mDataConnectionState[phoneId] + + ", mDataConnectionNetworkType=" + mDataConnectionNetworkType[phoneId] + + ")"); + } + r.callback.onDataConnectionStateChanged(mDataConnectionState[phoneId], + mDataConnectionNetworkType[phoneId]); + } catch (RemoteException ex) { + mRemoveList.add(r.binder); + } + } + } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 8dfb321..9f1ce0b 100755 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -1734,8 +1734,13 @@ public final class ActivityManagerService extends ActivityManagerNative logBuilder.append(" MemInfo: "); logBuilder.append(infos[Debug.MEMINFO_SLAB]).append(" kB slab, "); logBuilder.append(infos[Debug.MEMINFO_SHMEM]).append(" kB shmem, "); + logBuilder.append(infos[Debug.MEMINFO_VM_ALLOC_USED]).append(" kB vm alloc, "); + logBuilder.append(infos[Debug.MEMINFO_PAGE_TABLES]).append(" kB page tables "); + logBuilder.append(infos[Debug.MEMINFO_KERNEL_STACK]).append(" kB kernel stack\n"); + logBuilder.append(" "); logBuilder.append(infos[Debug.MEMINFO_BUFFERS]).append(" kB buffers, "); logBuilder.append(infos[Debug.MEMINFO_CACHED]).append(" kB cached, "); + logBuilder.append(infos[Debug.MEMINFO_MAPPED]).append(" kB mapped, "); logBuilder.append(infos[Debug.MEMINFO_FREE]).append(" kB free\n"); if (infos[Debug.MEMINFO_ZRAM_TOTAL] != 0) { logBuilder.append(" ZRAM: "); @@ -1952,9 +1957,7 @@ public final class ActivityManagerService extends ActivityManagerNative + (SystemClock.uptimeMillis()-start) + "ms"); mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(), memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(), - memInfo.getBuffersSizeKb()+memInfo.getShmemSizeKb() - +memInfo.getSlabSizeKb(), - nativeTotalPss); + memInfo.getKernelUsedSizeKb(), nativeTotalPss); } } @@ -8849,7 +8852,8 @@ public final class ActivityManagerService extends ActivityManagerNative task = mStackSupervisor.anyTaskForIdLocked(task.taskId); if (task != null) { if (!isSystemInitiated - && ((mFocusedActivity == null) || (task != mFocusedActivity.task))) { + && ((mStackSupervisor.getFocusedStack() == null) + || (task != mStackSupervisor.getFocusedStack().topTask()))) { throw new IllegalArgumentException("Invalid task, not in foreground"); } mStackSupervisor.setLockTaskModeLocked(task, !isSystemInitiated); @@ -14240,8 +14244,7 @@ public final class ActivityManagerService extends ActivityManagerNative synchronized (this) { mProcessStats.addSysMemUsageLocked(memInfo.getCachedSizeKb(), memInfo.getFreeSizeKb(), memInfo.getZramTotalSizeKb(), - memInfo.getBuffersSizeKb()+memInfo.getShmemSizeKb()+memInfo.getSlabSizeKb(), - nativeProcTotalPss); + memInfo.getKernelUsedSizeKb(), nativeProcTotalPss); } } if (!brief) { @@ -14280,16 +14283,12 @@ public final class ActivityManagerService extends ActivityManagerNative } if (!isCompact) { pw.print(" Used RAM: "); pw.print(totalPss - cachedPss - + memInfo.getBuffersSizeKb() + memInfo.getShmemSizeKb() - + memInfo.getSlabSizeKb()); pw.print(" kB ("); + + memInfo.getKernelUsedSizeKb()); pw.print(" kB ("); pw.print(totalPss - cachedPss); pw.print(" used pss + "); - pw.print(memInfo.getBuffersSizeKb()); pw.print(" buffers + "); - pw.print(memInfo.getShmemSizeKb()); pw.print(" shmem + "); - pw.print(memInfo.getSlabSizeKb()); pw.println(" slab)"); + pw.print(memInfo.getKernelUsedSizeKb()); pw.print(" kernel)\n"); pw.print(" Lost RAM: "); pw.print(memInfo.getTotalSizeKb() - totalPss - memInfo.getFreeSizeKb() - memInfo.getCachedSizeKb() - - memInfo.getBuffersSizeKb() - memInfo.getShmemSizeKb() - - memInfo.getSlabSizeKb()); pw.println(" kB"); + - memInfo.getKernelUsedSizeKb()); pw.println(" kB"); } if (!brief) { if (memInfo.getZramTotalSizeKb() != 0) { diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java index 03dd3c0..c1bf955 100644 --- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java @@ -120,7 +120,7 @@ public final class ActivityStackSupervisor implements DisplayListener { static final boolean DEBUG_RELEASE = DEBUG || false; static final boolean DEBUG_SAVED_STATE = DEBUG || false; static final boolean DEBUG_SCREENSHOTS = DEBUG || false; - static final boolean DEBUG_STATES = DEBUG || false; + static final boolean DEBUG_STATES = DEBUG || true; static final boolean DEBUG_VISIBLE_BEHIND = DEBUG || false; public static final int HOME_STACK_ID = 0; diff --git a/services/core/java/com/android/server/am/LockTaskNotify.java b/services/core/java/com/android/server/am/LockTaskNotify.java index 5768ddb..b3777ed 100644 --- a/services/core/java/com/android/server/am/LockTaskNotify.java +++ b/services/core/java/com/android/server/am/LockTaskNotify.java @@ -19,6 +19,7 @@ package com.android.server.am; import android.content.Context; import android.os.Handler; import android.os.Message; +import android.view.WindowManager; import android.view.accessibility.AccessibilityManager; import android.widget.Toast; @@ -56,8 +57,7 @@ public class LockTaskNotify { if (mLastToast != null) { mLastToast.cancel(); } - mLastToast = Toast.makeText(mContext, text, Toast.LENGTH_LONG); - mLastToast.show(); + mLastToast = makeAllUserToastAndShow(text); } public void show(boolean starting) { @@ -65,7 +65,15 @@ public class LockTaskNotify { if (starting) { showString = R.string.lock_to_app_start; } - Toast.makeText(mContext, mContext.getString(showString), Toast.LENGTH_LONG).show(); + makeAllUserToastAndShow(mContext.getString(showString)); + } + + private Toast makeAllUserToastAndShow(String text) { + Toast toast = Toast.makeText(mContext, text, Toast.LENGTH_LONG); + toast.getWindowParams().privateFlags |= + WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS; + toast.show(); + return toast; } private final class H extends Handler { diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java index afc781f..b331c84 100644 --- a/services/core/java/com/android/server/am/TaskPersister.java +++ b/services/core/java/com/android/server/am/TaskPersister.java @@ -166,7 +166,7 @@ public class TaskPersister { break; } } - if (queueNdx < 0) { + if (queueNdx < 0 && task.isPersistable) { mWriteQueue.add(new TaskWriteQueueItem(task)); } } else { @@ -473,13 +473,15 @@ public class TaskPersister { if (DEBUG) Slog.d(TAG, "mRecents=" + tasks); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { final TaskRecord task = tasks.get(taskNdx); - if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + " persistable=" + - task.isPersistable); - if (task.isPersistable && !task.stack.isHomeStack()) { + if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task + + " persistable=" + task.isPersistable); + if ((task.isPersistable || task.inRecents) + && !task.stack.isHomeStack()) { if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task); persistentTaskIds.add(task.taskId); } else { - if (DEBUG) Slog.d(TAG, "omitting from persistentTaskIds task=" + task); + if (DEBUG) Slog.d(TAG, + "omitting from persistentTaskIds task=" + task); } } } diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java index 4dfd23b..ee93233 100644 --- a/services/core/java/com/android/server/am/TaskRecord.java +++ b/services/core/java/com/android/server/am/TaskRecord.java @@ -144,7 +144,7 @@ final class TaskRecord { boolean mReuseTask = false; private Bitmap mLastThumbnail; // Last thumbnail captured for this item. - private final File mLastThumbnailFile; // File containing last thubmnail. + private final File mLastThumbnailFile; // File containing last thumbnail. private final String mFilename; CharSequence lastDescription; // Last description captured for this item. diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java index c382be0..3b0d8c1 100644 --- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java +++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java @@ -217,7 +217,7 @@ public class Nat464Xlat extends BaseNetworkObserver { NetworkUtils.resetConnections( CLAT_INTERFACE_NAME, NetworkUtils.RESET_IPV4_ADDRESSES); - mBaseLP.removeStackedLink(mLP); + mBaseLP.removeStackedLink(CLAT_INTERFACE_NAME); updateConnectivityService(); } Slog.i(TAG, "interface " + CLAT_INTERFACE_NAME + diff --git a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java index 3b23b6a..f514531 100644 --- a/services/core/java/com/android/server/display/OverlayDisplayAdapter.java +++ b/services/core/java/com/android/server/display/OverlayDisplayAdapter.java @@ -248,6 +248,7 @@ final class OverlayDisplayAdapter extends DisplayAdapter { mInfo.width = mWidth; mInfo.height = mHeight; mInfo.refreshRate = mRefreshRate; + mInfo.supportedRefreshRates = new float[] { mRefreshRate }; mInfo.densityDpi = mDensityDpi; mInfo.xDpi = mDensityDpi; mInfo.yDpi = mDensityDpi; diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java index c2b4478..0232bad 100644 --- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java +++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java @@ -257,6 +257,7 @@ final class VirtualDisplayAdapter extends DisplayAdapter { mInfo.width = mWidth; mInfo.height = mHeight; mInfo.refreshRate = 60; + mInfo.supportedRefreshRates = new float[] { 60.0f }; mInfo.densityDpi = mDensityDpi; mInfo.xDpi = mDensityDpi; mInfo.yDpi = mDensityDpi; diff --git a/services/core/java/com/android/server/display/WifiDisplayAdapter.java b/services/core/java/com/android/server/display/WifiDisplayAdapter.java index a17d731..6b010d9 100644 --- a/services/core/java/com/android/server/display/WifiDisplayAdapter.java +++ b/services/core/java/com/android/server/display/WifiDisplayAdapter.java @@ -625,6 +625,7 @@ final class WifiDisplayAdapter extends DisplayAdapter { mInfo.width = mWidth; mInfo.height = mHeight; mInfo.refreshRate = mRefreshRate; + mInfo.supportedRefreshRates = new float[] { mRefreshRate }; mInfo.presentationDeadlineNanos = 1000000000L / (int) mRefreshRate; // 1 frame mInfo.flags = mFlags; mInfo.type = Display.TYPE_WIFI; diff --git a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java index cb92112..9593a9c 100644 --- a/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java +++ b/services/core/java/com/android/server/hdmi/ActiveSourceHandler.java @@ -57,8 +57,9 @@ final class ActiveSourceHandler { * Handles the incoming active source command. * * @param newActive new active source information + * @param deviceType device type of the new active source */ - void process(ActiveSource newActive) { + void process(ActiveSource newActive, int deviceType) { // Seq #17 HdmiCecLocalDeviceTv tv = mSource; ActiveSource activeSource = tv.getActiveSource(); @@ -68,7 +69,7 @@ final class ActiveSourceHandler { } HdmiDeviceInfo device = mService.getDeviceInfo(newActive.logicalAddress); if (device == null) { - tv.startNewDeviceAction(newActive); + tv.startNewDeviceAction(newActive, deviceType); } if (!tv.isProhibitMode()) { diff --git a/services/core/java/com/android/server/hdmi/Constants.java b/services/core/java/com/android/server/hdmi/Constants.java index b0a3a66..bb12eae 100644 --- a/services/core/java/com/android/server/hdmi/Constants.java +++ b/services/core/java/com/android/server/hdmi/Constants.java @@ -205,13 +205,6 @@ final class Constants { static final int UNKNOWN_VOLUME = -1; - // IRT(Initiator Repetition Time) in millisecond as recommended in the standard. - // Outgoing UCP commands, when in 'Press and Hold' mode, should be this much apart - // from the adjacent one so as not to place unnecessarily heavy load on the CEC line. - // TODO: This value might need tweaking per product basis. Consider putting it - // in config.xml to allow customization. - static final int IRT_MS = 300; - static final String PROPERTY_PREFERRED_ADDRESS_PLAYBACK = "persist.sys.hdmi.addr.playback"; static final String PROPERTY_PREFERRED_ADDRESS_TV = "persist.sys.hdmi.addr.tv"; diff --git a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java index d965caa..3dd1522 100644 --- a/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java +++ b/services/core/java/com/android/server/hdmi/DevicePowerStatusAction.java @@ -70,7 +70,8 @@ final class DevicePowerStatusAction extends HdmiCecFeatureAction { @Override boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS) { + if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS + || mTargetAddress != cmd.getSource()) { return false; } if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) { diff --git a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java index d155e84..5a1d896 100644 --- a/services/core/java/com/android/server/hdmi/DeviceSelectAction.java +++ b/services/core/java/com/android/server/hdmi/DeviceSelectAction.java @@ -95,7 +95,7 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { sendCommand(mGivePowerStatus, new SendMessageCallback() { @Override public void onSendCompleted(int error) { - if (error == Constants.SEND_RESULT_NAK) { + if (error != Constants.SEND_RESULT_SUCCESS) { invokeCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED); finish(); return; @@ -168,6 +168,10 @@ final class DeviceSelectAction extends HdmiCecFeatureAction { } private void sendSetStreamPath() { + // Turn the active source invalidated, which remains so till <Active Source> comes from + // the selected device. + tv().getActiveSource().invalidate(); + tv().setActivePath(mTarget.getPhysicalAddress()); sendCommand(HdmiCecMessageBuilder.buildSetStreamPath( getSourceAddress(), mTarget.getPhysicalAddress())); invokeCallback(HdmiControlManager.RESULT_SUCCESS); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java index fc53c50..d26be57 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java @@ -85,8 +85,7 @@ abstract class HdmiCecFeatureAction { * Process the command. Called whenever a new command arrives. * * @param cmd command to process - * @return true if the command was consumed in the process; Otherwise false, which - * indicates that the command shall be handled by other actions. + * @return true if the command was consumed in the process; Otherwise false. */ abstract boolean processCommand(HdmiCecMessage cmd); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java index 61c9424..2eca42b 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecKeycode.java @@ -18,6 +18,10 @@ package com.android.server.hdmi; import android.view.KeyEvent; +import libcore.util.EmptyArray; + +import java.util.Arrays; + /** * Helper class to translate android keycode to hdmi cec keycode and vice versa. */ @@ -156,46 +160,60 @@ final class HdmiCecKeycode { /** * A mapping between Android and CEC keycode. + * <p> + * Normal implementation of this looks like * - * <p>Normal implementation of this looks like * <pre> - * new KeycodeEntry(KeyEvent.KEYCODE_DPAD_CENTER, CEC_KEYCODE_SELECT); + * new KeycodeEntry(KeyEvent.KEYCODE_DPAD_CENTER, CEC_KEYCODE_SELECT); * </pre> - * <p>However, some keys in CEC requires additional parameter. - * In order to use parameterized cec key, add unique android keycode (existing or custom) - * corresponding to a pair of cec keycode and and its param. + * <p> + * However, some keys in CEC requires additional parameter. In order to use parameterized cec + * key, add unique android keycode (existing or custom) corresponding to a pair of cec keycode + * and and its param. + * * <pre> - * new KeycodeEntry(CUSTOME_ANDORID_KEY_1, CEC_KEYCODE_SELECT_BROADCAST_TYPE, - * UI_BROADCAST_TOGGLE_ALL); - * new KeycodeEntry(CUSTOME_ANDORID_KEY_2, CEC_KEYCODE_SELECT_BROADCAST_TYPE, - * UI_BROADCAST_ANALOGUE); + * new KeycodeEntry(CUSTOME_ANDORID_KEY_1, CEC_KEYCODE_SELECT_BROADCAST_TYPE, + * UI_BROADCAST_TOGGLE_ALL); + * new KeycodeEntry(CUSTOME_ANDORID_KEY_2, CEC_KEYCODE_SELECT_BROADCAST_TYPE, + * UI_BROADCAST_ANALOGUE); * </pre> */ private static class KeycodeEntry { private final int mAndroidKeycode; - private final int mCecKeycode; private final boolean mIsRepeatable; + private final byte[] mCecKeycodeAndParams; - private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable) { + private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable, + byte[] cecParams) { mAndroidKeycode = androidKeycode; - mCecKeycode = cecKeycode; mIsRepeatable = isRepeatable; + mCecKeycodeAndParams = new byte[cecParams.length + 1]; + System.arraycopy(cecParams, 0, mCecKeycodeAndParams, 1, cecParams.length); + mCecKeycodeAndParams[0] = (byte) (cecKeycode & 0xFF); + } + + private KeycodeEntry(int androidKeycode, int cecKeycode, boolean isRepeatable) { + this(androidKeycode, cecKeycode, isRepeatable, EmptyArray.BYTE); + } + + private KeycodeEntry(int androidKeycode, int cecKeycode, byte[] cecParams) { + this(androidKeycode, cecKeycode, true, cecParams); } private KeycodeEntry(int androidKeycode, int cecKeycode) { - this(androidKeycode, cecKeycode, true); + this(androidKeycode, cecKeycode, true, EmptyArray.BYTE); } - private int toCecKeycodeIfMatched(int androidKeycode) { + private byte[] toCecKeycodeAndParamIfMatched(int androidKeycode) { if (mAndroidKeycode == androidKeycode) { - return mCecKeycode; + return mCecKeycodeAndParams; } else { - return UNSUPPORTED_KEYCODE; + return null; } } - private int toAndroidKeycodeIfMatched(int cecKeycode) { - if (cecKeycode == mCecKeycode) { + private int toAndroidKeycodeIfMatched(byte[] cecKeycodeAndParams) { + if (Arrays.equals(mCecKeycodeAndParams, cecKeycodeAndParams)) { return mAndroidKeycode; } else { return UNSUPPORTED_KEYCODE; @@ -211,6 +229,11 @@ final class HdmiCecKeycode { } } + private static byte[] intToSingleByteArray(int value) { + return new byte[] { + (byte) (value & 0xFF) }; + } + // Keycode entry container for all mappings. // Note that order of entry is the same as above cec keycode definition. private static final KeycodeEntry[] KEYCODE_ENTRIES = new KeycodeEntry[] { @@ -227,19 +250,25 @@ final class HdmiCecKeycode { new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_UP), // No Android keycode defined for CEC_KEYCODE_LEFT_DOWN new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_LEFT_DOWN), - new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU, false), - new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU, false), - new KeycodeEntry(KeyEvent.KEYCODE_MENU, CEC_KEYCODE_CONTENTS_MENU, false), + new KeycodeEntry(KeyEvent.KEYCODE_HOME, CEC_KEYCODE_ROOT_MENU), + new KeycodeEntry(KeyEvent.KEYCODE_SETTINGS, CEC_KEYCODE_SETUP_MENU), + new KeycodeEntry(KeyEvent.KEYCODE_TV_CONTENTS_MENU, CEC_KEYCODE_CONTENTS_MENU, false), // No Android keycode defined for CEC_KEYCODE_FAVORITE_MENU new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_FAVORITE_MENU), + // Note that both BACK and ESCAPE are mapped to EXIT of CEC keycode. + // This would be problematic when translates CEC keycode to Android keycode. + // In current implementation, we pick BACK as mapping of EXIT key. + // If you'd like to map CEC EXIT to Android EXIT key, change order of + // the following two definition. new KeycodeEntry(KeyEvent.KEYCODE_BACK, CEC_KEYCODE_EXIT), + new KeycodeEntry(KeyEvent.KEYCODE_ESCAPE, CEC_KEYCODE_EXIT), // RESERVED new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_TOP_MENU, CEC_KEYCODE_MEDIA_TOP_MENU), - // No Android keycode defined for CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU), + new KeycodeEntry(KeyEvent.KEYCODE_TV_MEDIA_CONTEXT_MENU, + CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU), // RESERVED // No Android keycode defined for CEC_KEYCODE_NUMBER_ENTRY_MODE - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_NUMBER_ENTRY_MODE), + new KeycodeEntry(KeyEvent.KEYCODE_TV_NUMBER_ENTRY, CEC_KEYCODE_NUMBER_ENTRY_MODE), new KeycodeEntry(KeyEvent.KEYCODE_11, CEC_KEYCODE_NUMBER_11), new KeycodeEntry(KeyEvent.KEYCODE_12, CEC_KEYCODE_NUMBER_12), new KeycodeEntry(KeyEvent.KEYCODE_0, CEC_KEYCODE_NUMBER_0_OR_NUMBER_10), @@ -276,7 +305,12 @@ final class HdmiCecKeycode { new KeycodeEntry(KeyEvent.KEYCODE_VOLUME_MUTE, CEC_KEYCODE_MUTE, false), new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PLAY, CEC_KEYCODE_PLAY), new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_STOP, CEC_KEYCODE_STOP), + // Note that we map both MEDIA_PAUSE and MEDIA_PLAY_PAUSE to CEC PAUSE key. + // When it translates CEC PAUSE key, it picks Android MEDIA_PAUSE key as a mapping of + // it. If you'd like to choose MEDIA_PLAY_PAUSE, please change order of the following + // two lines. new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PAUSE, CEC_KEYCODE_PAUSE), + new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE, CEC_KEYCODE_PAUSE), new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_RECORD, CEC_KEYCODE_RECORD), new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_REWIND, CEC_KEYCODE_REWIND), new KeycodeEntry(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD, CEC_KEYCODE_FAST_FORWARD), @@ -291,48 +325,61 @@ final class HdmiCecKeycode { new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RESERVED), // No Android keycode defined for CEC_KEYCODE_ANGLE new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_ANGLE), - // No Android keycode defined for CEC_KEYCODE_SUB_PICTURE - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SUB_PICTURE), + new KeycodeEntry(KeyEvent.KEYCODE_CAPTIONS, CEC_KEYCODE_SUB_PICTURE), // No Android keycode defined for CEC_KEYCODE_VIDEO_ON_DEMAND new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_VIDEO_ON_DEMAND), new KeycodeEntry(KeyEvent.KEYCODE_GUIDE, CEC_KEYCODE_ELECTRONIC_PROGRAM_GUIDE), - // No Android keycode defined for CEC_KEYCODE_TIMER_PROGRAMMING - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TIMER_PROGRAMMING), + new KeycodeEntry(KeyEvent.KEYCODE_TV_TIMER_PROGRAMMING, CEC_KEYCODE_TIMER_PROGRAMMING), // No Android keycode defined for CEC_KEYCODE_INITIAL_CONFIGURATION new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_INITIAL_CONFIGURATION), // No Android keycode defined for CEC_KEYCODE_SELECT_BROADCAST_TYPE new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_BROADCAST_TYPE), + new KeycodeEntry(KeyEvent.KEYCODE_TV_TERRESTRIAL_ANALOG, + CEC_KEYCODE_SELECT_BROADCAST_TYPE, true, + intToSingleByteArray(UI_BROADCAST_ANALOGUE)), + new KeycodeEntry(KeyEvent.KEYCODE_TV_TERRESTRIAL_DIGITAL, + CEC_KEYCODE_SELECT_BROADCAST_TYPE, true, + intToSingleByteArray(UI_BROADCAST_DIGITAL_TERRESTRIAL)), + new KeycodeEntry(KeyEvent.KEYCODE_TV_SATELLITE_BS, + CEC_KEYCODE_SELECT_BROADCAST_TYPE, true, + intToSingleByteArray(UI_BROADCAST_DIGITAL_SATELLITE)), + new KeycodeEntry(KeyEvent.KEYCODE_TV_SATELLITE_CS, + CEC_KEYCODE_SELECT_BROADCAST_TYPE, true, + intToSingleByteArray(UI_BROADCAST_DIGITAL_COMMNICATIONS_SATELLITE)), + new KeycodeEntry(KeyEvent.KEYCODE_TV_NETWORK, + CEC_KEYCODE_SELECT_BROADCAST_TYPE, true, + intToSingleByteArray(UI_BROADCAST_TOGGLE_ANALOGUE_DIGITAL)), // No Android keycode defined for CEC_KEYCODE_SELECT_SOUND_PRESENTATION new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_SOUND_PRESENTATION), // RESERVED // The following deterministic key definitions do not need key mapping // since they are supposed to be generated programmatically only. // No Android keycode defined for CEC_KEYCODE_PLAY_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PLAY_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PLAY_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_PAUSE_PLAY_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_PLAY_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_PLAY_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_RECORD_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RECORD_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RECORD_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_PAUSE_RECORD_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_RECORD_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_PAUSE_RECORD_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_STOP_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_STOP_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_STOP_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_MUTE_FUNCTION new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_MUTE_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_RESTORE_VOLUME_FUNCTION new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_RESTORE_VOLUME_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_TUNE_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TUNE_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_TUNE_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_SELECT_MEDIA_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_MEDIA_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_MEDIA_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AV_INPUT_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_SELECT_AUDIO_INPUT_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_POWER_TOGGLE_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_TOGGLE_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_TOGGLE_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_POWER_OFF_FUNCTION - new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_OFF_FUNCTION), + new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_OFF_FUNCTION, false), // No Android keycode defined for CEC_KEYCODE_POWER_ON_FUNCTION new KeycodeEntry(UNSUPPORTED_KEYCODE, CEC_KEYCODE_POWER_ON_FUNCTION, false), // RESERVED @@ -347,31 +394,31 @@ final class HdmiCecKeycode { }; /** - * Translate Android keycode to Hdmi Cec keycode. + * Translate Android keycode to Hdmi Cec keycode and params. * * @param keycode Android keycode. For details, refer {@link KeyEvent} - * @return single byte CEC keycode if matched. + * @return byte array of CEC keycode and params if matched. Otherwise, return null. */ - static int androidKeyToCecKey(int keycode) { + static byte[] androidKeyToCecKey(int keycode) { for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) { - int cecKeycode = KEYCODE_ENTRIES[i].toCecKeycodeIfMatched(keycode); - if (cecKeycode != UNSUPPORTED_KEYCODE) { - return cecKeycode; + byte[] cecKeycodeAndParams = KEYCODE_ENTRIES[i].toCecKeycodeAndParamIfMatched(keycode); + if (cecKeycodeAndParams != null) { + return cecKeycodeAndParams; } } - return UNSUPPORTED_KEYCODE; + return null; } /** - * Translate Hdmi CEC keycode to Android keycode. + * Translate Hdmi CEC keycode with params to Android keycode. * - * @param keycode CEC keycode - * @return cec keycode corresponding to the given android keycode. - * If finds no matched keycode, return {@link #UNSUPPORTED_KEYCODE} + * @param cecKeycodeAndParams CEC keycode and params + * @return cec keycode corresponding to the given android keycode. If finds no matched keycode, + * return {@link #UNSUPPORTED_KEYCODE} */ - static int cecKeyToAndroidKey(int keycode) { + static int cecKeycodeAndParamsToAndroidKey(byte[] cecKeycodeAndParams) { for (int i = 0; i < KEYCODE_ENTRIES.length; ++i) { - int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(keycode); + int androidKey = KEYCODE_ENTRIES[i].toAndroidKeycodeIfMatched(cecKeycodeAndParams); if (androidKey != UNSUPPORTED_KEYCODE) { return androidKey; } @@ -399,7 +446,6 @@ final class HdmiCecKeycode { * Returns {@code true} if given Android keycode is supported, otherwise {@code false}. */ static boolean isSupportedKeycode(int androidKeycode) { - return HdmiCecKeycode.androidKeyToCecKey(androidKeycode) - != HdmiCecKeycode.UNSUPPORTED_KEYCODE; - } + return HdmiCecKeycode.androidKeyToCecKey(androidKeycode) != null; + } } diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java index 8f9af61..4f8b9fb 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java @@ -34,7 +34,6 @@ import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; -import java.util.LinkedList; import java.util.List; /** @@ -125,7 +124,7 @@ abstract class HdmiCecLocalDevice { // A collection of FeatureAction. // Note that access to this collection should happen in service thread. - private final LinkedList<HdmiCecFeatureAction> mActions = new LinkedList<>(); + private final ArrayList<HdmiCecFeatureAction> mActions = new ArrayList<>(); private final Handler mHandler = new Handler () { @Override @@ -290,12 +289,14 @@ abstract class HdmiCecLocalDevice { @ServiceThreadOnly private boolean dispatchMessageToAction(HdmiCecMessage message) { assertRunOnServiceThread(); - for (HdmiCecFeatureAction action : mActions) { - if (action.processCommand(message)) { - return true; - } + boolean processed = false; + // Use copied action list in that processCommand may remove itself. + for (HdmiCecFeatureAction action : new ArrayList<>(mActions)) { + // Iterates all actions to check whether incoming message is consumed. + boolean result = action.processCommand(message); + processed = processed || result; } - return false; + return processed; } @ServiceThreadOnly @@ -425,9 +426,7 @@ abstract class HdmiCecLocalDevice { final long downTime = SystemClock.uptimeMillis(); final byte[] params = message.getParams(); - // Note that we don't support parameterized keycode now. - // TODO: translate parameterized keycode as well. - final int keycode = HdmiCecKeycode.cecKeyToAndroidKey(params[0]); + final int keycode = HdmiCecKeycode.cecKeycodeAndParamsToAndroidKey(params); int keyRepeatCount = 0; if (mLastKeycode != HdmiCecKeycode.UNSUPPORTED_KEYCODE) { if (keycode == mLastKeycode) { @@ -517,8 +516,8 @@ abstract class HdmiCecLocalDevice { } protected boolean handleVendorCommand(HdmiCecMessage message) { - if (!mService.invokeVendorCommandListeners(mDeviceType, message.getSource(), - message.getParams(), false)) { + if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(), + message.getDestination(), message.getParams(), false)) { // Vendor command listener may not have been registered yet. Respond with // <Feature Abort> [NOT_IN_CORRECT_MODE] so that the sender can try again later. mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE); @@ -530,8 +529,8 @@ abstract class HdmiCecLocalDevice { byte[] params = message.getParams(); int vendorId = HdmiUtils.threeBytesToInt(params); if (vendorId == mService.getVendorId()) { - if (!mService.invokeVendorCommandListeners(mDeviceType, message.getSource(), params, - true)) { + if (!mService.invokeVendorCommandListenersOnReceived(mDeviceType, message.getSource(), + message.getDestination(), params, true)) { mService.maySendFeatureAbortCommand(message, Constants.ABORT_NOT_IN_CORRECT_MODE); } } else if (message.getDestination() != Constants.ADDR_BROADCAST && diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java index 780d54b..85a1a15 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevicePlayback.java @@ -50,6 +50,8 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { assertRunOnServiceThread(); mService.sendCecCommand(HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( mAddress, mService.getPhysicalAddress(), mDeviceType)); + mService.sendCecCommand(HdmiCecMessageBuilder.buildDeviceVendorIdCommand( + mAddress, mService.getVendorId())); startQueuedActions(); } @@ -156,7 +158,7 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { assertRunOnServiceThread(); int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); maySetActiveSource(physicalAddress); - maySendActiveSource(); + maySendActiveSource(message.getSource()); wakeUpIfActiveSource(); return true; // Broadcast message. } @@ -196,10 +198,13 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { } } - private void maySendActiveSource() { + private void maySendActiveSource(int dest) { if (mIsActiveSource) { mService.sendCecCommand(HdmiCecMessageBuilder.buildActiveSource( mAddress, mService.getPhysicalAddress())); + // Always reports menu-status active to receive RCP. + mService.sendCecCommand(HdmiCecMessageBuilder.buildReportMenuStatus( + mAddress, dest, Constants.MENU_STATE_ACTIVATED)); } } @@ -207,7 +212,7 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { @ServiceThreadOnly protected boolean handleRequestActiveSource(HdmiCecMessage message) { assertRunOnServiceThread(); - maySendActiveSource(); + maySendActiveSource(message.getSource()); return true; // Broadcast message. } @@ -230,4 +235,4 @@ final class HdmiCecLocalDevicePlayback extends HdmiCecLocalDevice { super.dump(pw); pw.println("mIsActiveSource: " + mIsActiveSource); } -}
\ No newline at end of file +} diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java index 0fb4b48..6bae761 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java @@ -110,6 +110,9 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { // If true, TV wakes itself up when receiving <Text/Image View On>. private boolean mAutoWakeup; + // List of the logical address of local CEC devices. Unmodifiable, thread-safe. + private List<Integer> mLocalDeviceAddresses; + private final HdmiCecStandbyModeHandler mStandbyHandler; // If true, do not do routing control/send active source for internal source. @@ -141,10 +144,22 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { mSkipRoutingControl = (reason == HdmiControlService.INITIATED_BY_WAKE_UP_MESSAGE); launchRoutingControl(reason != HdmiControlService.INITIATED_BY_ENABLE_CEC && reason != HdmiControlService.INITIATED_BY_BOOT_UP); + mLocalDeviceAddresses = initLocalDeviceAddresses(); launchDeviceDiscovery(); startQueuedActions(); } + + @ServiceThreadOnly + private List<Integer> initLocalDeviceAddresses() { + assertRunOnServiceThread(); + List<Integer> addresses = new ArrayList<>(); + for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { + addresses.add(device.getDeviceInfo().getLogicalAddress()); + } + return Collections.unmodifiableList(addresses); + } + @Override @ServiceThreadOnly protected int getPreferredAddress() { @@ -351,13 +366,26 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (!action.isEmpty()) { action.get(0).processKeyEvent(keyCode, isPressed); } else { - if (isPressed && getActiveSource().isValid()) { - int logicalAddress = getActiveSource().logicalAddress; - addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode)); - } else { - Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed); + if (isPressed) { + int logicalAddress = findKeyReceiverAddress(); + if (logicalAddress != Constants.ADDR_INVALID) { + addAndStartAction(new SendKeyAction(this, logicalAddress, keyCode)); + return; + } } + Slog.w(TAG, "Discard key event: " + keyCode + " pressed:" + isPressed); + } + } + + private int findKeyReceiverAddress() { + if (getActiveSource().isValid()) { + return getActiveSource().logicalAddress; + } + HdmiDeviceInfo info = getDeviceInfoByPath(getActivePath()); + if (info != null) { + return info.getLogicalAddress(); } + return Constants.ADDR_INVALID; } private static void invokeCallback(IHdmiControlCallback callback, int result) { @@ -377,11 +405,12 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { assertRunOnServiceThread(); int logicalAddress = message.getSource(); int physicalAddress = HdmiUtils.twoBytesToInt(message.getParams()); - if (getCecDeviceInfo(logicalAddress) == null) { + HdmiDeviceInfo info = getCecDeviceInfo(logicalAddress); + if (info == null) { handleNewDeviceAtTheTailOfActivePath(physicalAddress); } else { ActiveSource activeSource = ActiveSource.of(logicalAddress, physicalAddress); - ActiveSourceHandler.create(this, null).process(activeSource); + ActiveSourceHandler.create(this, null).process(activeSource, info.getDeviceType()); } return true; } @@ -471,7 +500,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { if (!isInDeviceList(address, path)) { handleNewDeviceAtTheTailOfActivePath(path); } - startNewDeviceAction(ActiveSource.of(address, path)); + startNewDeviceAction(ActiveSource.of(address, path), type); return true; } @@ -507,7 +536,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { return false; } - void startNewDeviceAction(ActiveSource activeSource) { + void startNewDeviceAction(ActiveSource activeSource, int deviceType) { for (NewDeviceAction action : getActions(NewDeviceAction.class)) { // If there is new device action which has the same logical address and path // ignore new request. @@ -523,7 +552,7 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } addAndStartAction(new NewDeviceAction(this, activeSource.logicalAddress, - activeSource.physicalAddress)); + activeSource.physicalAddress, deviceType)); } private void handleNewDeviceAtTheTailOfActivePath(int path) { @@ -1182,15 +1211,8 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } - @ServiceThreadOnly private boolean isLocalDeviceAddress(int address) { - assertRunOnServiceThread(); - for (HdmiCecLocalDevice device : mService.getAllLocalDevices()) { - if (device.isAddressOf(address)) { - return true; - } - } - return false; + return mLocalDeviceAddresses.contains(address); } @ServiceThreadOnly @@ -1240,6 +1262,17 @@ final class HdmiCecLocalDeviceTv extends HdmiCecLocalDevice { } } + List<HdmiDeviceInfo> getSafeCecDevicesLocked() { + ArrayList<HdmiDeviceInfo> infoList = new ArrayList<>(); + for (HdmiDeviceInfo info : mSafeAllDeviceInfos) { + if (isLocalDeviceAddress(info.getLogicalAddress())) { + continue; + } + infoList.add(info); + } + return infoList; + } + /** * Called when a device is newly added or a new device is detected or * existing device is updated. diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 60d1520..e741fc4 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -303,6 +303,7 @@ public final class HdmiControlService extends SystemService { } } else { Slog.i(TAG, "Device does not support HDMI-CEC."); + return; } mMhlController = HdmiMhlControllerStub.create(this); @@ -315,20 +316,23 @@ public final class HdmiControlService extends SystemService { mMessageValidator = new HdmiCecMessageValidator(this); publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); - // Register broadcast receiver for power state change. if (mCecController != null) { + // Register broadcast receiver for power state change. IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); getContext().registerReceiver(mHdmiControlBroadcastReceiver, filter); + + // Register ContentObserver to monitor the settings change. + registerContentObserver(); } } /** * Called when the initialization of local devices is complete. */ - private void onInitializeCecComplete() { + private void onInitializeCecComplete(int initiatedBy) { if (mPowerStatus == HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON) { mPowerStatus = HdmiControlManager.POWER_STATUS_ON; } @@ -336,7 +340,22 @@ public final class HdmiControlService extends SystemService { if (isTvDevice()) { mCecController.setOption(OPTION_CEC_AUTO_WAKEUP, toInt(tv().getAutoWakeup())); - registerContentObserver(); + } + int reason = -1; + switch (initiatedBy) { + case INITIATED_BY_BOOT_UP: + reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_START; + break; + case INITIATED_BY_ENABLE_CEC: + reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING; + break; + case INITIATED_BY_SCREEN_ON: + case INITIATED_BY_WAKE_UP_MESSAGE: + reason = HdmiControlManager.CONTROL_STATE_CHANGED_REASON_WAKEUP; + break; + } + if (reason != -1) { + invokeVendorCommandListenersOnControlStateChanged(true, reason); } } @@ -401,10 +420,6 @@ public final class HdmiControlService extends SystemService { Global.putInt(cr, key, toInt(value)); } - private void unregisterSettingsObserver() { - getContext().getContentResolver().unregisterContentObserver(mSettingsObserver); - } - private void initializeCec(int initiatedBy) { mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED); initializeLocalDevices(initiatedBy); @@ -459,7 +474,7 @@ public final class HdmiControlService extends SystemService { if (initiatedBy != INITIATED_BY_HOTPLUG) { // In case of the hotplug we don't call onInitializeCecComplete() // since we reallocate the logical address only. - onInitializeCecComplete(); + onInitializeCecComplete(initiatedBy); } notifyAddressAllocated(allocatedDevices, initiatedBy); } @@ -729,20 +744,18 @@ public final class HdmiControlService extends SystemService { void onHotplug(int portId, boolean connected) { assertRunOnServiceThread(); - ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); - for (int type : mLocalDevices) { - if (type == HdmiDeviceInfo.DEVICE_TV) { - // Skip the reallocation of the logical address on TV. - continue; - } - HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); - if (localDevice == null) { - localDevice = HdmiCecLocalDevice.create(this, type); - localDevice.init(); + if (connected && !isTvDevice()) { + ArrayList<HdmiCecLocalDevice> localDevices = new ArrayList<>(); + for (int type : mLocalDevices) { + HdmiCecLocalDevice localDevice = mCecController.getLocalDevice(type); + if (localDevice == null) { + localDevice = HdmiCecLocalDevice.create(this, type); + localDevice.init(); + } + localDevices.add(localDevice); } - localDevices.add(localDevice); + allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG); } - allocateLogicalAddress(localDevices, INITIATED_BY_HOTPLUG); for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { device.onHotplug(portId, connected); @@ -827,6 +840,7 @@ public final class HdmiControlService extends SystemService { @ServiceThreadOnly void handleMhlHotplugEvent(int portId, boolean connected) { assertRunOnServiceThread(); + // Hotplug event is used to add/remove MHL devices as TV input. if (connected) { HdmiMhlLocalDeviceStub newDevice = new HdmiMhlLocalDeviceStub(this, portId); HdmiMhlLocalDeviceStub oldDevice = mMhlController.addLocalDevice(newDevice); @@ -834,17 +848,14 @@ public final class HdmiControlService extends SystemService { oldDevice.onDeviceRemoved(); Slog.i(TAG, "Old device of port " + portId + " is removed"); } + invokeDeviceEventListeners(newDevice.getInfo(), DEVICE_EVENT_ADD_DEVICE); + updateSafeMhlInput(); } else { HdmiMhlLocalDeviceStub device = mMhlController.removeLocalDevice(portId); if (device != null) { device.onDeviceRemoved(); - // There is no explicit event for device removal. - // Hence we remove the device on hotplug event. - HdmiDeviceInfo deviceInfo = device.getInfo(); - if (deviceInfo != null) { - invokeDeviceEventListeners(deviceInfo, DEVICE_EVENT_REMOVE_DEVICE); - updateSafeMhlInput(); - } + invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_REMOVE_DEVICE); + updateSafeMhlInput(); } else { Slog.w(TAG, "No device to remove:[portId=" + portId); } @@ -880,11 +891,8 @@ public final class HdmiControlService extends SystemService { assertRunOnServiceThread(); HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); - // Hotplug event should already have been called before device status change event. if (device != null) { device.setDeviceStatusChange(adopterId, deviceId); - invokeDeviceEventListeners(device.getInfo(), DEVICE_EVENT_ADD_DEVICE); - updateSafeMhlInput(); } else { Slog.w(TAG, "No mhl device exists for device status event[portId:" + portId + ", adopterId:" + adopterId + ", deviceId:" + deviceId + "]"); @@ -1025,6 +1033,7 @@ public final class HdmiControlService extends SystemService { @Override public HdmiDeviceInfo getActiveSource() { + enforceAccessPermission(); HdmiCecLocalDeviceTv tv = tv(); if (tv == null) { Slog.w(TAG, "Local tv device not available"); @@ -1238,6 +1247,19 @@ public final class HdmiControlService extends SystemService { } } + // Returns all the CEC devices on the bus including system audio, switch, + // even those of reserved type. + @Override + public List<HdmiDeviceInfo> getDeviceList() { + enforceAccessPermission(); + HdmiCecLocalDeviceTv tv = tv(); + synchronized (mLock) { + return (tv == null) + ? Collections.<HdmiDeviceInfo>emptyList() + : tv.getSafeCecDevicesLocked(); + } + } + @Override public void setSystemAudioVolume(final int oldIndex, final int newIndex, final int maxIndex) { @@ -1344,11 +1366,13 @@ public final class HdmiControlService extends SystemService { @Override public void setHdmiRecordListener(IHdmiRecordListener listener) { + enforceAccessPermission(); HdmiControlService.this.setHdmiRecordListener(listener); } @Override public void startOneTouchRecord(final int recorderAddress, final byte[] recordSource) { + enforceAccessPermission(); runOnServiceThread(new Runnable() { @Override public void run() { @@ -1363,6 +1387,7 @@ public final class HdmiControlService extends SystemService { @Override public void stopOneTouchRecord(final int recorderAddress) { + enforceAccessPermission(); runOnServiceThread(new Runnable() { @Override public void run() { @@ -1378,6 +1403,7 @@ public final class HdmiControlService extends SystemService { @Override public void startTimerRecording(final int recorderAddress, final int sourceType, final byte[] recordSource) { + enforceAccessPermission(); runOnServiceThread(new Runnable() { @Override public void run() { @@ -1393,6 +1419,7 @@ public final class HdmiControlService extends SystemService { @Override public void clearTimerRecording(final int recorderAddress, final int sourceType, final byte[] recordSource) { + enforceAccessPermission(); runOnServiceThread(new Runnable() { @Override public void run() { @@ -1696,7 +1723,7 @@ public final class HdmiControlService extends SystemService { } boolean isTvDevice() { - return tv() != null; + return mLocalDevices.contains(HdmiDeviceInfo.DEVICE_TV); } private HdmiCecLocalDevicePlayback playback() { @@ -1782,6 +1809,8 @@ public final class HdmiControlService extends SystemService { private void onStandby() { assertRunOnServiceThread(); mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_STANDBY; + invokeVendorCommandListenersOnControlStateChanged(false, + HdmiControlManager.CONTROL_STATE_CHANGED_REASON_STANDBY); final List<HdmiCecLocalDevice> devices = getAllLocalDevices(); disableDevices(new PendingActionClearedCallback() { @@ -1820,9 +1849,6 @@ public final class HdmiControlService extends SystemService { for (HdmiCecLocalDevice device : mCecController.getLocalDeviceList()) { device.disableDevice(mStandbyMessageReceived, callback); } - if (isTvDevice()) { - unregisterSettingsObserver(); - } } mMhlController.clearAllLocalDevices(); @@ -1867,8 +1893,8 @@ public final class HdmiControlService extends SystemService { } } - boolean invokeVendorCommandListeners(int deviceType, int srcAddress, byte[] params, - boolean hasVendorId) { + boolean invokeVendorCommandListenersOnReceived(int deviceType, int srcAddress, int destAddress, + byte[] params, boolean hasVendorId) { synchronized (mLock) { if (mVendorCommandListenerRecords.isEmpty()) { return false; @@ -1878,7 +1904,7 @@ public final class HdmiControlService extends SystemService { continue; } try { - record.mListener.onReceived(srcAddress, params, hasVendorId); + record.mListener.onReceived(srcAddress, destAddress, params, hasVendorId); } catch (RemoteException e) { Slog.e(TAG, "Failed to notify vendor command reception", e); } @@ -1887,6 +1913,22 @@ public final class HdmiControlService extends SystemService { } } + boolean invokeVendorCommandListenersOnControlStateChanged(boolean enabled, int reason) { + synchronized (mLock) { + if (mVendorCommandListenerRecords.isEmpty()) { + return false; + } + for (VendorCommandListenerRecord record : mVendorCommandListenerRecords) { + try { + record.mListener.onControlStateChanged(enabled, reason); + } catch (RemoteException e) { + Slog.e(TAG, "Failed to notify control-state-changed to vendor handler", e); + } + } + return true; + } + } + private void addHdmiMhlVendorCommandListener(IHdmiMhlVendorCommandListener listener) { HdmiMhlVendorCommandListenerRecord record = new HdmiMhlVendorCommandListenerRecord(listener); @@ -1936,6 +1978,11 @@ public final class HdmiControlService extends SystemService { void setControlEnabled(boolean enabled) { assertRunOnServiceThread(); + if (!enabled) { + // Call the vendor handler before the service is disabled. + invokeVendorCommandListenersOnControlStateChanged(false, + HdmiControlManager.CONTROL_STATE_CHANGED_REASON_SETTING); + } int value = toInt(enabled); mCecController.setOption(OPTION_CEC_ENABLE, value); mMhlController.setOption(OPTION_MHL_ENABLE, value); @@ -2008,9 +2055,7 @@ public final class HdmiControlService extends SystemService { // may not be the MHL-enabled one. In this case the device info to be passed to // input change listener should be the one describing the corresponding HDMI port. HdmiMhlLocalDeviceStub device = mMhlController.getLocalDevice(portId); - HdmiDeviceInfo info = (device != null && device.getInfo() != null) - ? device.getInfo() - : mPortDeviceMap.get(portId); + HdmiDeviceInfo info = (device != null) ? device.getInfo() : mPortDeviceMap.get(portId); invokeInputChangeListener(info); } @@ -2042,7 +2087,7 @@ public final class HdmiControlService extends SystemService { assertRunOnServiceThread(); Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE); intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId); - intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRAM_PARAM1, extra); + intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRA_PARAM1, extra); getContext().sendBroadcastAsUser(intent, UserHandle.ALL, HdmiControlService.PERMISSION); } diff --git a/services/core/java/com/android/server/hdmi/NewDeviceAction.java b/services/core/java/com/android/server/hdmi/NewDeviceAction.java index 2074085..998889b 100644 --- a/services/core/java/com/android/server/hdmi/NewDeviceAction.java +++ b/services/core/java/com/android/server/hdmi/NewDeviceAction.java @@ -47,6 +47,7 @@ final class NewDeviceAction extends HdmiCecFeatureAction { private final int mDeviceLogicalAddress; private final int mDevicePhysicalAddress; + private final int mDeviceType; private int mVendorId; private String mDisplayName; @@ -57,12 +58,14 @@ final class NewDeviceAction extends HdmiCecFeatureAction { * @param source {@link HdmiCecLocalDevice} instance * @param deviceLogicalAddress logical address of the device in interest * @param devicePhysicalAddress physical address of the device in interest + * @param deviceType type of the device */ NewDeviceAction(HdmiCecLocalDevice source, int deviceLogicalAddress, - int devicePhysicalAddress) { + int devicePhysicalAddress, int deviceType) { super(source); mDeviceLogicalAddress = deviceLogicalAddress; mDevicePhysicalAddress = devicePhysicalAddress; + mDeviceType = deviceType; mVendorId = Constants.UNKNOWN_VENDOR_ID; } @@ -155,8 +158,7 @@ final class NewDeviceAction extends HdmiCecFeatureAction { HdmiDeviceInfo deviceInfo = new HdmiDeviceInfo( mDeviceLogicalAddress, mDevicePhysicalAddress, tv().getPortId(mDevicePhysicalAddress), - HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress), - mVendorId, mDisplayName); + mDeviceType, mVendorId, mDisplayName); tv().addCecDevice(deviceInfo); if (HdmiUtils.getTypeFromAddress(mDeviceLogicalAddress) diff --git a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java index 7db991a..e764a1c 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchPlayAction.java @@ -92,7 +92,8 @@ final class OneTouchPlayAction extends HdmiCecFeatureAction { @Override boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS) { + if (mState != STATE_WAITING_FOR_REPORT_POWER_STATUS + || mTargetAddress != cmd.getSource()) { return false; } if (cmd.getOpcode() == Constants.MESSAGE_REPORT_POWER_STATUS) { diff --git a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java index 39c0d7f..906944b 100644 --- a/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java +++ b/services/core/java/com/android/server/hdmi/OneTouchRecordAction.java @@ -68,23 +68,21 @@ public class OneTouchRecordAction extends HdmiCecFeatureAction { finish(); return; } - - mState = STATE_WAITING_FOR_RECORD_STATUS; - addTimer(mState, RECORD_STATUS_TIMEOUT_MS); } }); + mState = STATE_WAITING_FOR_RECORD_STATUS; + addTimer(mState, RECORD_STATUS_TIMEOUT_MS); } @Override boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WAITING_FOR_RECORD_STATUS) { + if (mState != STATE_WAITING_FOR_RECORD_STATUS || mRecorderAddress != cmd.getSource()) { return false; } switch (cmd.getOpcode()) { case Constants.MESSAGE_RECORD_STATUS: return handleRecordStatus(cmd); - } return false; } diff --git a/services/core/java/com/android/server/hdmi/SendKeyAction.java b/services/core/java/com/android/server/hdmi/SendKeyAction.java index ed978e0..eef5010 100644 --- a/services/core/java/com/android/server/hdmi/SendKeyAction.java +++ b/services/core/java/com/android/server/hdmi/SendKeyAction.java @@ -15,7 +15,7 @@ */ package com.android.server.hdmi; -import static com.android.server.hdmi.Constants.IRT_MS; +import static com.android.server.hdmi.HdmiConfig.IRT_MS; import android.util.Slog; import android.view.KeyEvent; @@ -35,6 +35,11 @@ import android.view.KeyEvent; final class SendKeyAction extends HdmiCecFeatureAction { private static final String TAG = "SendKeyAction"; + // Amount of time this action waits for a new release key input event. When timed out, + // the action sends out UCR and finishes its lifecycle. Used to deal with missing key release + // event, which can lead the device on the receiving end to generating unintended key repeats. + private static final int AWAIT_RELEASE_KEY_MS = 1000; + // State in which the action is at work. The state is set in {@link #start()} and // persists throughout the process till it is set back to {@code STATE_NONE} at the end. private static final int STATE_PROCESSING_KEYCODE = 1; @@ -45,6 +50,10 @@ final class SendKeyAction extends HdmiCecFeatureAction { // The key code of the last key press event the action is passed via processKeyEvent. private int mLastKeycode; + // The time stamp when the last CEC key command was sent. Used to determine the press-and-hold + // operation. + private long mLastSendKeyTime; + /** * Constructor. * @@ -61,6 +70,7 @@ final class SendKeyAction extends HdmiCecFeatureAction { @Override public boolean start() { sendKeyDown(mLastKeycode); + mLastSendKeyTime = getCurrentTime(); // finish action for non-repeatable key. if (!HdmiCecKeycode.isRepeatableKey(mLastKeycode)) { sendKeyUp(); @@ -68,10 +78,14 @@ final class SendKeyAction extends HdmiCecFeatureAction { return true; } mState = STATE_PROCESSING_KEYCODE; - addTimer(mState, IRT_MS); + addTimer(mState, AWAIT_RELEASE_KEY_MS); return true; } + private long getCurrentTime() { + return System.currentTimeMillis(); + } + /** * Called when a key event should be handled for the action. * @@ -83,24 +97,32 @@ final class SendKeyAction extends HdmiCecFeatureAction { Slog.w(TAG, "Not in a valid state"); return; } - // A new key press event that comes in with a key code different from the last - // one sets becomes a new key code to be used for press-and-hold operation. - // Removes any pending timer and starts a new timer for itself. - // Key release event indicates that the action shall be finished. Send UCR - // command and terminate the action. Other release events are ignored. if (isPressed) { + // A new key press event that comes in with a key code different from the last + // one becomes a new key code to be used for press-and-hold operation. if (keycode != mLastKeycode) { sendKeyDown(keycode); + mLastSendKeyTime = getCurrentTime(); if (!HdmiCecKeycode.isRepeatableKey(keycode)) { sendKeyUp(); finish(); return; } - mActionTimer.clearTimerMessage(); - addTimer(mState, IRT_MS); - mLastKeycode = keycode; + } else { + // Press-and-hold key transmission takes place if Android key inputs are + // repeatedly coming in and more than IRT_MS has passed since the last + // press-and-hold key transmission. + if (getCurrentTime() - mLastSendKeyTime >= IRT_MS) { + sendKeyDown(keycode); + mLastSendKeyTime = getCurrentTime(); + } } + mActionTimer.clearTimerMessage(); + addTimer(mState, AWAIT_RELEASE_KEY_MS); + mLastKeycode = keycode; } else { + // Key release event indicates that the action shall be finished. Send UCR + // command and terminate the action. Other release events are ignored. if (keycode == mLastKeycode) { sendKeyUp(); finish(); @@ -109,12 +131,12 @@ final class SendKeyAction extends HdmiCecFeatureAction { } private void sendKeyDown(int keycode) { - int cecKeycode = HdmiCecKeycode.androidKeyToCecKey(keycode); - if (cecKeycode == HdmiCecKeycode.UNSUPPORTED_KEYCODE) { + byte[] cecKeycodeAndParams = HdmiCecKeycode.androidKeyToCecKey(keycode); + if (cecKeycodeAndParams == null) { return; } sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(), - mTargetAddress, new byte[] { (byte) (cecKeycode & 0xFF) })); + mTargetAddress, cecKeycodeAndParams)); } private void sendKeyUp() { @@ -130,15 +152,12 @@ final class SendKeyAction extends HdmiCecFeatureAction { @Override public void handleTimerEvent(int state) { - // Timer event occurs every IRT_MS milliseconds to perform key-repeat (or press-and-hold) - // operation. If the last received key code is as same as the one with which the action - // is started, plus there was no key release event in last IRT_MS timeframe, send a UCP - // command and start another timer to schedule the next press-and-hold command. + // Timeout on waiting for the release key event. Send UCR and quit the action. if (mState != STATE_PROCESSING_KEYCODE) { Slog.w(TAG, "Not in a valid state"); return; } - sendKeyDown(mLastKeycode); - addTimer(mState, IRT_MS); + sendKeyUp(); + finish(); } } diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java index 0871194..6023354 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java @@ -125,6 +125,9 @@ abstract class SystemAudioAction extends HdmiCecFeatureAction { @Override final boolean processCommand(HdmiCecMessage cmd) { + if (cmd.getSource() != mAvrLogicalAddress) { + return false; + } switch (mState) { case STATE_WAIT_FOR_SET_SYSTEM_AUDIO_MODE: if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java index 3653aac..50f8475 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioAutoInitiationAction.java @@ -58,17 +58,16 @@ final class SystemAudioAutoInitiationAction extends HdmiCecFeatureAction { @Override boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS) { + if (mState != STATE_WAITING_FOR_SYSTEM_AUDIO_MODE_STATUS + || mAvrAddress != cmd.getSource()) { return false; } - switch (cmd.getOpcode()) { - case Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS: - handleSystemAudioModeStatusMessage(); - return true; - default: - return false; + if (cmd.getOpcode() == Constants.MESSAGE_SYSTEM_AUDIO_MODE_STATUS) { + handleSystemAudioModeStatusMessage(); + return true; } + return false; } private void handleSystemAudioModeStatusMessage() { diff --git a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java index bfcda50..dba3591 100644 --- a/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java +++ b/services/core/java/com/android/server/hdmi/SystemAudioStatusAction.java @@ -79,7 +79,7 @@ final class SystemAudioStatusAction extends HdmiCecFeatureAction { @Override boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS) { + if (mState != STATE_WAIT_FOR_REPORT_AUDIO_STATUS || mAvrAddress != cmd.getSource()) { return false; } diff --git a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java index 8fc0182..5fcbc91 100644 --- a/services/core/java/com/android/server/hdmi/TimerRecordingAction.java +++ b/services/core/java/com/android/server/hdmi/TimerRecordingAction.java @@ -96,11 +96,8 @@ public class TimerRecordingAction extends HdmiCecFeatureAction { @Override boolean processCommand(HdmiCecMessage cmd) { - if (mState != STATE_WAITING_FOR_TIMER_STATUS) { - return false; - } - - if (cmd.getSource() != mRecorderAddress) { + if (mState != STATE_WAITING_FOR_TIMER_STATUS + || cmd.getSource() != mRecorderAddress) { return false; } diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java index 4338fc7..cd38b1f 100644 --- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java +++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java @@ -16,10 +16,10 @@ package com.android.server.hdmi; -import static com.android.server.hdmi.Constants.IRT_MS; import static com.android.server.hdmi.Constants.MESSAGE_FEATURE_ABORT; import static com.android.server.hdmi.Constants.MESSAGE_REPORT_AUDIO_STATUS; import static com.android.server.hdmi.Constants.MESSAGE_USER_CONTROL_PRESSED; +import static com.android.server.hdmi.HdmiConfig.IRT_MS; import android.media.AudioManager; @@ -45,6 +45,7 @@ final class VolumeControlAction extends HdmiCecFeatureAction { private boolean mIsVolumeUp; private long mLastKeyUpdateTime; private int mLastAvrVolume; + private boolean mLastAvrMute; private boolean mSentKeyPressed; /** @@ -74,6 +75,7 @@ final class VolumeControlAction extends HdmiCecFeatureAction { mAvrAddress = avrAddress; mIsVolumeUp = isVolumeUp; mLastAvrVolume = UNKNOWN_AVR_VOLUME; + mLastAvrMute = false; mSentKeyPressed = false; updateLastKeyUpdateTime(); @@ -108,6 +110,8 @@ final class VolumeControlAction extends HdmiCecFeatureAction { HdmiLogger.debug("Volume Key Status Changed[old:%b new:%b]", mIsVolumeUp, isVolumeUp); sendVolumeKeyReleased(); mIsVolumeUp = isVolumeUp; + sendVolumeKeyPressed(); + resetTimer(); } updateLastKeyUpdateTime(); } @@ -129,9 +133,8 @@ final class VolumeControlAction extends HdmiCecFeatureAction { return handleReportAudioStatus(cmd); case MESSAGE_FEATURE_ABORT: return handleFeatureAbort(cmd); - default: - return false; } + return false; } private boolean handleReportAudioStatus(HdmiCecMessage cmd) { @@ -139,9 +142,12 @@ final class VolumeControlAction extends HdmiCecFeatureAction { boolean mute = (params[0] & 0x80) == 0x80; int volume = params[0] & 0x7F; mLastAvrVolume = volume; + mLastAvrMute = mute; if (shouldUpdateAudioVolume(mute)) { HdmiLogger.debug("Force volume change[mute:%b, volume=%d]", mute, volume); tv().setAudioStatus(mute, volume); + mLastAvrVolume = UNKNOWN_AVR_VOLUME; + mLastAvrMute = false; } return true; } @@ -182,8 +188,9 @@ final class VolumeControlAction extends HdmiCecFeatureAction { sendVolumeKeyReleased(); } if (mLastAvrVolume != UNKNOWN_AVR_VOLUME) { - tv().setAudioStatus(false, mLastAvrVolume); + tv().setAudioStatus(mLastAvrMute, mLastAvrVolume); mLastAvrVolume = UNKNOWN_AVR_VOLUME; + mLastAvrMute = false; } } diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java index c6d2db2..83d6986 100644 --- a/services/core/java/com/android/server/job/JobSchedulerService.java +++ b/services/core/java/com/android/server/job/JobSchedulerService.java @@ -137,11 +137,15 @@ public class JobSchedulerService extends com.android.server.SystemService public void onReceive(Context context, Intent intent) { Slog.d(TAG, "Receieved: " + intent.getAction()); if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { - int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1); - if (DEBUG) { - Slog.d(TAG, "Removing jobs for uid: " + uidRemoved); + // If this is an outright uninstall rather than the first half of an + // app update sequence, cancel the jobs associated with the app. + if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + int uidRemoved = intent.getIntExtra(Intent.EXTRA_UID, -1); + if (DEBUG) { + Slog.d(TAG, "Removing jobs for uid: " + uidRemoved); + } + cancelJobsForUid(uidRemoved); } - cancelJobsForUid(uidRemoved); } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) { final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0); if (DEBUG) { diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java index cdfb656..e9b3f8b 100644 --- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java +++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java @@ -91,7 +91,8 @@ public final class MediaProjectionManagerService extends SystemService public void onStart() { publishBinderService(Context.MEDIA_PROJECTION_SERVICE, new BinderService(), false /*allowIsolated*/); - mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback); + mMediaRouter.addCallback(MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY, mMediaRouterCallback, + MediaRouter.CALLBACK_FLAG_PASSIVE_DISCOVERY); } @Override @@ -325,7 +326,7 @@ public final class MediaProjectionManagerService extends SystemService final long token = Binder.clearCallingIdentity(); try { - dump(pw); + MediaProjectionManagerService.this.dump(pw); } finally { Binder.restoreCallingIdentity(token); } diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index b5aa4d8..150ad34 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -45,7 +45,6 @@ import static android.provider.Settings.Global.NETSTATS_DEV_PERSIST_BYTES; import static android.provider.Settings.Global.NETSTATS_DEV_ROTATE_AGE; import static android.provider.Settings.Global.NETSTATS_GLOBAL_ALERT_BYTES; import static android.provider.Settings.Global.NETSTATS_POLL_INTERVAL; -import static android.provider.Settings.Global.NETSTATS_REPORT_XT_OVER_DEV; import static android.provider.Settings.Global.NETSTATS_SAMPLE_ENABLED; import static android.provider.Settings.Global.NETSTATS_TIME_CACHE_MAX_AGE; import static android.provider.Settings.Global.NETSTATS_UID_BUCKET_DURATION; @@ -184,7 +183,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { public long getPollInterval(); public long getTimeCacheMaxAge(); public boolean getSampleEnabled(); - public boolean getReportXtOverDev(); public static class Config { public final long bucketDuration; @@ -229,8 +227,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { private NetworkStatsRecorder mUidRecorder; private NetworkStatsRecorder mUidTagRecorder; - /** Cached {@link #mDevRecorder} stats. */ - private NetworkStatsCollection mDevStatsCached; /** Cached {@link #mXtRecorder} stats. */ private NetworkStatsCollection mXtStatsCached; @@ -305,7 +301,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // read historical network stats from disk, since policy service // might need them right away. - mDevStatsCached = mDevRecorder.getOrLoadCompleteLocked(); mXtStatsCached = mXtRecorder.getOrLoadCompleteLocked(); // bootstrap initial stats to prevent double-counting later @@ -386,7 +381,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { mUidRecorder = null; mUidTagRecorder = null; - mDevStatsCached = null; mXtStatsCached = null; mSystemReady = false; @@ -523,48 +517,24 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } /** - * Return network summary, splicing between {@link #mDevStatsCached} - * and {@link #mXtStatsCached} when appropriate. + * Return network summary, splicing between DEV and XT stats when + * appropriate. */ private NetworkStats internalGetSummaryForNetwork( NetworkTemplate template, long start, long end) { - if (!mSettings.getReportXtOverDev()) { - // shortcut when XT reporting disabled - return mDevStatsCached.getSummary(template, start, end); - } - - // splice stats between DEV and XT, switching over from DEV to XT at - // first atomic bucket. - final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis(); - final NetworkStats dev = mDevStatsCached.getSummary( - template, Math.min(start, firstAtomicBucket), Math.min(end, firstAtomicBucket)); - final NetworkStats xt = mXtStatsCached.getSummary( - template, Math.max(start, firstAtomicBucket), Math.max(end, firstAtomicBucket)); - - xt.combineAllValues(dev); - return xt; + // We've been using pure XT stats long enough that we no longer need to + // splice DEV and XT together. + return mXtStatsCached.getSummary(template, start, end); } /** - * Return network history, splicing between {@link #mDevStatsCached} - * and {@link #mXtStatsCached} when appropriate. + * Return network history, splicing between DEV and XT stats when + * appropriate. */ private NetworkStatsHistory internalGetHistoryForNetwork(NetworkTemplate template, int fields) { - if (!mSettings.getReportXtOverDev()) { - // shortcut when XT reporting disabled - return mDevStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); - } - - // splice stats between DEV and XT, switching over from DEV to XT at - // first atomic bucket. - final long firstAtomicBucket = mXtStatsCached.getFirstAtomicBucketMillis(); - final NetworkStatsHistory dev = mDevStatsCached.getHistory( - template, UID_ALL, SET_ALL, TAG_NONE, fields, Long.MIN_VALUE, firstAtomicBucket); - final NetworkStatsHistory xt = mXtStatsCached.getHistory( - template, UID_ALL, SET_ALL, TAG_NONE, fields, firstAtomicBucket, Long.MAX_VALUE); - - xt.recordEntireHistory(dev); - return xt; + // We've been using pure XT stats long enough that we no longer need to + // splice DEV and XT together. + return mXtStatsCached.getHistory(template, UID_ALL, SET_ALL, TAG_NONE, fields); } @Override @@ -1329,10 +1299,6 @@ public class NetworkStatsService extends INetworkStatsService.Stub { return getGlobalBoolean(NETSTATS_SAMPLE_ENABLED, true); } @Override - public boolean getReportXtOverDev() { - return getGlobalBoolean(NETSTATS_REPORT_XT_OVER_DEV, true); - } - @Override public Config getDevConfig() { return new Config(getGlobalLong(NETSTATS_DEV_BUCKET_DURATION, HOUR_IN_MILLIS), getGlobalLong(NETSTATS_DEV_ROTATE_AGE, 15 * DAY_IN_MILLIS), diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java index 97f0a1e..24fc455 100644 --- a/services/core/java/com/android/server/notification/NotificationDelegate.java +++ b/services/core/java/com/android/server/notification/NotificationDelegate.java @@ -20,6 +20,7 @@ public interface NotificationDelegate { void onSetDisabled(int status); void onClearAll(int callingUid, int callingPid, int userId); void onNotificationClick(int callingUid, int callingPid, String key); + void onNotificationActionClick(int callingUid, int callingPid, String key, int actionIndex); void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId); void onNotificationError(int callingUid, int callingPid, diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 22f060f..e9d19aa 100644 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -541,6 +541,20 @@ public class NotificationManagerService extends SystemService { } @Override + public void onNotificationActionClick(int callingUid, int callingPid, String key, + int actionIndex) { + synchronized (mNotificationList) { + EventLogTags.writeNotificationActionClicked(key, actionIndex); + NotificationRecord r = mNotificationsByKey.get(key); + if (r == null) { + Log.w(TAG, "No notification with key: " + key); + return; + } + // TODO: Log action click via UsageStats. + } + } + + @Override public void onNotificationClear(int callingUid, int callingPid, String pkg, String tag, int id, int userId) { cancelNotification(callingUid, callingPid, pkg, tag, id, 0, @@ -1698,14 +1712,6 @@ public class NotificationManagerService extends SystemService { } } - // This conditional is a dirty hack to limit the logging done on - // behalf of the download manager without affecting other apps. - if (!pkg.equals("com.android.providers.downloads") - || Log.isLoggable("DownloadManager", Log.VERBOSE)) { - EventLogTags.writeNotificationEnqueue(callingUid, callingPid, - pkg, id, tag, userId, notification.toString()); - } - if (pkg == null || notification == null) { throw new IllegalArgumentException("null not allowed: pkg=" + pkg + " id=" + id + " notification=" + notification); @@ -1755,6 +1761,14 @@ public class NotificationManagerService extends SystemService { } mRankingHelper.extractSignals(r); + // This conditional is a dirty hack to limit the logging done on + // behalf of the download manager without affecting other apps. + if (!pkg.equals("com.android.providers.downloads") + || Log.isLoggable("DownloadManager", Log.VERBOSE)) { + EventLogTags.writeNotificationEnqueue(callingUid, callingPid, + pkg, id, tag, userId, notification.toString(), + (old != null) ? 1 : 0); + } // 3. Apply local rules // blocked apps @@ -2358,6 +2372,8 @@ public class NotificationManagerService extends SystemService { // Save it for users of getHistoricalNotifications() mArchive.record(r.sbn); + + EventLogTags.writeNotificationCanceled(r.getKey(), reason); } /** diff --git a/services/core/java/com/android/server/notification/ZenLog.java b/services/core/java/com/android/server/notification/ZenLog.java index 6cc5e0e..e0b83de 100644 --- a/services/core/java/com/android/server/notification/ZenLog.java +++ b/services/core/java/com/android/server/notification/ZenLog.java @@ -34,6 +34,7 @@ import java.util.Date; public class ZenLog { private static final String TAG = "ZenLog"; + private static final boolean DEBUG = Build.IS_DEBUGGABLE; private static final int SIZE = Build.IS_DEBUGGABLE ? 100 : 20; @@ -166,7 +167,7 @@ public class ZenLog { sSize++; } } - Slog.d(TAG, typeToString(type) + ": " + msg); + if (DEBUG) Slog.d(TAG, typeToString(type) + ": " + msg); } public static void dump(PrintWriter pw, String prefix) { diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java index a7eebf8..cb9a45e 100644 --- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java +++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java @@ -23,9 +23,9 @@ import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.os.ServiceManager; +import android.util.ArraySet; import android.util.Log; -import java.util.HashSet; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -59,7 +59,7 @@ public class BackgroundDexOptService extends JobService { if (pm.isStorageLow()) { return false; } - final HashSet<String> pkgs = pm.getPackagesThatNeedDexOpt(); + final ArraySet<String> pkgs = pm.getPackagesThatNeedDexOpt(); if (pkgs == null) { return false; } diff --git a/services/core/java/com/android/server/pm/GrantedPermissions.java b/services/core/java/com/android/server/pm/GrantedPermissions.java index 14258a4..8f0f935 100644 --- a/services/core/java/com/android/server/pm/GrantedPermissions.java +++ b/services/core/java/com/android/server/pm/GrantedPermissions.java @@ -17,13 +17,12 @@ package com.android.server.pm; import android.content.pm.ApplicationInfo; - -import java.util.HashSet; +import android.util.ArraySet; class GrantedPermissions { int pkgFlags; - HashSet<String> grantedPermissions = new HashSet<String>(); + ArraySet<String> grantedPermissions = new ArraySet<String>(); int[] gids; @@ -34,7 +33,7 @@ class GrantedPermissions { @SuppressWarnings("unchecked") GrantedPermissions(GrantedPermissions base) { pkgFlags = base.pkgFlags; - grantedPermissions = (HashSet<String>) base.grantedPermissions.clone(); + grantedPermissions = new ArraySet<>(base.grantedPermissions); if (base.gids != null) { gids = base.gids.clone(); diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java index 9f9bafd..8f12c03 100644 --- a/services/core/java/com/android/server/pm/PackageKeySetData.java +++ b/services/core/java/com/android/server/pm/PackageKeySetData.java @@ -16,10 +16,9 @@ package com.android.server.pm; -import com.android.internal.util.ArrayUtils; +import android.util.ArrayMap; -import java.util.HashMap; -import java.util.Map; +import com.android.internal.util.ArrayUtils; public class PackageKeySetData { @@ -34,7 +33,7 @@ public class PackageKeySetData { private long[] mDefinedKeySets; - private final Map<String, Long> mKeySetAliases = new HashMap<String, Long>(); + private final ArrayMap<String, Long> mKeySetAliases = new ArrayMap<String, Long>(); PackageKeySetData() { mProperSigningKeySet = KEYSET_UNASSIGNED; @@ -132,7 +131,7 @@ public class PackageKeySetData { return mDefinedKeySets; } - protected Map<String, Long> getAliases() { + protected ArrayMap<String, Long> getAliases() { return mKeySetAliases; } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index b79e157..de6e82b 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -84,6 +84,8 @@ import android.app.AppGlobals; import android.app.IActivityManager; import android.app.admin.IDevicePolicyManager; import android.app.backup.IBackupManager; +import android.app.usage.UsageStats; +import android.app.usage.UsageStatsManager; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; @@ -199,8 +201,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -329,6 +329,7 @@ public class PackageManagerService extends IPackageManager.Stub { final boolean mFactoryTest; final boolean mOnlyCore; final boolean mLazyDexOpt; + final long mDexOptLRUThresholdInMills; final DisplayMetrics mMetrics; final int mDefParseFlags; final String[] mSeparateProcesses; @@ -371,20 +372,20 @@ public class PackageManagerService extends IPackageManager.Stub { // Keys are String (package name), values are Package. This also serves // as the lock for the global state. Methods that must be called with // this lock held have the prefix "LP". - final HashMap<String, PackageParser.Package> mPackages = - new HashMap<String, PackageParser.Package>(); + final ArrayMap<String, PackageParser.Package> mPackages = + new ArrayMap<String, PackageParser.Package>(); // Tracks available target package names -> overlay package paths. - final HashMap<String, HashMap<String, PackageParser.Package>> mOverlays = - new HashMap<String, HashMap<String, PackageParser.Package>>(); + final ArrayMap<String, ArrayMap<String, PackageParser.Package>> mOverlays = + new ArrayMap<String, ArrayMap<String, PackageParser.Package>>(); final Settings mSettings; boolean mRestoredSettings; // System configuration read by SystemConfig. final int[] mGlobalGids; - final SparseArray<HashSet<String>> mSystemPermissions; - final HashMap<String, FeatureInfo> mAvailableFeatures; + final SparseArray<ArraySet<String>> mSystemPermissions; + final ArrayMap<String, FeatureInfo> mAvailableFeatures; // If mac_permissions.xml was found for seinfo labeling. boolean mFoundPolicyFile; @@ -403,8 +404,8 @@ public class PackageManagerService extends IPackageManager.Stub { } // Currently known shared libraries. - final HashMap<String, SharedLibraryEntry> mSharedLibraries = - new HashMap<String, SharedLibraryEntry>(); + final ArrayMap<String, SharedLibraryEntry> mSharedLibraries = + new ArrayMap<String, SharedLibraryEntry>(); // All available activities, for your resolving pleasure. final ActivityIntentResolver mActivities = @@ -422,23 +423,23 @@ public class PackageManagerService extends IPackageManager.Stub { // Mapping from provider base names (first directory in content URI codePath) // to the provider information. - final HashMap<String, PackageParser.Provider> mProvidersByAuthority = - new HashMap<String, PackageParser.Provider>(); + final ArrayMap<String, PackageParser.Provider> mProvidersByAuthority = + new ArrayMap<String, PackageParser.Provider>(); // Mapping from instrumentation class names to info about them. - final HashMap<ComponentName, PackageParser.Instrumentation> mInstrumentation = - new HashMap<ComponentName, PackageParser.Instrumentation>(); + final ArrayMap<ComponentName, PackageParser.Instrumentation> mInstrumentation = + new ArrayMap<ComponentName, PackageParser.Instrumentation>(); // Mapping from permission names to info about them. - final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups = - new HashMap<String, PackageParser.PermissionGroup>(); + final ArrayMap<String, PackageParser.PermissionGroup> mPermissionGroups = + new ArrayMap<String, PackageParser.PermissionGroup>(); // Packages whose data we have transfered into another package, thus // should no longer exist. - final HashSet<String> mTransferedPackages = new HashSet<String>(); + final ArraySet<String> mTransferedPackages = new ArraySet<String>(); // Broadcast actions that are only available to the system. - final HashSet<String> mProtectedBroadcasts = new HashSet<String>(); + final ArraySet<String> mProtectedBroadcasts = new ArraySet<String>(); /** List of packages waiting for verification. */ final SparseArray<PackageVerificationState> mPendingVerification @@ -449,7 +450,7 @@ public class PackageManagerService extends IPackageManager.Stub { final PackageInstallerService mInstallerService; - HashSet<PackageParser.Package> mDeferredDexOpt = null; + ArraySet<PackageParser.Package> mDeferredDexOpt = null; // Cache of users who need badging. SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray(); @@ -473,24 +474,24 @@ public class PackageManagerService extends IPackageManager.Stub { // 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> - final SparseArray<HashMap<String, ArrayList<String>>> mUidMap; + final SparseArray<ArrayMap<String, ArrayList<String>>> mUidMap; public PendingPackageBroadcasts() { - mUidMap = new SparseArray<HashMap<String, ArrayList<String>>>(2); + mUidMap = new SparseArray<ArrayMap<String, ArrayList<String>>>(2); } public ArrayList<String> get(int userId, String packageName) { - HashMap<String, ArrayList<String>> packages = getOrAllocate(userId); + ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId); return packages.get(packageName); } public void put(int userId, String packageName, ArrayList<String> components) { - HashMap<String, ArrayList<String>> packages = getOrAllocate(userId); + ArrayMap<String, ArrayList<String>> packages = getOrAllocate(userId); packages.put(packageName, components); } public void remove(int userId, String packageName) { - HashMap<String, ArrayList<String>> packages = mUidMap.get(userId); + ArrayMap<String, ArrayList<String>> packages = mUidMap.get(userId); if (packages != null) { packages.remove(packageName); } @@ -508,7 +509,7 @@ public class PackageManagerService extends IPackageManager.Stub { return mUidMap.keyAt(n); } - public HashMap<String, ArrayList<String>> packagesForUserId(int userId) { + public ArrayMap<String, ArrayList<String>> packagesForUserId(int userId) { return mUidMap.get(userId); } @@ -525,10 +526,10 @@ public class PackageManagerService extends IPackageManager.Stub { mUidMap.clear(); } - private HashMap<String, ArrayList<String>> getOrAllocate(int userId) { - HashMap<String, ArrayList<String>> map = mUidMap.get(userId); + private ArrayMap<String, ArrayList<String>> getOrAllocate(int userId) { + ArrayMap<String, ArrayList<String>> map = mUidMap.get(userId); if (map == null) { - map = new HashMap<String, ArrayList<String>>(); + map = new ArrayMap<String, ArrayList<String>>(); mUidMap.put(userId, map); } return map; @@ -565,7 +566,7 @@ public class PackageManagerService extends IPackageManager.Stub { static UserManagerService sUserManager; // Stores a list of users whose package restrictions file needs to be updated - private HashSet<Integer> mDirtyUsers = new HashSet<Integer>(); + private ArraySet<Integer> mDirtyUsers = new ArraySet<Integer>(); final private DefaultContainerConnection mDefContainerConn = new DefaultContainerConnection(); @@ -1294,6 +1295,15 @@ public class PackageManagerService extends IPackageManager.Stub { mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM|ApplicationInfo.FLAG_PRIVILEGED); + // TODO: add a property to control this? + long dexOptLRUThresholdInMinutes; + if (mLazyDexOpt) { + dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds. + } else { + dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users. + } + mDexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000; + String separateProcesses = SystemProperties.get("debug.separate_processes"); if (separateProcesses != null && separateProcesses.length() > 0) { if ("*".equals(separateProcesses)) { @@ -1384,7 +1394,7 @@ public class PackageManagerService extends IPackageManager.Stub { // scanning install directories. final int scanFlags = SCAN_NO_PATHS | SCAN_DEFER_DEX | SCAN_BOOTING; - final HashSet<String> alreadyDexOpted = new HashSet<String>(); + final ArraySet<String> alreadyDexOpted = new ArraySet<String>(); /** * Add everything in the in the boot class path to the @@ -2369,7 +2379,7 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.PERMISSION_GRANTED; } } else { - HashSet<String> perms = mSystemPermissions.get(uid); + ArraySet<String> perms = mSystemPermissions.get(uid); if (perms != null && perms.contains(permName)) { return PackageManager.PERMISSION_GRANTED; } @@ -2790,11 +2800,11 @@ public class PackageManagerService extends IPackageManager.Stub { PackageManager.SIGNATURE_NO_MATCH; } - HashSet<Signature> set1 = new HashSet<Signature>(); + ArraySet<Signature> set1 = new ArraySet<Signature>(); for (Signature sig : s1) { set1.add(sig); } - HashSet<Signature> set2 = new HashSet<Signature>(); + ArraySet<Signature> set2 = new ArraySet<Signature>(); for (Signature sig : s2) { set2.add(sig); } @@ -2829,11 +2839,11 @@ public class PackageManagerService extends IPackageManager.Stub { return PackageManager.SIGNATURE_NO_MATCH; } - HashSet<Signature> existingSet = new HashSet<Signature>(); + ArraySet<Signature> existingSet = new ArraySet<Signature>(); for (Signature sig : existingSigs.mSignatures) { existingSet.add(sig); } - HashSet<Signature> scannedCompatSet = new HashSet<Signature>(); + ArraySet<Signature> scannedCompatSet = new ArraySet<Signature>(); for (Signature sig : scannedPkg.mSignatures) { try { Signature[] chainSignatures = sig.getChainSignatures(); @@ -4023,7 +4033,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private void createIdmapsForPackageLI(PackageParser.Package pkg) { - HashMap<String, PackageParser.Package> overlays = mOverlays.get(pkg.packageName); + ArrayMap<String, PackageParser.Package> overlays = mOverlays.get(pkg.packageName); if (overlays == null) { Slog.w(TAG, "Unable to create idmap for " + pkg.packageName + ": no overlay packages"); return; @@ -4044,7 +4054,7 @@ public class PackageManagerService extends IPackageManager.Stub { opkg.baseCodePath + ": overlay not trusted"); return false; } - HashMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName); + ArrayMap<String, PackageParser.Package> overlaySet = mOverlays.get(pkg.packageName); if (overlaySet == null) { Slog.e(TAG, "was about to create idmap for " + pkg.baseCodePath + " and " + opkg.baseCodePath + " but target package has no known overlays"); @@ -4465,7 +4475,7 @@ public class PackageManagerService extends IPackageManager.Stub { public void performBootDexOpt() { enforceSystemOrRoot("Only the system can request dexopt be performed"); - final HashSet<PackageParser.Package> pkgs; + final ArraySet<PackageParser.Package> pkgs; synchronized (mPackages) { pkgs = mDeferredDexOpt; mDeferredDexOpt = null; @@ -4488,7 +4498,7 @@ public class PackageManagerService extends IPackageManager.Stub { } // Give priority to system apps that listen for pre boot complete. Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); - HashSet<String> pkgNames = getPackageNamesForIntent(intent); + ArraySet<String> pkgNames = getPackageNamesForIntent(intent); for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) { PackageParser.Package pkg = it.next(); if (pkgNames.contains(pkg.packageName)) { @@ -4562,28 +4572,19 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private void filterRecentlyUsedApps(HashSet<PackageParser.Package> pkgs) { + private void filterRecentlyUsedApps(ArraySet<PackageParser.Package> pkgs) { // Filter out packages that aren't recently used. // // The exception is first boot of a non-eng device (aka !mLazyDexOpt), which // should do a full dexopt. if (mLazyDexOpt || (!isFirstBoot() && mPackageUsage.isHistoricalPackageUsageAvailable())) { - // TODO: add a property to control this? - long dexOptLRUThresholdInMinutes; - if (mLazyDexOpt) { - dexOptLRUThresholdInMinutes = 30; // only last 30 minutes of apps for eng builds. - } else { - dexOptLRUThresholdInMinutes = 7 * 24 * 60; // apps used in the 7 days for users. - } - long dexOptLRUThresholdInMills = dexOptLRUThresholdInMinutes * 60 * 1000; - int total = pkgs.size(); int skipped = 0; long now = System.currentTimeMillis(); for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) { PackageParser.Package pkg = i.next(); long then = pkg.mLastPackageUsageTimeInMills; - if (then + dexOptLRUThresholdInMills < now) { + if (then + mDexOptLRUThresholdInMills < now) { if (DEBUG_DEXOPT) { Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " + ((then == 0) ? "never" : new Date(then))); @@ -4598,14 +4599,14 @@ public class PackageManagerService extends IPackageManager.Stub { } } - private HashSet<String> getPackageNamesForIntent(Intent intent) { + private ArraySet<String> getPackageNamesForIntent(Intent intent) { List<ResolveInfo> ris = null; try { ris = AppGlobals.getPackageManager().queryIntentReceivers( intent, null, 0, UserHandle.USER_OWNER); } catch (RemoteException e) { } - HashSet<String> pkgNames = new HashSet<String>(); + ArraySet<String> pkgNames = new ArraySet<String>(); if (ris != null) { for (ResolveInfo ri : ris) { pkgNames.add(ri.activityInfo.packageName); @@ -4683,8 +4684,8 @@ public class PackageManagerService extends IPackageManager.Stub { } } - public HashSet<String> getPackagesThatNeedDexOpt() { - HashSet<String> pkgs = null; + public ArraySet<String> getPackagesThatNeedDexOpt() { + ArraySet<String> pkgs = null; synchronized (mPackages) { for (PackageParser.Package p : mPackages.values()) { if (DEBUG_DEXOPT) { @@ -4694,7 +4695,7 @@ public class PackageManagerService extends IPackageManager.Stub { continue; } if (pkgs == null) { - pkgs = new HashSet<String>(); + pkgs = new ArraySet<String>(); } pkgs.add(p.packageName); } @@ -4707,7 +4708,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets, - boolean forceDex, boolean defer, HashSet<String> done) { + boolean forceDex, boolean defer, ArraySet<String> done) { for (int i=0; i<libs.size(); i++) { PackageParser.Package libPkg; String libName; @@ -4732,7 +4733,7 @@ public class PackageManagerService extends IPackageManager.Stub { static final int DEX_OPT_FAILED = -1; private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets, - boolean forceDex, boolean defer, HashSet<String> done) { + boolean forceDex, boolean defer, ArraySet<String> done) { final String[] instructionSets = targetInstructionSets != null ? targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo); @@ -4810,7 +4811,7 @@ public class PackageManagerService extends IPackageManager.Stub { // our list of deferred dexopts. if (defer && isDexOptNeeded != DexFile.UP_TO_DATE) { if (mDeferredDexOpt == null) { - mDeferredDexOpt = new HashSet<PackageParser.Package>(); + mDeferredDexOpt = new ArraySet<PackageParser.Package>(); } mDeferredDexOpt.add(pkg); return DEX_OPT_DEFERRED; @@ -4907,7 +4908,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private static String[] getDexCodeInstructionSets(String[] instructionSets) { - HashSet<String> dexCodeInstructionSets = new HashSet<String>(instructionSets.length); + ArraySet<String> dexCodeInstructionSets = new ArraySet<String>(instructionSets.length); for (String instructionSet : instructionSets) { dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet)); } @@ -4950,9 +4951,9 @@ public class PackageManagerService extends IPackageManager.Stub { private int performDexOptLI(PackageParser.Package pkg, String[] instructionSets, boolean forceDex, boolean defer, boolean inclDependencies) { - HashSet<String> done; + ArraySet<String> done; if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) { - done = new HashSet<String>(); + done = new ArraySet<String>(); done.add(pkg.packageName); } else { done = null; @@ -6137,7 +6138,7 @@ public class PackageManagerService extends IPackageManager.Stub { r = null; for (i=0; i<N; i++) { PackageParser.Permission p = pkg.permissions.get(i); - HashMap<String, BasePermission> permissionMap = + ArrayMap<String, BasePermission> permissionMap = p.tree ? mSettings.mPermissionTrees : mSettings.mPermissions; p.group = mPermissionGroups.get(p.info.group); @@ -6265,9 +6266,9 @@ public class PackageManagerService extends IPackageManager.Stub { if (pkg.mOverlayTarget != null && !pkg.mOverlayTarget.equals("android")) { if (!mOverlays.containsKey(pkg.mOverlayTarget)) { mOverlays.put(pkg.mOverlayTarget, - new HashMap<String, PackageParser.Package>()); + new ArrayMap<String, PackageParser.Package>()); } - HashMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget); + ArrayMap<String, PackageParser.Package> map = mOverlays.get(pkg.mOverlayTarget); map.put(pkg.packageName, pkg); PackageParser.Package orig = mPackages.get(pkg.mOverlayTarget); if (orig != null && !createIdmapForPackagePairLI(orig, pkg)) { @@ -6928,13 +6929,13 @@ public class PackageManagerService extends IPackageManager.Stub { return; } final GrantedPermissions gp = ps.sharedUser != null ? ps.sharedUser : ps; - HashSet<String> origPermissions = gp.grantedPermissions; + ArraySet<String> origPermissions = gp.grantedPermissions; boolean changedPermission = false; if (replace) { ps.permissionsFixed = false; if (gp == ps) { - origPermissions = new HashSet<String>(gp.grantedPermissions); + origPermissions = new ArraySet<String>(gp.grantedPermissions); gp.grantedPermissions.clear(); gp.gids = mGlobalGids; } @@ -7081,7 +7082,7 @@ public class PackageManagerService extends IPackageManager.Stub { } private boolean grantSignaturePermission(String perm, PackageParser.Package pkg, - BasePermission bp, HashSet<String> origPermissions) { + BasePermission bp, ArraySet<String> origPermissions) { boolean allowed; allowed = (compareSignatures( bp.packageSetting.signatures.mSignatures, pkg.mSignatures) @@ -7339,8 +7340,8 @@ public class PackageManagerService extends IPackageManager.Stub { // } // Keys are String (activity class name), values are Activity. - private final HashMap<ComponentName, PackageParser.Activity> mActivities - = new HashMap<ComponentName, PackageParser.Activity>(); + private final ArrayMap<ComponentName, PackageParser.Activity> mActivities + = new ArrayMap<ComponentName, PackageParser.Activity>(); private int mFlags; } @@ -7538,8 +7539,8 @@ public class PackageManagerService extends IPackageManager.Stub { // } // Keys are String (activity class name), values are Activity. - private final HashMap<ComponentName, PackageParser.Service> mServices - = new HashMap<ComponentName, PackageParser.Service>(); + private final ArrayMap<ComponentName, PackageParser.Service> mServices + = new ArrayMap<ComponentName, PackageParser.Service>(); private int mFlags; }; @@ -7732,8 +7733,8 @@ public class PackageManagerService extends IPackageManager.Stub { out.println(Integer.toHexString(System.identityHashCode(filter))); } - private final HashMap<ComponentName, PackageParser.Provider> mProviders - = new HashMap<ComponentName, PackageParser.Provider>(); + private final ArrayMap<ComponentName, PackageParser.Provider> mProviders + = new ArrayMap<ComponentName, PackageParser.Provider>(); private int mFlags; }; @@ -10402,6 +10403,60 @@ public class PackageManagerService extends IPackageManager.Stub { String oldCodePath = null; boolean systemApp = false; synchronized (mPackages) { + // Check if installing already existing package + if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { + String oldName = mSettings.mRenamedPackages.get(pkgName); + if (pkg.mOriginalPackages != null + && pkg.mOriginalPackages.contains(oldName) + && mPackages.containsKey(oldName)) { + // This package is derived from an original package, + // and this device has been updating from that original + // name. We must continue using the original name, so + // rename the new package here. + pkg.setPackageName(oldName); + pkgName = pkg.packageName; + replace = true; + if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName=" + + oldName + " pkgName=" + pkgName); + } else if (mPackages.containsKey(pkgName)) { + // This package, under its official name, already exists + // on the device; we should replace it. + replace = true; + if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); + } + } + + PackageSetting ps = mSettings.mPackages.get(pkgName); + if (ps != null) { + if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); + + // Quick sanity check that we're signed correctly if updating; + // we'll check this again later when scanning, but we want to + // bail early here before tripping over redefined permissions. + if (!ps.keySetData.isUsingUpgradeKeySets() || ps.sharedUser != null) { + try { + verifySignaturesLP(ps, pkg); + } catch (PackageManagerException e) { + res.setError(e.error, e.getMessage()); + return; + } + } else { + if (!checkUpgradeKeySetLP(ps, pkg)) { + res.setError(INSTALL_FAILED_UPDATE_INCOMPATIBLE, "Package " + + pkg.packageName + " upgrade keys do not match the " + + "previously installed version"); + return; + } + } + + oldCodePath = mSettings.mPackages.get(pkgName).codePathString; + if (ps.pkg != null && ps.pkg.applicationInfo != null) { + systemApp = (ps.pkg.applicationInfo.flags & + ApplicationInfo.FLAG_SYSTEM) != 0; + } + res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); + } + // Check whether the newly-scanned package wants to define an already-defined perm int N = pkg.permissions.size(); for (int i = N-1; i >= 0; i--) { @@ -10442,38 +10497,6 @@ public class PackageManagerService extends IPackageManager.Stub { } } - // Check if installing already existing package - if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) { - String oldName = mSettings.mRenamedPackages.get(pkgName); - if (pkg.mOriginalPackages != null - && pkg.mOriginalPackages.contains(oldName) - && mPackages.containsKey(oldName)) { - // This package is derived from an original package, - // and this device has been updating from that original - // name. We must continue using the original name, so - // rename the new package here. - pkg.setPackageName(oldName); - pkgName = pkg.packageName; - replace = true; - if (DEBUG_INSTALL) Slog.d(TAG, "Replacing existing renamed package: oldName=" - + oldName + " pkgName=" + pkgName); - } else if (mPackages.containsKey(pkgName)) { - // This package, under its official name, already exists - // on the device; we should replace it. - replace = true; - if (DEBUG_INSTALL) Slog.d(TAG, "Replace existing pacakge: " + pkgName); - } - } - PackageSetting ps = mSettings.mPackages.get(pkgName); - if (ps != null) { - if (DEBUG_INSTALL) Slog.d(TAG, "Existing package: " + ps); - oldCodePath = mSettings.mPackages.get(pkgName).codePathString; - if (ps.pkg != null && ps.pkg.applicationInfo != null) { - systemApp = (ps.pkg.applicationInfo.flags & - ApplicationInfo.FLAG_SYSTEM) != 0; - } - res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true); - } } if (systemApp && onSd) { @@ -11835,8 +11858,8 @@ public class PackageManagerService extends IPackageManager.Stub { synchronized (mPackages) { CrossProfileIntentResolver resolver = mSettings.editCrossProfileIntentResolverLPw(sourceUserId); - HashSet<CrossProfileIntentFilter> set = - new HashSet<CrossProfileIntentFilter>(resolver.filterSet()); + ArraySet<CrossProfileIntentFilter> set = + new ArraySet<CrossProfileIntentFilter>(resolver.filterSet()); for (CrossProfileIntentFilter filter : set) { if (filter.getOwnerPackage().equals(ownerPackage) && filter.getOwnerUserId() == callingUserId) { @@ -13381,4 +13404,25 @@ public class PackageManagerService extends IPackageManager.Stub { return false; } } + + public void getUsageStatsIfNoPackageUsageInfo() { + if (!mPackageUsage.isHistoricalPackageUsageAvailable()) { + UsageStatsManager usm = (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE); + if (usm == null) { + throw new IllegalStateException("UsageStatsManager must be initialized"); + } + long now = System.currentTimeMillis(); + Map<String, UsageStats> stats = usm.queryAndAggregateUsageStats(now - mDexOptLRUThresholdInMills, now); + for (Map.Entry<String, UsageStats> entry : stats.entrySet()) { + String packageName = entry.getKey(); + PackageParser.Package pkg = mPackages.get(packageName); + if (pkg == null) { + continue; + } + UsageStats usage = entry.getValue(); + pkg.mLastPackageUsageTimeInMills = usage.getLastTimeUsed(); + mPackageUsage.mIsHistoricalPackageUsageAvailable = true; + } + } + } } diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java index bf13fd9..1dcadb4 100644 --- a/services/core/java/com/android/server/pm/PackageSettingBase.java +++ b/services/core/java/com/android/server/pm/PackageSettingBase.java @@ -21,10 +21,10 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; import android.content.pm.PackageUserState; +import android.util.ArraySet; import android.util.SparseArray; import java.io.File; -import java.util.HashSet; /** * Settings base class for pending and resolved classes. @@ -321,8 +321,8 @@ class PackageSettingBase extends GrantedPermissions { void setUserState(int userId, int enabled, boolean installed, boolean stopped, boolean notLaunched, boolean hidden, - String lastDisableAppCaller, HashSet<String> enabledComponents, - HashSet<String> disabledComponents, boolean blockUninstall) { + String lastDisableAppCaller, ArraySet<String> enabledComponents, + ArraySet<String> disabledComponents, boolean blockUninstall) { PackageUserState state = modifyUserState(userId); state.enabled = enabled; state.installed = installed; @@ -335,39 +335,39 @@ class PackageSettingBase extends GrantedPermissions { state.blockUninstall = blockUninstall; } - HashSet<String> getEnabledComponents(int userId) { + ArraySet<String> getEnabledComponents(int userId) { return readUserState(userId).enabledComponents; } - HashSet<String> getDisabledComponents(int userId) { + ArraySet<String> getDisabledComponents(int userId) { return readUserState(userId).disabledComponents; } - void setEnabledComponents(HashSet<String> components, int userId) { + void setEnabledComponents(ArraySet<String> components, int userId) { modifyUserState(userId).enabledComponents = components; } - void setDisabledComponents(HashSet<String> components, int userId) { + void setDisabledComponents(ArraySet<String> components, int userId) { modifyUserState(userId).disabledComponents = components; } - void setEnabledComponentsCopy(HashSet<String> components, int userId) { + void setEnabledComponentsCopy(ArraySet<String> components, int userId) { modifyUserState(userId).enabledComponents = components != null - ? new HashSet<String>(components) : null; + ? new ArraySet<String>(components) : null; } - void setDisabledComponentsCopy(HashSet<String> components, int userId) { + void setDisabledComponentsCopy(ArraySet<String> components, int userId) { modifyUserState(userId).disabledComponents = components != null - ? new HashSet<String>(components) : null; + ? new ArraySet<String>(components) : null; } PackageUserState modifyUserStateComponents(int userId, boolean disabled, boolean enabled) { PackageUserState state = modifyUserState(userId); if (disabled && state.disabledComponents == null) { - state.disabledComponents = new HashSet<String>(1); + state.disabledComponents = new ArraySet<String>(1); } if (enabled && state.enabledComponents == null) { - state.enabledComponents = new HashSet<String>(1); + state.enabledComponents = new ArraySet<String>(1); } return state; } diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index 7de56c8..200eb5f 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -63,6 +63,8 @@ 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; @@ -78,8 +80,6 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -159,11 +159,11 @@ final class Settings { private final File mStoppedPackagesFilename; private final File mBackupStoppedPackagesFilename; - final HashMap<String, PackageSetting> mPackages = - new HashMap<String, PackageSetting>(); + final ArrayMap<String, PackageSetting> mPackages = + new ArrayMap<String, PackageSetting>(); // List of replaced system applications - private final HashMap<String, PackageSetting> mDisabledSysPackages = - new HashMap<String, PackageSetting>(); + private final ArrayMap<String, PackageSetting> mDisabledSysPackages = + new ArrayMap<String, PackageSetting>(); private static int mFirstAvailableUid = 0; @@ -206,8 +206,8 @@ final class Settings { final SparseArray<CrossProfileIntentResolver> mCrossProfileIntentResolvers = new SparseArray<CrossProfileIntentResolver>(); - final HashMap<String, SharedUserSetting> mSharedUsers = - new HashMap<String, SharedUserSetting>(); + final ArrayMap<String, SharedUserSetting> mSharedUsers = + new ArrayMap<String, SharedUserSetting>(); private final ArrayList<Object> mUserIds = new ArrayList<Object>(); private final SparseArray<Object> mOtherUserIds = new SparseArray<Object>(); @@ -217,12 +217,12 @@ final class Settings { new ArrayList<Signature>(); // Mapping from permission names to info about them. - final HashMap<String, BasePermission> mPermissions = - new HashMap<String, BasePermission>(); + final ArrayMap<String, BasePermission> mPermissions = + new ArrayMap<String, BasePermission>(); // Mapping from permission tree names to info about them. - final HashMap<String, BasePermission> mPermissionTrees = - new HashMap<String, BasePermission>(); + final ArrayMap<String, BasePermission> mPermissionTrees = + new ArrayMap<String, BasePermission>(); // Packages that have been uninstalled and still need their external // storage data deleted. @@ -232,7 +232,7 @@ final class Settings { // Keys are the new names of the packages, values are the original // names. The packages appear everwhere else under their original // names. - final HashMap<String, String> mRenamedPackages = new HashMap<String, String>(); + final ArrayMap<String, String> mRenamedPackages = new ArrayMap<String, String>(); final StringBuilder mReadMessages = new StringBuilder(); @@ -437,7 +437,7 @@ final class Settings { void transferPermissionsLPw(String origPkg, String newPkg) { // Transfer ownership of permissions to the new package. for (int i=0; i<2; i++) { - HashMap<String, BasePermission> permissions = + ArrayMap<String, BasePermission> permissions = i == 0 ? mPermissionTrees : mPermissions; for (BasePermission bp : permissions.values()) { if (origPkg.equals(bp.sourcePackage)) { @@ -582,7 +582,7 @@ final class Settings { } p.appId = dis.appId; // Clone permissions - p.grantedPermissions = new HashSet<String>(dis.grantedPermissions); + p.grantedPermissions = new ArraySet<String>(dis.grantedPermissions); // Clone component info List<UserInfo> users = getAllUsers(); if (users != null) { @@ -1138,8 +1138,8 @@ final class Settings { final boolean blockUninstall = blockUninstallStr == null ? false : Boolean.parseBoolean(blockUninstallStr); - HashSet<String> enabledComponents = null; - HashSet<String> disabledComponents = null; + ArraySet<String> enabledComponents = null; + ArraySet<String> disabledComponents = null; int packageDepth = parser.getDepth(); while ((type=parser.next()) != XmlPullParser.END_DOCUMENT @@ -1189,9 +1189,9 @@ final class Settings { } } - private HashSet<String> readComponentsLPr(XmlPullParser parser) + private ArraySet<String> readComponentsLPr(XmlPullParser parser) throws IOException, XmlPullParserException { - HashSet<String> components = null; + ArraySet<String> components = null; int type; int outerDepth = parser.getDepth(); String tagName; @@ -1207,7 +1207,7 @@ final class Settings { String componentName = parser.getAttributeValue(null, ATTR_NAME); if (componentName != null) { if (components == null) { - components = new HashSet<String>(); + components = new ArraySet<String>(); } components.add(componentName); } @@ -1921,7 +1921,7 @@ final class Settings { } ArrayList<PackageSetting> getListOfIncompleteInstallPackagesLPr() { - final HashSet<String> kList = new HashSet<String>(mPackages.keySet()); + final ArraySet<String> kList = new ArraySet<String>(mPackages.keySet()); final Iterator<String> its = kList.iterator(); final ArrayList<PackageSetting> ret = new ArrayList<PackageSetting>(); while (its.hasNext()) { @@ -2511,7 +2511,7 @@ final class Settings { return defValue; } - private void readPermissionsLPw(HashMap<String, BasePermission> out, XmlPullParser parser) + private void readPermissionsLPw(ArrayMap<String, BasePermission> out, XmlPullParser parser) throws IOException, XmlPullParserException { int outerDepth = parser.getDepth(); int type; @@ -3016,7 +3016,7 @@ final class Settings { } } - private void readGrantedPermissionsLPw(XmlPullParser parser, HashSet<String> outPerms) + private void readGrantedPermissionsLPw(XmlPullParser parser, ArraySet<String> outPerms) throws IOException, XmlPullParserException { int outerDepth = parser.getDepth(); int type; @@ -3090,8 +3090,8 @@ final class Settings { int sourceUserId = mCrossProfileIntentResolvers.keyAt(i); CrossProfileIntentResolver cpir = mCrossProfileIntentResolvers.get(sourceUserId); boolean needsWriting = false; - HashSet<CrossProfileIntentFilter> cpifs = - new HashSet<CrossProfileIntentFilter>(cpir.filterSet()); + ArraySet<CrossProfileIntentFilter> cpifs = + new ArraySet<CrossProfileIntentFilter>(cpir.filterSet()); for (CrossProfileIntentFilter cpif : cpifs) { if (cpif.getTargetUserId() == userId) { needsWriting = true; @@ -3147,7 +3147,7 @@ final class Settings { return ps; } - private String compToString(HashSet<String> cmp) { + private String compToString(ArraySet<String> cmp) { return cmp != null ? Arrays.toString(cmp.toArray()) : "[]"; } @@ -3477,7 +3477,7 @@ final class Settings { pw.print(prefix); pw.print(" lastDisabledCaller: "); pw.println(lastDisabledAppCaller); } - HashSet<String> cmp = ps.getDisabledComponents(user.id); + ArraySet<String> cmp = ps.getDisabledComponents(user.id); if (cmp != null && cmp.size() > 0) { pw.print(prefix); pw.println(" disabledComponents:"); for (String s : cmp) { diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index ca1eeea..2b406f7 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -16,7 +16,7 @@ package com.android.server.pm; -import java.util.HashSet; +import android.util.ArraySet; /** * Settings data for a particular shared user ID we know about. @@ -29,7 +29,7 @@ final class SharedUserSetting extends GrantedPermissions { // flags that are associated with this uid, regardless of any package flags int uidFlags; - final HashSet<PackageSetting> packages = new HashSet<PackageSetting>(); + final ArraySet<PackageSetting> packages = new ArraySet<PackageSetting>(); final PackageSignatures signatures = new PackageSignatures(); diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java index 52807c0..5e95dfe 100644 --- a/services/core/java/com/android/server/power/PowerManagerService.java +++ b/services/core/java/com/android/server/power/PowerManagerService.java @@ -281,6 +281,9 @@ public final class PowerManagerService extends SystemService // True if the device should wake up when plugged or unplugged. private boolean mWakeUpWhenPluggedOrUnpluggedConfig; + // True if the device should wake up when plugged or unplugged in theater mode. + private boolean mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig; + // True if the device should suspend when the screen is off due to proximity. private boolean mSuspendWhenScreenOffDueToProximityConfig; @@ -420,6 +423,9 @@ public final class PowerManagerService extends SystemService // True if the battery level is currently considered low. private boolean mBatteryLevelLow; + // True if theater mode is enabled + private boolean mTheaterModeEnabled; + private final ArrayList<PowerManagerInternal.LowPowerModeListener> mLowPowerModeListeners = new ArrayList<PowerManagerInternal.LowPowerModeListener>(); @@ -568,6 +574,9 @@ public final class PowerManagerService extends SystemService resolver.registerContentObserver(Settings.Global.getUriFor( Settings.Global.LOW_POWER_MODE_TRIGGER_LEVEL), false, mSettingsObserver, UserHandle.USER_ALL); + resolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.THEATER_MODE_ON), + false, mSettingsObserver, UserHandle.USER_ALL); // Go. readConfigurationLocked(); updateSettingsLocked(); @@ -585,6 +594,8 @@ public final class PowerManagerService extends SystemService com.android.internal.R.bool.config_powerDecoupleInteractiveModeFromDisplay); mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean( com.android.internal.R.bool.config_unplugTurnsOnScreen); + mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig = resources.getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromUnplug); mSuspendWhenScreenOffDueToProximityConfig = resources.getBoolean( com.android.internal.R.bool.config_suspendWhenScreenOffDueToProximity); mDreamsSupportedConfig = resources.getBoolean( @@ -636,6 +647,8 @@ public final class PowerManagerService extends SystemService UserHandle.USER_CURRENT); mStayOnWhilePluggedInSetting = Settings.Global.getInt(resolver, Settings.Global.STAY_ON_WHILE_PLUGGED_IN, BatteryManager.BATTERY_PLUGGED_AC); + mTheaterModeEnabled = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0) == 1; final int oldScreenBrightnessSetting = mScreenBrightnessSetting; mScreenBrightnessSetting = Settings.System.getIntForUser(resolver, @@ -1334,6 +1347,11 @@ public final class PowerManagerService extends SystemService return false; } + // Don't wake while theater mode is enabled. + if (mTheaterModeEnabled && !mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig) { + return false; + } + // Otherwise wake up! return true; } @@ -2360,6 +2378,10 @@ public final class PowerManagerService extends SystemService + mDecoupleHalInteractiveModeFromDisplayConfig); pw.println(" mWakeUpWhenPluggedOrUnpluggedConfig=" + mWakeUpWhenPluggedOrUnpluggedConfig); + pw.println(" mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig=" + + mWakeUpWhenPluggedOrUnpluggedInTheaterModeConfig); + pw.println(" mTheaterModeEnabled=" + + mTheaterModeEnabled); pw.println(" mSuspendWhenScreenOffDueToProximityConfig=" + mSuspendWhenScreenOffDueToProximityConfig); pw.println(" mDreamsSupportedConfig=" + mDreamsSupportedConfig); diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java index f85e2d9..15e0bf0 100644 --- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java +++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java @@ -26,6 +26,7 @@ import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; import android.util.Slog; +import android.view.WindowManager; import com.android.internal.statusbar.IStatusBar; import com.android.internal.statusbar.IStatusBarService; @@ -295,9 +296,10 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } } - /** + /** * Hide or show the on-screen Menu key. Only call this from the window manager, typically in - * response to a window with FLAG_NEEDS_MENU_KEY set. + * response to a window with {@link android.view.WindowManager.LayoutParams#needsMenuKey} set + * to {@link android.view.WindowManager.LayoutParams#NEEDS_MENU_SET_TRUE}. */ @Override public void topAppWindowChanged(final boolean menuVisible) { @@ -523,6 +525,20 @@ public class StatusBarManagerService extends IStatusBarService.Stub { } @Override + public void onNotificationActionClick(String key, int actionIndex) { + enforceStatusBarService(); + final int callingUid = Binder.getCallingUid(); + final int callingPid = Binder.getCallingPid(); + long identity = Binder.clearCallingIdentity(); + try { + mNotificationDelegate.onNotificationActionClick(callingUid, callingPid, key, + actionIndex); + } finally { + Binder.restoreCallingIdentity(identity); + } + } + + @Override public void onNotificationError(String pkg, String tag, int id, int uid, int initialPid, String message, int userId) { enforceStatusBarService(); diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java index fefbe0a..65cb35b 100644 --- a/services/core/java/com/android/server/trust/TrustManagerService.java +++ b/services/core/java/com/android/server/trust/TrustManagerService.java @@ -16,6 +16,7 @@ package com.android.server.trust; +import com.android.internal.annotations.GuardedBy; import com.android.internal.content.PackageMonitor; import com.android.internal.widget.LockPatternUtils; import com.android.server.SystemService; @@ -24,6 +25,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.Manifest; +import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; import android.app.trust.ITrustListener; @@ -41,6 +43,7 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.XmlResourceParser; import android.graphics.drawable.Drawable; +import android.os.Binder; import android.os.DeadObjectException; import android.os.Handler; import android.os.IBinder; @@ -100,8 +103,10 @@ public class TrustManagerService extends SystemService { /* package */ final TrustArchive mArchive = new TrustArchive(); private final Context mContext; private final LockPatternUtils mLockPatternUtils; + private final UserManager mUserManager; - private UserManager mUserManager; + @GuardedBy("mUserIsTrusted") + private final SparseBooleanArray mUserIsTrusted = new SparseBooleanArray(); public TrustManagerService(Context context) { super(context); @@ -117,11 +122,16 @@ public class TrustManagerService extends SystemService { @Override public void onBootPhase(int phase) { - if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY && !isSafeMode()) { + if (isSafeMode()) { + // No trust agents in safe mode. + return; + } + if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true); mReceiver.register(mContext); - maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_OWNER); refreshAgentList(UserHandle.USER_ALL); + } else if (phase == SystemService.PHASE_BOOT_COMPLETED) { + maybeEnableFactoryTrustAgents(mLockPatternUtils, UserHandle.USER_OWNER); } } @@ -159,11 +169,19 @@ public class TrustManagerService extends SystemService { public void updateTrust(int userId, boolean initiatedByUser) { dispatchOnTrustManagedChanged(aggregateIsTrustManaged(userId), userId); - dispatchOnTrustChanged(aggregateIsTrusted(userId), userId, initiatedByUser); + boolean trusted = aggregateIsTrusted(userId); + synchronized (mUserIsTrusted) { + mUserIsTrusted.put(userId, trusted); + } + dispatchOnTrustChanged(trusted, userId, initiatedByUser); } void refreshAgentList(int userId) { if (DEBUG) Slog.d(TAG, "refreshAgentList()"); + if (isSafeMode()) { + // Don't ever bind to trust agents in safe mode. + return; + } if (userId != UserHandle.USER_ALL && userId < UserHandle.USER_OWNER) { Log.e(TAG, "refreshAgentList(userId=" + userId + "): Invalid user handle," + " must be USER_ALL or a specific user.", new Throwable("here")); @@ -546,6 +564,16 @@ public class TrustManagerService extends SystemService { mHandler.obtainMessage(MSG_UNREGISTER_LISTENER, trustListener).sendToTarget(); } + @Override + public boolean isTrusted(int userId) throws RemoteException { + userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId, + false /* allowAll */, true /* requireFull */, "isTrusted", null); + userId = resolveProfileParent(userId); + synchronized (mUserIsTrusted) { + return mUserIsTrusted.get(userId); + } + } + private void enforceReportPermission() { mContext.enforceCallingOrSelfPermission( Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events"); @@ -560,6 +588,10 @@ public class TrustManagerService extends SystemService { protected void dump(FileDescriptor fd, final PrintWriter fout, String[] args) { mContext.enforceCallingPermission(Manifest.permission.DUMP, "dumping TrustManagerService"); + if (isSafeMode()) { + fout.println("disabled because the system is in safe mode."); + return; + } final UserInfo currentUser; final List<UserInfo> userInfos = mUserManager.getUsers(true /* excludeDying */); try { @@ -622,6 +654,19 @@ public class TrustManagerService extends SystemService { } }; + private int resolveProfileParent(int userId) { + long identity = Binder.clearCallingIdentity(); + try { + UserInfo parent = mUserManager.getProfileParent(userId); + if (parent != null) { + return parent.getUserHandle().getIdentifier(); + } + return userId; + } finally { + Binder.restoreCallingIdentity(identity); + } + } + private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java index 558ffb5..c12dd63 100644 --- a/services/core/java/com/android/server/tv/TvInputHal.java +++ b/services/core/java/com/android/server/tv/TvInputHal.java @@ -55,7 +55,7 @@ final class TvInputHal implements Handler.Callback { private native long nativeOpen(); - private static native int nativeAddStream(long ptr, int deviceId, int streamId, + private static native int nativeAddOrUpdateStream(long ptr, int deviceId, int streamId, Surface surface); private static native int nativeRemoveStream(long ptr, int deviceId, int streamId); private static native TvStreamConfig[] nativeGetStreamConfigs(long ptr, int deviceId, @@ -80,7 +80,7 @@ final class TvInputHal implements Handler.Callback { } } - public int addStream(int deviceId, Surface surface, TvStreamConfig streamConfig) { + public int addOrUpdateStream(int deviceId, Surface surface, TvStreamConfig streamConfig) { synchronized (mLock) { if (mPtr == 0) { return ERROR_NO_INIT; @@ -89,7 +89,7 @@ final class TvInputHal implements Handler.Callback { if (generation != streamConfig.getGeneration()) { return ERROR_STALE_CONFIG; } - if (nativeAddStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) { + if (nativeAddOrUpdateStream(mPtr, deviceId, streamConfig.getStreamId(), surface) == 0) { return SUCCESS; } else { return ERROR_UNKNOWN; diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 77ab33b..85659cf 100644 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -122,6 +122,8 @@ class TvInputHardwareManager implements TvInputHal.Callback { } catch (RemoteException e) { Slog.w(TAG, "Error registering listeners to HdmiControlService:", e); } + } else { + Slog.w(TAG, "HdmiControlService is not available"); } } } @@ -186,6 +188,11 @@ class TvInputHardwareManager implements TvInputHal.Callback { return; } connection.updateConfigsLocked(configs); + String inputId = mHardwareInputIdMap.get(deviceId); + if (inputId != null) { + mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, + convertConnectedToState(configs.length > 0), 0, inputId).sendToTarget(); + } try { connection.getCallbackLocked().onStreamConfigChanged(configs); } catch (RemoteException e) { @@ -255,6 +262,9 @@ class TvInputHardwareManager implements TvInputHal.Callback { mHardwareInputIdMap.put(deviceId, info.getId()); mInputMap.put(info.getId(), info); + // Process pending state changes + + // For logical HDMI devices, they have information from HDMI CEC signals. for (int i = 0; i < mHdmiStateMap.size(); ++i) { TvInputHardwareInfo hardwareInfo = findHardwareInfoForHdmiPortLocked(mHdmiStateMap.keyAt(i)); @@ -266,8 +276,17 @@ class TvInputHardwareManager implements TvInputHal.Callback { mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, convertConnectedToState(mHdmiStateMap.valueAt(i)), 0, inputId).sendToTarget(); + return; } } + // For the rest of the devices, we can tell by the number of available streams. + Connection connection = mConnections.get(deviceId); + if (connection != null) { + mHandler.obtainMessage(ListenerHandler.STATE_CHANGED, + convertConnectedToState(connection.getConfigsLocked().length > 0), 0, + info.getId()).sendToTarget(); + return; + } } } @@ -666,14 +685,14 @@ class TvInputHardwareManager implements TvInputHal.Callback { result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); mActiveConfig = null; } else { - if (config != mActiveConfig && mActiveConfig != null) { + if (!config.equals(mActiveConfig)) { result = mHal.removeStream(mInfo.getDeviceId(), mActiveConfig); if (result != TvInputHal.SUCCESS) { mActiveConfig = null; return false; } } - result = mHal.addStream(mInfo.getDeviceId(), surface, config); + result = mHal.addOrUpdateStream(mInfo.getDeviceId(), surface, config); if (result == TvInputHal.SUCCESS) { mActiveConfig = config; } @@ -743,7 +762,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { && sinkConfig.channelMask() != mDesiredChannelMask) || (mDesiredFormat != AudioFormat.ENCODING_DEFAULT && sinkConfig.format() != mDesiredFormat)) { - sinkConfig = mAudioSource.buildConfig(mDesiredSamplingRate, mDesiredChannelMask, + sinkConfig = mAudioSink.buildConfig(mDesiredSamplingRate, mDesiredChannelMask, mDesiredFormat, null); shouldRecreateAudioPatch = true; } @@ -799,7 +818,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { return false; } - int result = mHal.addStream(mInfo.getDeviceId(), surface, config); + int result = mHal.addOrUpdateStream(mInfo.getDeviceId(), surface, config); return result == TvInputHal.SUCCESS; } } @@ -914,11 +933,18 @@ class TvInputHardwareManager implements TvInputHal.Callback { break; } case HDMI_DEVICE_UPDATED: { - SomeArgs args = (SomeArgs) msg.obj; - String inputId = (String) args.arg1; - HdmiDeviceInfo info = (HdmiDeviceInfo) args.arg2; - args.recycle(); - mListener.onHdmiDeviceUpdated(inputId, info); + HdmiDeviceInfo info = (HdmiDeviceInfo) msg.obj; + String inputId = null; + synchronized (mLock) { + inputId = mHdmiInputIdMap.get(info.getId()); + } + if (inputId != null) { + mListener.onHdmiDeviceUpdated(inputId, info); + } else { + Slog.w(TAG, "Could not resolve input ID matching the device info; " + + "ignoring."); + } + break; } default: { Slog.w(TAG, "Unhandled message: " + msg); @@ -986,11 +1012,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { } mHdmiDeviceList.add(deviceInfo); messageType = ListenerHandler.HDMI_DEVICE_UPDATED; - String inputId = mHdmiInputIdMap.get(deviceInfo.getId()); - SomeArgs args = SomeArgs.obtain(); - args.arg1 = inputId; - args.arg2 = deviceInfo; - obj = args; + obj = deviceInfo; break; } } diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java index 8a36335..257cbd0 100644 --- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java +++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java @@ -62,6 +62,7 @@ import android.service.wallpaper.IWallpaperConnection; import android.service.wallpaper.IWallpaperEngine; import android.service.wallpaper.IWallpaperService; import android.service.wallpaper.WallpaperService; +import android.util.EventLog; import android.util.Slog; import android.util.SparseArray; import android.util.Xml; @@ -87,6 +88,7 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; import com.android.internal.R; +import com.android.server.EventLogTags; public class WallpaperManagerService extends IWallpaperManager.Stub { static final String TAG = "WallpaperManagerService"; @@ -99,6 +101,7 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { * restarting it vs. just reverting to the static wallpaper. */ static final long MIN_WALLPAPER_CRASH_TIME = 10000; + static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128; static final String WALLPAPER = "wallpaper"; static final String WALLPAPER_INFO = "wallpaper_info.xml"; @@ -272,6 +275,10 @@ public class WallpaperManagerService extends IWallpaperManager.Stub { } else { mWallpaper.lastDiedTime = SystemClock.uptimeMillis(); } + final String flattened = name.flattenToString(); + EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED, + flattened.substring(0, Math.min(flattened.length(), + MAX_WALLPAPER_COMPONENT_LOG_LENGTH))); } } } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index fa1c0ff..f947b6a 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -346,8 +346,7 @@ final class AccessibilityController { case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG: case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR: case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY: - case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: - case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: { + case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL: { Rect magnifiedRegionBounds = mTempRect2; mMagnifedViewport.getMagnifiedFrameInContentCoordsLocked( magnifiedRegionBounds); @@ -993,8 +992,7 @@ final class AccessibilityController { final int flags = windowState.mAttrs.flags; - // If the window is not touchable, do not report it but take into account - // the space it takes since the content behind it cannot be touched. + // If the window is not touchable - ignore. if ((flags & WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE) != 0) { continue; } @@ -1015,9 +1013,14 @@ final class AccessibilityController { } } - // Account for the space this window takes. - unaccountedSpace.op(boundsInScreen, unaccountedSpace, - Region.Op.REVERSE_DIFFERENCE); + // Account for the space this window takes if the window + // is not an accessibility overlay which does not change + // the reported windows. + if (windowState.mAttrs.type == WindowManager.LayoutParams + .TYPE_ACCESSIBILITY_OVERLAY) { + unaccountedSpace.op(boundsInScreen, unaccountedSpace, + Region.Op.REVERSE_DIFFERENCE); + } // We figured out what is touchable for the entire screen - done. if (unaccountedSpace.isEmpty()) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 30589b1..b0feca8 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -376,10 +376,9 @@ class DisplayContent { stack.dump(prefix + " ", pw); } pw.println(); - pw.println(" Application tokens in bottom up Z order:"); + pw.println(" Application tokens in top down Z order:"); int ndx = 0; - final int numStacks = mStacks.size(); - for (int stackNdx = 0; stackNdx < numStacks; ++stackNdx) { + for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) { ArrayList<Task> tasks = mStacks.get(stackNdx).getTasks(); for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) { AppTokenList tokens = tasks.get(taskNdx).mAppTokens; diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 9ceac41..a60be3b 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -60,6 +60,12 @@ class Task { return removed; } + void setSendingToBottom(boolean toBottom) { + for (int appTokenNdx = 0; appTokenNdx < mAppTokens.size(); appTokenNdx++) { + mAppTokens.get(appTokenNdx).sendingToBottom = toBottom; + } + } + @Override public String toString() { return "{taskId=" + taskId + " appTokens=" + mAppTokens + "}"; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 837672a..0e55c1c 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -619,6 +619,9 @@ public class WindowManagerService extends IWindowManager.Stub boolean mTurnOnScreen; + // Whether or not a layout can cause a wake up when theater mode is enabled. + boolean mAllowTheaterModeWakeFromLayout; + DragState mDragState = null; // For frozen screen animations. @@ -881,6 +884,9 @@ public class WindowManagerService extends IWindowManager.Stub mAnimator = new WindowAnimator(this); + mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean( + com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout); + LocalServices.addService(WindowManagerInternal.class, new LocalService()); initPolicy(); @@ -2331,6 +2337,11 @@ public class WindowManagerService extends IWindowManager.Stub + attrs.token + ". Aborting."); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } + if (type == TYPE_ACCESSIBILITY_OVERLAY) { + Slog.w(TAG, "Attempted to add Accessibility overlay window with unknown token " + + attrs.token + ". Aborting."); + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; + } token = new WindowToken(this, attrs.token, -1, false); addToken = true; } else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) { @@ -2374,6 +2385,12 @@ public class WindowManagerService extends IWindowManager.Stub + attrs.token + ". Aborting."); return WindowManagerGlobal.ADD_BAD_APP_TOKEN; } + } else if (type == TYPE_ACCESSIBILITY_OVERLAY) { + if (token.windowType != TYPE_ACCESSIBILITY_OVERLAY) { + Slog.w(TAG, "Attempted to add Accessibility overlay window with bad token " + + attrs.token + ". Aborting."); + return WindowManagerGlobal.ADD_BAD_APP_TOKEN; + } } else if (token.appWindowToken != null) { Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type); // It is not valid to use an app token with other system types; we will @@ -2509,9 +2526,8 @@ public class WindowManagerService extends IWindowManager.Stub } mInputMonitor.updateInputWindowsLw(false /*force*/); - if (localLOGV) Slog.v( - TAG, "New client " + client.asBinder() - + ": window=" + win); + if (true || localLOGV) Slog.v(TAG, "addWindow: New client " + client.asBinder() + + ": window=" + win + " Callers=" + Debug.getCallers(5)); if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) { reportNewConfig = true; @@ -2675,7 +2691,8 @@ public class WindowManagerService extends IWindowManager.Stub mPolicy.removeWindowLw(win); win.removeLocked(); - if (DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win); + if (true || DEBUG_ADD_REMOVE) Slog.v(TAG, "removeWindowInnerLocked: " + win + + " Callers=" + Debug.getCallers(5)); mWindowMap.remove(win.mClient.asBinder()); if (win.mAppOp != AppOpsManager.OP_NONE) { mAppOps.finishOp(win.mAppOp, win.getOwningUid(), win.getOwningPackage()); @@ -2980,8 +2997,8 @@ public class WindowManagerService extends IWindowManager.Stub return 0; } WindowStateAnimator winAnimator = win.mWinAnimator; - if (win.mRequestedWidth != requestedWidth - || win.mRequestedHeight != requestedHeight) { + if (viewVisibility != View.GONE && (win.mRequestedWidth != requestedWidth + || win.mRequestedHeight != requestedHeight)) { win.mLayoutNeeded = true; win.mRequestedWidth = requestedWidth; win.mRequestedHeight = requestedHeight; @@ -5052,6 +5069,10 @@ public class WindowManagerService extends IWindowManager.Stub } } stack.moveTaskToTop(task); + if (mAppTransition.isTransitionSet()) { + task.setSendingToBottom(false); + } + moveStackWindowsLocked(displayContent); } } finally { Binder.restoreCallingIdentity(origId); @@ -5070,6 +5091,9 @@ public class WindowManagerService extends IWindowManager.Stub } final TaskStack stack = task.mStack; stack.moveTaskToBottom(task); + if (mAppTransition.isTransitionSet()) { + task.setSendingToBottom(true); + } moveStackWindowsLocked(stack.getDisplayContent()); } } finally { @@ -9365,7 +9389,6 @@ public class WindowManagerService extends IWindowManager.Stub final int type = attrs.type; if (canBeSeen && (type == TYPE_SYSTEM_DIALOG - || type == TYPE_RECENTS_OVERLAY || type == TYPE_SYSTEM_ERROR || (attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0)) { mInnerFields.mSyswin = true; @@ -9954,8 +9977,12 @@ public class WindowManagerService extends IWindowManager.Stub } if (mTurnOnScreen) { - if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!"); - mPowerManager.wakeUp(SystemClock.uptimeMillis()); + if (mAllowTheaterModeWakeFromLayout + || Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.THEATER_MODE_ON, 0) == 0) { + if (DEBUG_VISIBILITY) Slog.v(TAG, "Turning screen on after layout!"); + mPowerManager.wakeUp(SystemClock.uptimeMillis()); + } mTurnOnScreen = false; } @@ -11611,5 +11638,23 @@ public class WindowManagerService extends IWindowManager.Stub checkDrawnWindowsLocked(); } } + + @Override + public void addWindowToken(IBinder token, int type) { + WindowManagerService.this.addWindowToken(token, type); + } + + @Override + public void removeWindowToken(IBinder token, boolean removeWindows) { + synchronized(mWindowMap) { + if (removeWindows) { + WindowToken wtoken = mTokenMap.remove(token); + if (wtoken != null) { + wtoken.removeAllWindows(); + } + } + WindowManagerService.this.removeWindowToken(token); + } + } } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index b4a7f04..e5cf764 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -227,13 +227,33 @@ final class WindowState implements WindowManagerPolicy.WindowState { final Rect mCompatFrame = new Rect(); final Rect mContainingFrame = new Rect(); + + final Rect mParentFrame = new Rect(); + + // The entire screen area of the device. final Rect mDisplayFrame = new Rect(); + + // The region of the display frame that the display type supports displaying content on. This + // is mostly a special case for TV where some displays don’t have the entire display usable. + // {@link WindowManager.LayoutParams#FLAG_LAYOUT_IN_OVERSCAN} flag can be used to allow + // window display contents to extend into the overscan region. final Rect mOverscanFrame = new Rect(); + + // The display frame minus the stable insets. This value is always constant regardless of if + // the status bar or navigation bar is visible. + final Rect mStableFrame = new Rect(); + + // The area not occupied by the status and navigation bars. So, if both status and navigation + // bars are visible, the decor frame is equal to the stable frame. + final Rect mDecorFrame = new Rect(); + + // Equal to the decor frame if the IME (e.g. keyboard) is not present. Equal to the decor frame + // minus the area occupied by the IME if the IME is present. final Rect mContentFrame = new Rect(); - final Rect mParentFrame = new Rect(); + + // Legacy stuff. Generally equal to the content frame expect when the IME for older apps + // displays hint text. final Rect mVisibleFrame = new Rect(); - final Rect mDecorFrame = new Rect(); - final Rect mStableFrame = new Rect(); boolean mContentChanged; @@ -704,9 +724,8 @@ final class WindowState implements WindowManagerPolicy.WindowState { WindowState ws = this; WindowList windows = getWindowList(); while (true) { - if ((ws.mAttrs.privateFlags - & WindowManager.LayoutParams.PRIVATE_FLAG_SET_NEEDS_MENU_KEY) != 0) { - return (ws.mAttrs.flags & WindowManager.LayoutParams.FLAG_NEEDS_MENU_KEY) != 0; + if (ws.mAttrs.needsMenuKey != WindowManager.LayoutParams.NEEDS_MENU_UNSET) { + return ws.mAttrs.needsMenuKey == WindowManager.LayoutParams.NEEDS_MENU_SET_TRUE; } // If we reached the bottom of the range of windows we are considering, // assume no menu is needed. diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 2267123..1a672e6 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -17,6 +17,7 @@ package com.android.server.wm; import android.os.IBinder; +import android.util.Slog; import java.io.PrintWriter; @@ -29,7 +30,7 @@ import java.io.PrintWriter; class WindowToken { // The window manager! final WindowManagerService service; - + // The actual token. final IBinder token; @@ -77,6 +78,15 @@ class WindowToken { explicit = _explicit; } + void removeAllWindows() { + for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) { + WindowState win = windows.get(winNdx); + if (WindowManagerService.DEBUG_WINDOW_MOVEMENT) Slog.w(WindowManagerService.TAG, + "removeAllWindows: removing win=" + win); + win.mService.removeWindowLocked(win.mSession, win); + } + } + void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("windows="); pw.println(windows); pw.print(prefix); pw.print("windowType="); pw.print(windowType); diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp index d5abe0c..5cb0543 100644 --- a/services/core/jni/com_android_server_tv_TvInputHal.cpp +++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp @@ -235,7 +235,7 @@ public: static JTvInputHal* createInstance(JNIEnv* env, jobject thiz); - int addStream(int deviceId, int streamId, const sp<Surface>& surface); + int addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface); int removeStream(int deviceId, int streamId); const tv_stream_config_t* getStreamConfigs(int deviceId, int* numConfigs); @@ -312,7 +312,7 @@ JTvInputHal* JTvInputHal::createInstance(JNIEnv* env, jobject thiz) { return new JTvInputHal(env, thiz, device); } -int JTvInputHal::addStream(int deviceId, int streamId, const sp<Surface>& surface) { +int JTvInputHal::addOrUpdateStream(int deviceId, int streamId, const sp<Surface>& surface) { KeyedVector<int, Connection>& connections = mConnections.editValueFor(deviceId); if (connections.indexOfKey(streamId) < 0) { connections.add(streamId, Connection()); @@ -555,14 +555,14 @@ static jlong nativeOpen(JNIEnv* env, jobject thiz) { return (jlong)JTvInputHal::createInstance(env, thiz); } -static int nativeAddStream(JNIEnv* env, jclass clazz, +static int nativeAddOrUpdateStream(JNIEnv* env, jclass clazz, jlong ptr, jint deviceId, jint streamId, jobject jsurface) { JTvInputHal* tvInputHal = (JTvInputHal*)ptr; if (!jsurface) { return BAD_VALUE; } sp<Surface> surface(android_view_Surface_getSurface(env, jsurface)); - return tvInputHal->addStream(deviceId, streamId, surface); + return tvInputHal->addOrUpdateStream(deviceId, streamId, surface); } static int nativeRemoveStream(JNIEnv* env, jclass clazz, @@ -612,8 +612,8 @@ static JNINativeMethod gTvInputHalMethods[] = { /* name, signature, funcPtr */ { "nativeOpen", "()J", (void*) nativeOpen }, - { "nativeAddStream", "(JIILandroid/view/Surface;)I", - (void*) nativeAddStream }, + { "nativeAddOrUpdateStream", "(JIILandroid/view/Surface;)I", + (void*) nativeAddOrUpdateStream }, { "nativeRemoveStream", "(JII)I", (void*) nativeRemoveStream }, { "nativeGetStreamConfigs", "(JII)[Landroid/media/tv/TvStreamConfig;", diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index fe4b7b9..308fcd8 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -1687,7 +1687,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { .setContentTitle(mContext.getString(R.string.ssl_ca_cert_warning)) .setContentText(contentText) .setContentIntent(notifyIntent) - .setOngoing(true) .setPriority(Notification.PRIORITY_HIGH) .setShowWhen(false) .setColor(mContext.getResources().getColor( @@ -4789,6 +4788,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); } } + sendChangedNotification(userHandle); } } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index 92ad1ad..d7f6130 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -374,6 +374,8 @@ public final class SystemServer { mSystemServiceManager.startService(UsageStatsService.class); mActivityManagerService.setUsageStatsManager( LocalServices.getService(UsageStatsManagerInternal.class)); + // Update after UsageStatsService is available, needed before performBootDexOpt. + mPackageManagerService.getUsageStatsIfNoPackageUsageInfo(); // Tracks whether the updatable WebView is in a ready state and watches for update installs. mSystemServiceManager.startService(WebViewUpdateService.class); @@ -416,6 +418,7 @@ public final class SystemServer { boolean disableSystemUI = SystemProperties.getBoolean("config.disable_systemui", false); boolean disableNonCoreServices = SystemProperties.getBoolean("config.disable_noncore", false); boolean disableNetwork = SystemProperties.getBoolean("config.disable_network", false); + boolean disableNetworkTime = SystemProperties.getBoolean("config.disable_networktime", false); boolean isEmulator = SystemProperties.get("ro.kernel.qemu").equals("1"); try { @@ -863,7 +866,7 @@ public final class SystemServer { reportWtf("starting SamplingProfiler Service", e); } - if (!disableNetwork) { + if (!disableNetwork && !disableNetworkTime) { try { Slog.i(TAG, "NetworkTimeUpdateService"); networkTimeUpdater = new NetworkTimeUpdateService(context); diff --git a/services/print/java/com/android/server/print/RemotePrintSpooler.java b/services/print/java/com/android/server/print/RemotePrintSpooler.java index 9496cae..7ab3840 100644 --- a/services/print/java/com/android/server/print/RemotePrintSpooler.java +++ b/services/print/java/com/android/server/print/RemotePrintSpooler.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.os.Binder; +import android.os.Build; import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; @@ -55,7 +56,8 @@ final class RemotePrintSpooler { private static final boolean DEBUG = false; - private static final long BIND_SPOOLER_SERVICE_TIMEOUT = 10000; + private static final long BIND_SPOOLER_SERVICE_TIMEOUT = + ("eng".equals(Build.TYPE)) ? 120000 : 10000; private final Object mLock = new Object(); diff --git a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java index c3d4ed9..c115339 100644 --- a/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/NetworkStatsServiceTest.java @@ -932,7 +932,6 @@ public class NetworkStatsServiceTest extends AndroidTestCase { expect(mSettings.getPollInterval()).andReturn(HOUR_IN_MILLIS).anyTimes(); expect(mSettings.getTimeCacheMaxAge()).andReturn(DAY_IN_MILLIS).anyTimes(); expect(mSettings.getSampleEnabled()).andReturn(true).anyTimes(); - expect(mSettings.getReportXtOverDev()).andReturn(true).anyTimes(); final Config config = new Config(bucketDuration, deleteAge, deleteAge); expect(mSettings.getDevConfig()).andReturn(config).anyTimes(); diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java index a70ebf4..b631331 100644 --- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java +++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java @@ -21,22 +21,15 @@ import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; -import com.android.internal.content.PackageHelper; +import android.test.AndroidTestCase; +import android.util.ArraySet; +import android.util.Log; + import com.android.internal.os.AtomicFile; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; -import java.util.HashSet; - -import android.os.Debug; -import android.os.Environment; -import android.os.IBinder; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.os.storage.IMountService; -import android.test.AndroidTestCase; -import android.util.Log; public class PackageManagerSettingsTests extends AndroidTestCase { @@ -182,11 +175,11 @@ public class PackageManagerSettingsTests extends AndroidTestCase { assertEquals(COMPONENT_ENABLED_STATE_ENABLED, ps.getEnabled(1)); // Enable/Disable a component - HashSet<String> components = new HashSet<String>(); + ArraySet<String> components = new ArraySet<String>(); String component1 = PACKAGE_NAME_1 + "/.Component1"; components.add(component1); ps.setDisabledComponents(components, 0); - HashSet<String> componentsDisabled = ps.getDisabledComponents(0); + ArraySet<String> componentsDisabled = ps.getDisabledComponents(0); assertEquals(1, componentsDisabled.size()); assertEquals(component1, componentsDisabled.toArray()[0]); boolean hasEnabled = diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 2ed9745..7ff246a 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -38,6 +38,7 @@ import android.os.Environment; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.os.Process; import android.os.RemoteException; import android.os.SystemClock; import android.os.UserHandle; @@ -349,8 +350,12 @@ public class UsageStatsService extends SystemService implements private class BinderService extends IUsageStatsManager.Stub { private boolean hasPermission(String callingPackage) { + final int callingUid = Binder.getCallingUid(); + if (callingUid == Process.SYSTEM_UID) { + return true; + } final int mode = mAppOps.checkOp(AppOpsManager.OP_GET_USAGE_STATS, - Binder.getCallingUid(), callingPackage); + callingUid, callingPackage); if (mode == AppOpsManager.MODE_DEFAULT) { // The default behavior here is to check if PackageManager has given the app // permission. diff --git a/telecomm/java/android/telecom/AudioState.java b/telecomm/java/android/telecom/AudioState.java index fc2fff4..d0e2860 100644 --- a/telecomm/java/android/telecom/AudioState.java +++ b/telecomm/java/android/telecom/AudioState.java @@ -16,7 +16,6 @@ package android.telecom; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; @@ -24,9 +23,7 @@ import java.util.Locale; /** * Encapsulates all audio states during a call. - * @hide */ -@SystemApi public final class AudioState implements Parcelable { /** Direct the audio stream through the device's earpiece. */ public static final int ROUTE_EARPIECE = 0x00000001; diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java index f934963..354fa2e 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -484,10 +484,10 @@ public final class Call { /** * Notifies this {@code Call} that an account has been selected and to proceed with placing - * an outgoing call. + * an outgoing call. Optionally sets this account as the default account. */ - public void phoneAccountSelected(PhoneAccountHandle accountHandle) { - mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle); + public void phoneAccountSelected(PhoneAccountHandle accountHandle, boolean setDefault) { + mInCallAdapter.phoneAccountSelected(mTelecomCallId, accountHandle, setDefault); } diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index b7b98bf..15cb786 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -16,8 +16,6 @@ package android.telecom; -import android.annotation.SystemApi; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -27,9 +25,7 @@ import java.util.concurrent.CopyOnWriteArraySet; /** * Represents a conference call which can contain any number of {@link Connection} objects. - * @hide */ -@SystemApi public abstract class Conference { /** @hide */ diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java index b5f6692..2932721 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -19,7 +19,6 @@ package android.telecom; import com.android.internal.telecom.IVideoCallback; import com.android.internal.telecom.IVideoProvider; -import android.annotation.SystemApi; import android.net.Uri; import android.os.Handler; import android.os.IBinder; @@ -44,9 +43,7 @@ import java.util.concurrent.ConcurrentHashMap; * Implementations are then responsible for updating the state of the {@code Connection}, and * must call {@link #destroy()} to signal to the framework that the {@code Connection} is no * longer used and associated resources may be recovered. - * @hide */ -@SystemApi public abstract class Connection { public static final int STATE_INITIALIZING = 0; @@ -876,7 +873,7 @@ public abstract class Connection { return mUnmodifiableConferenceableConnections; } - /** + /* * @hide */ public final void setConnectionService(ConnectionService connectionService) { @@ -901,6 +898,13 @@ public abstract class Connection { } /** + * @hide + */ + public final ConnectionService getConnectionService() { + return mConnectionService; + } + + /** * Sets the conference that this connection is a part of. This will fail if the connection is * already part of a conference call. {@link #resetConference} to un-set the conference first. * @@ -914,6 +918,7 @@ public abstract class Connection { mConference = conference; if (mConnectionService != null && mConnectionService.containsConference(conference)) { fireConferenceChanged(); + onConferenceChanged(); } return true; } @@ -929,6 +934,7 @@ public abstract class Connection { Log.d(this, "Conference reset"); mConference = null; fireConferenceChanged(); + onConferenceChanged(); } } @@ -1013,14 +1019,9 @@ public abstract class Connection { public void onPostDialContinue(boolean proceed) {} /** - * Merge this connection and the specified connection into a conference call. Once the - * connections are merged, the calls should be added to the an existing or new - * {@code Conference} instance. For new {@code Conference} instances, use - * {@code ConnectionService#addConference}. - * - * @param otherConnection The connection with which this connection should be conferenced. + * Notifies this Connection that the conference which is set on it has changed. */ - public void onConferenceWith(Connection otherConnection) {} + public void onConferenceChanged() {} static String toLogSafePhoneNumber(String number) { // For unknown number, log empty string. diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java index f691c17..71b481b 100644 --- a/telecomm/java/android/telecom/ConnectionRequest.java +++ b/telecomm/java/android/telecom/ConnectionRequest.java @@ -16,7 +16,6 @@ package android.telecom; -import android.annotation.SystemApi; import android.net.Uri; import android.os.Bundle; import android.os.Parcel; @@ -25,9 +24,7 @@ import android.os.Parcelable; /** * Simple data container encapsulating a request to some entity to * create a new {@link Connection}. - * @hide */ -@SystemApi public final class ConnectionRequest implements Parcelable { // TODO: Token to limit recursive invocations diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 6eee99d..649533e 100644 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -16,7 +16,6 @@ package android.telecom; -import android.annotation.SystemApi; import android.annotation.SdkConstant; import android.app.Service; import android.content.ComponentName; @@ -43,9 +42,7 @@ import java.util.concurrent.ConcurrentHashMap; /** * A {@link android.app.Service} that provides telephone connections to processes running on an * Android device. - * @hide */ -@SystemApi public abstract class ConnectionService extends Service { /** * The {@link Intent} that must be declared as handled by the service. diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java index 52c1284..9be0138 100644 --- a/telecomm/java/android/telecom/DisconnectCause.java +++ b/telecomm/java/android/telecom/DisconnectCause.java @@ -16,7 +16,6 @@ package android.telecom; -import android.annotation.SystemApi; import android.os.Parcel; import android.os.Parcelable; import android.media.ToneGenerator; @@ -29,9 +28,7 @@ import java.util.Objects; * cause of the disconnect. Optionally, it may include a localized label and/or localized description * to display to the user which is provided by the {@link ConnectionService}. It also may contain a * reason for the the disconnect, which is intended for logging and not for display to the user. - * @hide */ -@SystemApi public final class DisconnectCause implements Parcelable { /** Disconnected because of an unknown or unspecified reason. */ diff --git a/telecomm/java/android/telecom/GatewayInfo.java b/telecomm/java/android/telecom/GatewayInfo.java index 3efab0f..583c3e2 100644 --- a/telecomm/java/android/telecom/GatewayInfo.java +++ b/telecomm/java/android/telecom/GatewayInfo.java @@ -30,9 +30,7 @@ import android.text.TextUtils; * <li> Call the appropriate routing number * <li> Display information about how the call is being routed to the user * </ol> - * @hide */ -@SystemApi public class GatewayInfo implements Parcelable { private final String mGatewayProviderPackageName; diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java index fd3cf2e..62b8dea 100644 --- a/telecomm/java/android/telecom/InCallAdapter.java +++ b/telecomm/java/android/telecom/InCallAdapter.java @@ -189,14 +189,16 @@ public final class InCallAdapter { } /** - * Instructs Telecom to add a PhoneAccountHandle to the specified call + * Instructs Telecom to add a PhoneAccountHandle to the specified call. * - * @param callId The identifier of the call - * @param accountHandle The PhoneAccountHandle through which to place the call + * @param callId The identifier of the call. + * @param accountHandle The PhoneAccountHandle through which to place the call. + * @param setDefault {@code True} if this account should be set as the default for calls. */ - public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle) { + public void phoneAccountSelected(String callId, PhoneAccountHandle accountHandle, + boolean setDefault) { try { - mAdapter.phoneAccountSelected(callId, accountHandle); + mAdapter.phoneAccountSelected(callId, accountHandle, setDefault); } catch (RemoteException e) { } } diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java index 1d6d8bc..402df30 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -16,7 +16,6 @@ package android.telecom; -import android.annotation.SystemApi; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources.NotFoundException; @@ -35,9 +34,7 @@ import java.util.MissingResourceException; /** * Describes a distinct account, line of service or call placement method that the system * can use to place phone calls. - * @hide */ -@SystemApi public class PhoneAccount implements Parcelable { /** @@ -108,11 +105,17 @@ public class PhoneAccount implements Parcelable { */ public static final String SCHEME_SIP = "sip"; + /** + * Indicating no color is set. + */ + public static final int NO_COLOR = -1; + private final PhoneAccountHandle mAccountHandle; private final Uri mAddress; private final Uri mSubscriptionAddress; private final int mCapabilities; private final int mIconResId; + private final int mColor; private final CharSequence mLabel; private final CharSequence mShortDescription; private final List<String> mSupportedUriSchemes; @@ -123,6 +126,7 @@ public class PhoneAccount implements Parcelable { private Uri mSubscriptionAddress; private int mCapabilities; private int mIconResId; + private int mColor = NO_COLOR; private CharSequence mLabel; private CharSequence mShortDescription; private List<String> mSupportedUriSchemes = new ArrayList<String>(); @@ -144,6 +148,7 @@ public class PhoneAccount implements Parcelable { mSubscriptionAddress = phoneAccount.getSubscriptionAddress(); mCapabilities = phoneAccount.getCapabilities(); mIconResId = phoneAccount.getIconResId(); + mColor = phoneAccount.getColor(); mLabel = phoneAccount.getLabel(); mShortDescription = phoneAccount.getShortDescription(); mSupportedUriSchemes.addAll(phoneAccount.getSupportedUriSchemes()); @@ -169,6 +174,11 @@ public class PhoneAccount implements Parcelable { return this; } + public Builder setColor(int value) { + this.mColor = value; + return this; + } + public Builder setShortDescription(CharSequence value) { this.mShortDescription = value; return this; @@ -222,6 +232,7 @@ public class PhoneAccount implements Parcelable { mSubscriptionAddress, mCapabilities, mIconResId, + mColor, mLabel, mShortDescription, mSupportedUriSchemes); @@ -234,6 +245,7 @@ public class PhoneAccount implements Parcelable { Uri subscriptionAddress, int capabilities, int iconResId, + int color, CharSequence label, CharSequence shortDescription, List<String> supportedUriSchemes) { @@ -242,6 +254,7 @@ public class PhoneAccount implements Parcelable { mSubscriptionAddress = subscriptionAddress; mCapabilities = capabilities; mIconResId = iconResId; + mColor = color; mLabel = label; mShortDescription = shortDescription; mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes); @@ -286,6 +299,9 @@ public class PhoneAccount implements Parcelable { * The raw callback number used for this {@code PhoneAccount}, as distinct from * {@link #getAddress()}. For the majority of {@code PhoneAccount}s this should be registered * as {@code null}. It is used by the system for SIM-based {@code PhoneAccount} registration + * where {@link android.telephony.TelephonyManager#setLine1NumberForDisplay(String, String)} + * has been used to alter the callback number. + * <p> * * @return The subscription number, suitable for display to the user. */ @@ -371,6 +387,15 @@ public class PhoneAccount implements Parcelable { } /** + * A highlight color to use in displaying information about this {@code PhoneAccount}. + * + * @return A hexadecimal color value. + */ + public int getColor() { + return mColor; + } + + /** * An icon to represent this {@code PhoneAccount} in a user interface. * * @return An icon for this {@code PhoneAccount}. @@ -380,12 +405,17 @@ public class PhoneAccount implements Parcelable { } private Drawable getIcon(Context context, int resId) { + if (resId == 0) { + return null; + } + Context packageContext; try { packageContext = context.createPackageContext( mAccountHandle.getComponentName().getPackageName(), 0); } catch (PackageManager.NameNotFoundException e) { - Log.w(this, "Cannot find package %s", mAccountHandle.getComponentName().getPackageName()); + Log.w(this, "Cannot find package %s", + mAccountHandle.getComponentName().getPackageName()); return null; } try { @@ -413,6 +443,7 @@ public class PhoneAccount implements Parcelable { out.writeParcelable(mSubscriptionAddress, 0); out.writeInt(mCapabilities); out.writeInt(mIconResId); + out.writeInt(mColor); out.writeCharSequence(mLabel); out.writeCharSequence(mShortDescription); out.writeList(mSupportedUriSchemes); @@ -439,6 +470,7 @@ public class PhoneAccount implements Parcelable { mSubscriptionAddress = in.readParcelable(getClass().getClassLoader()); mCapabilities = in.readInt(); mIconResId = in.readInt(); + mColor = in.readInt(); mLabel = in.readCharSequence(); mShortDescription = in.readCharSequence(); @@ -446,4 +478,19 @@ public class PhoneAccount implements Parcelable { in.readList(supportedUriSchemes, classLoader); mSupportedUriSchemes = Collections.unmodifiableList(supportedUriSchemes); } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder().append("[PhoneAccount: ") + .append(mAccountHandle) + .append(" Capabilities: ") + .append(mCapabilities) + .append(" Schemes: "); + for (String scheme : mSupportedUriSchemes) { + sb.append(scheme) + .append(" "); + } + sb.append("]"); + return sb.toString(); + } } diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java index 652befe5..768188b 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -16,7 +16,6 @@ package android.telecom; -import android.annotation.SystemApi; import android.content.ComponentName; import android.os.Parcel; import android.os.Parcelable; @@ -25,9 +24,7 @@ import java.util.Objects; /** * The unique identifier for a {@link PhoneAccount}. - * @hide */ -@SystemApi public class PhoneAccountHandle implements Parcelable { private ComponentName mComponentName; private String mId; @@ -74,9 +71,11 @@ public class PhoneAccountHandle implements Parcelable { @Override public String toString() { + // Note: Log.pii called for mId as it can contain personally identifying phone account + // information such as SIP account IDs. return new StringBuilder().append(mComponentName) .append(", ") - .append(mId) + .append(Log.pii(mId)) .toString(); } diff --git a/telecomm/java/android/telecom/PhoneCapabilities.java b/telecomm/java/android/telecom/PhoneCapabilities.java index de2abcb..9c67503 100644 --- a/telecomm/java/android/telecom/PhoneCapabilities.java +++ b/telecomm/java/android/telecom/PhoneCapabilities.java @@ -16,14 +16,10 @@ package android.telecom; -import android.annotation.SystemApi; - /** * Defines capabilities a phone call can support, such as conference calling and video telephony. * Also defines properties of a phone call, such as whether it is using VoLTE technology. - * @hide */ -@SystemApi public final class PhoneCapabilities { /** Call can currently be put on hold or unheld. */ public static final int HOLD = 0x00000001; @@ -96,43 +92,65 @@ public final class PhoneCapabilities { | ADD_CALL | RESPOND_VIA_TEXT | MUTE | MANAGE_CONFERENCE | SEPARATE_FROM_CONFERENCE | DISCONNECT_FROM_CONFERENCE; + /** + * Whether this set of capabilities supports the specified capability. + * @param capabilities The set of capabilities. + * @param capability The capability to check capabilities for. + * @return Whether the specified capability is supported. + * @hide + */ + public static boolean can(int capabilities, int capability) { + return (capabilities & capability) != 0; + } + + /** + * Removes the specified capability from the set of capabilities and returns the new set. + * @param capabilities The set of capabilities. + * @param capability The capability to remove from the set. + * @return The set of capabilities, with the capability removed. + * @hide + */ + public static int remove(int capabilities, int capability) { + return capabilities & ~capability; + } + public static String toString(int capabilities) { StringBuilder builder = new StringBuilder(); builder.append("[Capabilities:"); - if ((capabilities & HOLD) != 0) { + if (can(capabilities, HOLD)) { builder.append(" HOLD"); } - if ((capabilities & SUPPORT_HOLD) != 0) { + if (can(capabilities, SUPPORT_HOLD)) { builder.append(" SUPPORT_HOLD"); } - if ((capabilities & MERGE_CONFERENCE) != 0) { + if (can(capabilities, MERGE_CONFERENCE)) { builder.append(" MERGE_CONFERENCE"); } - if ((capabilities & SWAP_CONFERENCE) != 0) { + if (can(capabilities, SWAP_CONFERENCE)) { builder.append(" SWAP_CONFERENCE"); } - if ((capabilities & ADD_CALL) != 0) { + if (can(capabilities, ADD_CALL)) { builder.append(" ADD_CALL"); } - if ((capabilities & RESPOND_VIA_TEXT) != 0) { + if (can(capabilities, RESPOND_VIA_TEXT)) { builder.append(" RESPOND_VIA_TEXT"); } - if ((capabilities & MUTE) != 0) { + if (can(capabilities, MUTE)) { builder.append(" MUTE"); } - if ((capabilities & MANAGE_CONFERENCE) != 0) { + if (can(capabilities, MANAGE_CONFERENCE)) { builder.append(" MANAGE_CONFERENCE"); } - if ((capabilities & SUPPORTS_VT_LOCAL) != 0) { + if (can(capabilities, SUPPORTS_VT_LOCAL)) { builder.append(" SUPPORTS_VT_LOCAL"); } - if ((capabilities & SUPPORTS_VT_REMOTE) != 0) { + if (can(capabilities, SUPPORTS_VT_REMOTE)) { builder.append(" SUPPORTS_VT_REMOTE"); } - if ((capabilities & VoLTE) != 0) { + if (can(capabilities, VoLTE)) { builder.append(" VoLTE"); } - if ((capabilities & VoWIFI) != 0) { + if (can(capabilities, VoWIFI)) { builder.append(" VoWIFI"); } builder.append("]"); diff --git a/telecomm/java/android/telecom/RemoteConference.java b/telecomm/java/android/telecom/RemoteConference.java index b548274..eba7580 100644 --- a/telecomm/java/android/telecom/RemoteConference.java +++ b/telecomm/java/android/telecom/RemoteConference.java @@ -18,7 +18,6 @@ package android.telecom; import com.android.internal.telecom.IConnectionService; -import android.annotation.SystemApi; import android.os.RemoteException; import java.util.ArrayList; @@ -30,9 +29,7 @@ import java.util.concurrent.CopyOnWriteArraySet; /** * Represents a conference call which can contain any number of {@link Connection} objects. - * @hide */ -@SystemApi public final class RemoteConference { public abstract static class Callback { diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java index 4a89692..9a094df 100644 --- a/telecomm/java/android/telecom/RemoteConnection.java +++ b/telecomm/java/android/telecom/RemoteConnection.java @@ -20,7 +20,6 @@ import com.android.internal.telecom.IConnectionService; import com.android.internal.telecom.IVideoCallback; import com.android.internal.telecom.IVideoProvider; -import android.annotation.SystemApi; import android.net.Uri; import android.os.IBinder; import android.os.RemoteException; @@ -38,9 +37,7 @@ import java.util.concurrent.ConcurrentHashMap; * * @see ConnectionService#createRemoteOutgoingConnection(PhoneAccountHandle, ConnectionRequest) * @see ConnectionService#createRemoteIncomingConnection(PhoneAccountHandle, ConnectionRequest) - * @hide */ -@SystemApi public final class RemoteConnection { public static abstract class Callback { diff --git a/telecomm/java/android/telecom/StatusHints.java b/telecomm/java/android/telecom/StatusHints.java index dd3a639..a32eae7 100644 --- a/telecomm/java/android/telecom/StatusHints.java +++ b/telecomm/java/android/telecom/StatusHints.java @@ -16,7 +16,6 @@ package android.telecom; -import android.annotation.SystemApi; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageManager; @@ -30,9 +29,7 @@ import java.util.Objects; /** * Contains status label and icon displayed in the in-call UI. - * @hide */ -@SystemApi public final class StatusHints implements Parcelable { private final ComponentName mPackageName; diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java index f3358f8..2652b45 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -31,7 +31,6 @@ import java.util.List; /** * Provides access to Telecom-related functionality. - * TODO: Move this all into PhoneManager. */ public class TelecomManager { @@ -60,7 +59,6 @@ public class TelecomManager { /** * The {@link android.content.Intent} action used to configure a * {@link android.telecom.ConnectionService}. - * @hide */ public static final String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE"; @@ -74,7 +72,6 @@ public class TelecomManager { /** * The {@link android.content.Intent} action used to show the settings page used to configure * {@link PhoneAccount} preferences. - * @hide */ public static final String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS"; @@ -105,7 +102,6 @@ public class TelecomManager { * {@link PhoneAccountHandle} to use when making the call. * <p class="note"> * Retrieve with {@link android.content.Intent#getParcelableExtra(String)}. - * @hide */ public static final String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE"; @@ -154,7 +150,6 @@ public class TelecomManager { /** * Optional extra for {@link android.telephony.TelephonyManager#ACTION_PHONE_STATE_CHANGED} * containing the component name of the associated connection service. - * @hide */ public static final String EXTRA_CONNECTION_SERVICE = "android.telecom.extra.CONNECTION_SERVICE"; @@ -190,7 +185,6 @@ public class TelecomManager { * {@link ConnectionService}s which interact with {@link RemoteConnection}s should only populate * this if the {@link android.telephony.TelephonyManager#getLine1Number()} value, as that is the * user's expected caller ID. - * @hide */ public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER"; @@ -437,7 +431,6 @@ public class TelecomManager { * {@code PhoneAccount}. * * @return The phone account handle of the current connection manager. - * @hide */ public PhoneAccountHandle getConnectionManager() { return getSimCallManager(); @@ -495,7 +488,6 @@ public class TelecomManager { * * @return {@code true} if the device has more than one account registered and {@code false} * otherwise. - * @hide */ public boolean hasMultipleCallCapableAccounts() { return getCallCapablePhoneAccounts().size() > 1; @@ -505,7 +497,6 @@ public class TelecomManager { * Returns a list of all {@link PhoneAccount}s registered for the calling package. * * @return A list of {@code PhoneAccountHandle} objects. - * @hide */ public List<PhoneAccountHandle> getPhoneAccountsForPackage() { try { @@ -524,7 +515,6 @@ public class TelecomManager { * * @param account The {@link PhoneAccountHandle}. * @return The {@link PhoneAccount} object. - * @hide */ public PhoneAccount getPhoneAccount(PhoneAccountHandle account) { try { @@ -595,9 +585,7 @@ public class TelecomManager { * Register a {@link PhoneAccount} for use by the system. * * @param account The complete {@link PhoneAccount}. - * @hide */ - @SystemApi public void registerPhoneAccount(PhoneAccount account) { try { if (isServiceConnected()) { @@ -612,9 +600,7 @@ public class TelecomManager { * Remove a {@link PhoneAccount} registration from the system. * * @param accountHandle A {@link PhoneAccountHandle} for the {@link PhoneAccount} to unregister. - * @hide */ - @SystemApi public void unregisterPhoneAccount(PhoneAccountHandle accountHandle) { try { if (isServiceConnected()) { @@ -627,9 +613,7 @@ public class TelecomManager { /** * Remove all Accounts that belong to the calling package from the system. - * @hide */ - @SystemApi public void clearAccounts() { try { if (isServiceConnected()) { @@ -656,13 +640,33 @@ public class TelecomManager { } /** + * Return whether a given phone number is the configured voicemail number for a + * particular phone account. + * + * @param accountHandle The handle for the account to check the voicemail number against + * @param number The number to look up. + * + * @hide + */ + @SystemApi + public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) { + try { + if (isServiceConnected()) { + return getTelecomService().isVoiceMailNumber(accountHandle, number); + } + } catch (RemoteException e) { + Log.e(TAG, "RemoteException calling isInCall().", e); + } + return false; + } + + /** * Returns whether there is an ongoing phone call (can be in dialing, ringing, active or holding * states). * <p> * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE} * </p> */ - @SystemApi public boolean isInCall() { try { if (isServiceConnected()) { @@ -813,9 +817,7 @@ public class TelecomManager { * {@link #registerPhoneAccount}. * @param extras A bundle that will be passed through to * {@link ConnectionService#onCreateIncomingConnection}. - * @hide */ - @SystemApi public void addNewIncomingCall(PhoneAccountHandle phoneAccount, Bundle extras) { try { if (isServiceConnected()) { diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl index 138a877..863fff2 100644 --- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl +++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl @@ -46,7 +46,8 @@ oneway interface IInCallAdapter { void postDialContinue(String callId, boolean proceed); - void phoneAccountSelected(String callId, in PhoneAccountHandle accountHandle); + void phoneAccountSelected(String callId, in PhoneAccountHandle accountHandle, + boolean setDefault); void conference(String callId, String otherCallId); diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl index f1cf885..91f44b9 100644 --- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl +++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl @@ -115,6 +115,11 @@ interface ITelecomService { void clearAccounts(String packageName); /** + * @see TelecomServiceImpl#isVoiceMailNumber + */ + boolean isVoiceMailNumber(in PhoneAccountHandle accountHandle, String number); + + /** * @see TelecomServiceImpl#getDefaultPhoneApp */ ComponentName getDefaultPhoneApp(); diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java index 30799f8..897702d 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -976,6 +976,8 @@ public class PhoneNumberUtils return 0xc; } else if (c == WILD) { return 0xd; + } else if (c == WAIT) { + return 0xe; } else { throw new RuntimeException ("invalid char for BCD " + c); } @@ -1568,7 +1570,7 @@ public class PhoneNumberUtils * listed in the RIL / SIM, otherwise return false. * @hide */ - public static boolean isEmergencyNumber(long subId, String number) { + public static boolean isEmergencyNumber(int subId, String number) { // Return true only if the specified number *exactly* matches // one of the emergency numbers listed by the RIL / SIM. return isEmergencyNumberInternal(subId, number, true /* useExactMatch */); @@ -1618,7 +1620,7 @@ public class PhoneNumberUtils * same digits as any of those emergency numbers. * @hide */ - public static boolean isPotentialEmergencyNumber(long subId, String number) { + public static boolean isPotentialEmergencyNumber(int subId, String number) { // Check against the emergency numbers listed by the RIL / SIM, // and *don't* require an exact match. return isEmergencyNumberInternal(subId, number, false /* useExactMatch */); @@ -1667,7 +1669,7 @@ public class PhoneNumberUtils * @return true if the number is in the list of emergency numbers * listed in the RIL / sim, otherwise return false. */ - private static boolean isEmergencyNumberInternal(long subId, String number, + private static boolean isEmergencyNumberInternal(int subId, String number, boolean useExactMatch) { return isEmergencyNumberInternal(subId, number, null, useExactMatch); } @@ -1696,7 +1698,7 @@ public class PhoneNumberUtils * otherwise false * @hide */ - public static boolean isEmergencyNumber(long subId, String number, String defaultCountryIso) { + public static boolean isEmergencyNumber(int subId, String number, String defaultCountryIso) { return isEmergencyNumberInternal(subId, number, defaultCountryIso, true /* useExactMatch */); @@ -1748,7 +1750,7 @@ public class PhoneNumberUtils * any of those emergency numbers. * @hide */ - public static boolean isPotentialEmergencyNumber(long subId, String number, + public static boolean isPotentialEmergencyNumber(int subId, String number, String defaultCountryIso) { return isEmergencyNumberInternal(subId, number, defaultCountryIso, @@ -1792,7 +1794,7 @@ public class PhoneNumberUtils * @return true if the number is an emergency number for the specified country. * @hide */ - private static boolean isEmergencyNumberInternal(long subId, String number, + private static boolean isEmergencyNumberInternal(int subId, String number, String defaultCountryIso, boolean useExactMatch) { // If the number passed in is null, just return false: @@ -1813,23 +1815,31 @@ public class PhoneNumberUtils // to the list. number = extractNetworkPortionAlt(number); - String numbers = ""; + Rlog.d(LOG_TAG, "subId:" + subId + ", number: " + number + ", defaultCountryIso:" + + ((defaultCountryIso == null) ? "NULL" : defaultCountryIso)); + + String emergencyNumbers = ""; int slotId = SubscriptionManager.getSlotId(subId); - // retrieve the list of emergency numbers - // check read-write ecclist property first - String ecclist = (slotId <= 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); - numbers = SystemProperties.get(ecclist); + if (slotId >= 0) { + // retrieve the list of emergency numbers + // check read-write ecclist property first + String ecclist = (slotId == 0) ? "ril.ecclist" : ("ril.ecclist" + slotId); + + emergencyNumbers = SystemProperties.get(ecclist, ""); + } - if (TextUtils.isEmpty(numbers)) { + Rlog.d(LOG_TAG, "slotId:" + slotId + ", emergencyNumbers: " + emergencyNumbers); + + if (TextUtils.isEmpty(emergencyNumbers)) { // then read-only ecclist property since old RIL only uses this - numbers = SystemProperties.get("ro.ril.ecclist"); + emergencyNumbers = SystemProperties.get("ro.ril.ecclist"); } - if (!TextUtils.isEmpty(numbers)) { + if (!TextUtils.isEmpty(emergencyNumbers)) { // searches through the comma-separated list for a match, // return true if one is found. - for (String emergencyNum : numbers.split(",")) { + for (String emergencyNum : emergencyNumbers.split(",")) { // It is not possible to append additional digits to an emergency number to dial // the number in Brazil - it won't connect. if (useExactMatch || "BR".equalsIgnoreCase(defaultCountryIso)) { @@ -1849,6 +1859,23 @@ public class PhoneNumberUtils Rlog.d(LOG_TAG, "System property doesn't provide any emergency numbers." + " Use embedded logic for determining ones."); + // If slot id is invalid, means that there is no sim card. + // According spec 3GPP TS22.101, the following numbers should be + // ECC numbers when SIM/USIM is not present. + emergencyNumbers = ((slotId < 0) ? "112,911,000,08,110,118,119,999" : "112,911"); + + for (String emergencyNum : emergencyNumbers.split(",")) { + if (useExactMatch) { + if (number.equals(emergencyNum)) { + return true; + } + } else { + if (number.startsWith(emergencyNum)) { + return true; + } + } + } + // No ecclist system property, so use our own list. if (defaultCountryIso != null) { ShortNumberUtil util = new ShortNumberUtil(); @@ -1857,13 +1884,9 @@ public class PhoneNumberUtils } else { return util.connectsToEmergencyNumber(number, defaultCountryIso); } - } else { - if (useExactMatch) { - return (number.equals("112") || number.equals("911")); - } else { - return (number.startsWith("112") || number.startsWith("911")); - } } + + return false; } /** @@ -1888,7 +1911,7 @@ public class PhoneNumberUtils * is currently in. * @hide */ - public static boolean isLocalEmergencyNumber(Context context, long subId, String number) { + public static boolean isLocalEmergencyNumber(Context context, int subId, String number) { return isLocalEmergencyNumberInternal(subId, number, context, true /* useExactMatch */); @@ -1942,7 +1965,7 @@ public class PhoneNumberUtils * * @hide */ - public static boolean isPotentialLocalEmergencyNumber(Context context, long subId, + public static boolean isPotentialLocalEmergencyNumber(Context context, int subId, String number) { return isLocalEmergencyNumberInternal(subId, number, context, @@ -1991,7 +2014,7 @@ public class PhoneNumberUtils * local country, based on the CountryDetector. * @hide */ - private static boolean isLocalEmergencyNumberInternal(long subId, String number, + private static boolean isLocalEmergencyNumberInternal(int subId, String number, Context context, boolean useExactMatch) { String countryIso; @@ -2034,7 +2057,7 @@ public class PhoneNumberUtils * to read the VM number. * @hide */ - public static boolean isVoiceMailNumber(long subId, String number) { + public static boolean isVoiceMailNumber(int subId, String number) { String vmNumber; try { @@ -2773,7 +2796,7 @@ public class PhoneNumberUtils /** * Returns Default voice subscription Id. */ - private static long getDefaultVoiceSubId() { + private static int getDefaultVoiceSubId() { return SubscriptionManager.getDefaultVoiceSubId(); } //==== End of utility methods used only in compareStrictly() ===== diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java index 0dcd7c6..2f1a8da 100644 --- a/telephony/java/android/telephony/PhoneStateListener.java +++ b/telephony/java/android/telephony/PhoneStateListener.java @@ -20,6 +20,7 @@ import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; +import android.telephony.SubscriptionManager; import android.telephony.CellLocation; import android.telephony.CellInfo; import android.telephony.VoLteServiceState; @@ -31,6 +32,7 @@ import android.telephony.PreciseCallState; import android.telephony.PreciseDataConnectionState; import com.android.internal.telephony.IPhoneStateListener; +import com.android.internal.telephony.PhoneConstants; import java.util.List; @@ -225,7 +227,7 @@ public class PhoneStateListener { * @hide */ /** @hide */ - protected long mSubId = 0; + protected int mSubId = SubscriptionManager.INVALID_SUB_ID; private final Handler mHandler; @@ -250,10 +252,10 @@ public class PhoneStateListener { /** * Create a PhoneStateListener for the Phone using the specified subscription. * This class requires Looper.myLooper() not return null. To supply your - * own non-null Looper use PhoneStateListener(long subId, Looper looper) below. + * own non-null Looper use PhoneStateListener(int subId, Looper looper) below. * @hide */ - public PhoneStateListener(long subId) { + public PhoneStateListener(int subId) { this(subId, Looper.myLooper()); } @@ -262,7 +264,7 @@ public class PhoneStateListener { * and non-null Looper. * @hide */ - public PhoneStateListener(long subId, Looper looper) { + public PhoneStateListener(int subId, Looper looper) { if (DBG) log("ctor: subId=" + subId + " looper=" + looper); mSubId = subId; mHandler = new Handler(looper) { diff --git a/telephony/java/android/telephony/RadioAccessFamily.aidl b/telephony/java/android/telephony/RadioAccessFamily.aidl new file mode 100644 index 0000000..f42e134 --- /dev/null +++ b/telephony/java/android/telephony/RadioAccessFamily.aidl @@ -0,0 +1,19 @@ +/* +* 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 android.telephony; + +parcelable RadioAccessFamily;
\ No newline at end of file diff --git a/telephony/java/android/telephony/RadioAccessFamily.java b/telephony/java/android/telephony/RadioAccessFamily.java new file mode 100644 index 0000000..dd4c45d --- /dev/null +++ b/telephony/java/android/telephony/RadioAccessFamily.java @@ -0,0 +1,135 @@ +/* +* 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 android.telephony; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * Object to indicate the phone radio type and access technology. + * + * @hide + */ +public class RadioAccessFamily implements Parcelable { + + // Radio Access Family + public static final int RAF_UNKNOWN = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN); + public static final int RAF_GPRS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GPRS); + public static final int RAF_EDGE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EDGE); + public static final int RAF_UMTS = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_UMTS); + public static final int RAF_IS95A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95A); + public static final int RAF_IS95B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_IS95B); + public static final int RAF_1xRTT = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_1xRTT); + public static final int RAF_EVDO_0 = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_0); + public static final int RAF_EVDO_A = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_A); + public static final int RAF_HSDPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSDPA); + public static final int RAF_HSUPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSUPA); + public static final int RAF_HSPA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPA); + public static final int RAF_EVDO_B = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EVDO_B); + public static final int RAF_EHRPD = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_EHRPD); + public static final int RAF_LTE = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_LTE); + public static final int RAF_HSPAP = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_HSPAP); + public static final int RAF_GSM = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_GSM); + public static final int RAF_TD_SCDMA = (1 << ServiceState.RIL_RADIO_TECHNOLOGY_TD_SCDMA); + + /* Phone ID of phone */ + private int mPhoneId; + + /* Radio Access Family */ + private int mRadioAccessFamily; + + /** + * Constructor. + * + * @param phoneId the phone ID + * @param radioAccessFamily the phone radio access family defined + * in RadioAccessFamily. It's a bit mask value to represent + * the support type. + */ + public RadioAccessFamily(int phoneId, int radioAccessFamily) { + mPhoneId = phoneId; + mRadioAccessFamily = radioAccessFamily; + } + + /** + * Get phone ID. + * + * @return phone ID + */ + public int getPhoneId() { + return mPhoneId; + } + + /** + * get radio access family. + * + * @return radio access family + */ + public int getRadioAccessFamily() { + return mRadioAccessFamily; + } + + @Override + public String toString() { + String ret = "{ mPhoneId = " + mPhoneId + + ", mRadioAccessFamily = " + mRadioAccessFamily + + "}"; + return ret; + } + + /** + * Implement the Parcelable interface. + * + * @return describe content + */ + @Override + public int describeContents() { + return 0; + } + + /** + * Implement the Parcelable interface. + * + * @param outParcel The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. + */ + public void writeToParcel(Parcel outParcel, int flags) { + outParcel.writeInt(mPhoneId); + outParcel.writeInt(mRadioAccessFamily); + } + + /** + * Implement the Parcelable interface. + */ + public static final Creator<RadioAccessFamily> CREATOR = + new Creator<RadioAccessFamily>() { + + @Override + public RadioAccessFamily createFromParcel(Parcel in) { + int phoneId = in.readInt(); + int radioAccessFamily = in.readInt(); + + return new RadioAccessFamily(phoneId, radioAccessFamily); + } + + @Override + public RadioAccessFamily[] newArray(int size) { + return new RadioAccessFamily[size]; + } + }; +} + diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java index 52d0516..8c2a4eb 100644 --- a/telephony/java/android/telephony/ServiceState.java +++ b/telephony/java/android/telephony/ServiceState.java @@ -864,4 +864,23 @@ public class ServiceState implements Parcelable { || radioTechnology == RIL_RADIO_TECHNOLOGY_EVDO_B || radioTechnology == RIL_RADIO_TECHNOLOGY_EHRPD; } + + /** + * Returns a merged ServiceState consisting of the base SS with voice settings from the + * voice SS. The voice SS is only used if it is IN_SERVICE (otherwise the base SS is returned). + * @hide + * */ + public static ServiceState mergeServiceStates(ServiceState baseSs, ServiceState voiceSs) { + if (voiceSs.mVoiceRegState != STATE_IN_SERVICE) { + return baseSs; + } + + ServiceState newSs = new ServiceState(baseSs); + + // voice overrides + newSs.mVoiceRegState = voiceSs.mVoiceRegState; + newSs.mIsEmergencyOnly = false; // only get here if voice is IN_SERVICE + + return newSs; + } } diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java index 805f787..4a3d67e 100644 --- a/telephony/java/android/telephony/SubInfoRecord.java +++ b/telephony/java/android/telephony/SubInfoRecord.java @@ -16,12 +16,12 @@ package android.telephony; +import android.graphics.drawable.BitmapDrawable; import android.os.Parcel; import android.os.Parcelable; /** * A Parcelable class for Subscription Information. - * @hide - to be unhidden */ public class SubInfoRecord implements Parcelable { @@ -29,7 +29,7 @@ public class SubInfoRecord implements Parcelable { * Subscription Identifier, this is a device unique number * and not an index into an array */ - public long subId; + public int subId; /** The GID for a SIM that maybe associated with this subscription, empty if unknown */ public String iccId; /** @@ -91,7 +91,7 @@ public class SubInfoRecord implements Parcelable { this.mnc = 0; } - public SubInfoRecord(long subId, String iccId, int slotId, String displayName, int nameSource, + public SubInfoRecord(int subId, String iccId, int slotId, String displayName, int nameSource, int color, String number, int displayFormat, int roaming, int[] iconRes, int mcc, int mnc) { this.subId = subId; @@ -108,10 +108,35 @@ public class SubInfoRecord implements Parcelable { this.mnc = mnc; } + /** + * Returns the string displayed to the user that identifies this subscription + */ + public String getLabel() { + return this.displayName; + } + + /** + * Return the icon used to identify this SIM. + * TODO: return the correct drawable. + */ + public BitmapDrawable getIconDrawable() { + return new BitmapDrawable(); + } + + /** + * Return the color to be used for when displaying to the user. This is the value of the color. + * ex: 0x00ff00 + */ + public int getColor() { + // Note: This color is currently an index into a list of drawables, but this is soon to + // change. + return this.color; + } + public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() { @Override public SubInfoRecord createFromParcel(Parcel source) { - long subId = source.readLong(); + int subId = source.readInt(); String iccId = source.readString(); int slotId = source.readInt(); String displayName = source.readString(); @@ -137,7 +162,7 @@ public class SubInfoRecord implements Parcelable { @Override public void writeToParcel(Parcel dest, int flags) { - dest.writeLong(subId); + dest.writeInt(subId); dest.writeString(iccId); dest.writeInt(slotId); dest.writeString(displayName); diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index fe68263..c3ad826 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -37,8 +37,6 @@ import java.util.List; * * The android.Manifest.permission.READ_PHONE_STATE to retrieve the information, except * getActiveSubIdList and getActiveSubIdCount for which no permission is needed. - * - * @hide - to be unhidden */ public class SubscriptionManager implements BaseColumns { private static final String LOG_TAG = "SUB"; @@ -46,31 +44,35 @@ public class SubscriptionManager implements BaseColumns { private static final boolean VDBG = false; /** An invalid phone identifier */ - /** @hide - to be unhidden */ public static final int INVALID_PHONE_ID = -1000; /** Indicates the caller wants the default phone id. */ - /** @hide - to be unhidden */ public static final int DEFAULT_PHONE_ID = Integer.MAX_VALUE; /** An invalid slot identifier */ - /** @hide - to be unhidden */ public static final int INVALID_SLOT_ID = -1000; /** Indicates the caller wants the default slot id. */ /** @hide */ public static final int DEFAULT_SLOT_ID = Integer.MAX_VALUE; - /** Indicates the user should be asked which sub to use. */ - /** @hide */ - public static final long ASK_USER_SUB_ID = -1001; + /** Indicates the user should be asked which subscription to use. */ + public static final int ASK_USER_SUB_ID = -1001; /** An invalid subscription identifier */ - public static final long INVALID_SUB_ID = -1000; + public static final int INVALID_SUB_ID = -1000; /** Indicates the caller wants the default sub id. */ - /** @hide - to be unhidden */ - public static final long DEFAULT_SUB_ID = Long.MAX_VALUE; + public static final int DEFAULT_SUB_ID = Integer.MAX_VALUE; + + /** Minimum possible subid that represents a subscription */ + /** @hide */ + public static final int MIN_SUB_ID_VALUE = 0; + + /** Maximum possible subid that represents a subscription */ + /** @hide */ + public static final int MAX_SUB_ID_VALUE = DEFAULT_SUB_ID - 1; + /** @hide */ public static final Uri CONTENT_URI = Uri.parse("content://telephony/siminfo"); @@ -114,7 +116,6 @@ public class SubscriptionManager implements BaseColumns { public static final String SIM_ID = "sim_id"; /** SIM is not inserted */ - /** @hide - to be unhidden */ public static final int SIM_NOT_INSERTED = -1; /** @@ -263,9 +264,8 @@ public class SubscriptionManager implements BaseColumns { * Get the SubInfoRecord associated with the subId * @param subId The unique SubInfoRecord index in database * @return SubInfoRecord, maybe null - * @hide - to be unhidden */ - public static SubInfoRecord getSubInfoForSubscriber(long subId) { + public static SubInfoRecord getSubInfoForSubscriber(int subId) { if (!isValidSubId(subId)) { logd("[getSubInfoForSubscriberx]- invalid subId"); return null; @@ -321,7 +321,6 @@ public class SubscriptionManager implements BaseColumns { * Get the SubInfoRecord according to slotId * @param slotId the slot which the SIM is inserted * @return SubInfoRecord list, maybe empty but not null - * @hide - to be unhidden */ public static List<SubInfoRecord> getSubInfoUsingSlotId(int slotId) { // FIXME: Consider never returning null @@ -377,7 +376,6 @@ public class SubscriptionManager implements BaseColumns { /** * Get the SubInfoRecord(s) of the currently inserted SIM(s) * @return Array list of currently inserted SubInfoRecord(s) maybe empty but not null - * @hide - to be unhidden */ public static List<SubInfoRecord> getActiveSubInfoList() { List<SubInfoRecord> result = null; @@ -477,7 +475,7 @@ public class SubscriptionManager implements BaseColumns { * @return the number of records updated * @hide */ - public static int setColor(int color, long subId) { + public static int setColor(int color, int subId) { if (VDBG) logd("[setColor]+ color:" + color + " subId:" + subId); int size = sSimBackgroundDarkRes.length; if (!isValidSubId(subId) || color < 0 || color >= size) { @@ -507,7 +505,7 @@ public class SubscriptionManager implements BaseColumns { * @return the number of records updated * @hide */ - public static int setDisplayName(String displayName, long subId) { + public static int setDisplayName(String displayName, int subId) { return setDisplayName(displayName, subId, NAME_SOURCE_UNDEFINDED); } @@ -520,7 +518,7 @@ public class SubscriptionManager implements BaseColumns { * @return the number of records updated or -1 if invalid subId * @hide */ - public static int setDisplayName(String displayName, long subId, long nameSource) { + public static int setDisplayName(String displayName, int subId, long nameSource) { if (VDBG) { logd("[setDisplayName]+ displayName:" + displayName + " subId:" + subId + " nameSource:" + nameSource); @@ -552,7 +550,7 @@ public class SubscriptionManager implements BaseColumns { * @return the number of records updated * @hide */ - public static int setDisplayNumber(String number, long subId) { + public static int setDisplayNumber(String number, int subId) { if (number == null || !isValidSubId(subId)) { logd("[setDisplayNumber]- fail"); return -1; @@ -580,7 +578,7 @@ public class SubscriptionManager implements BaseColumns { * @return the number of records updated * @hide */ - public static int setDisplayNumberFormat(int format, long subId) { + public static int setDisplayNumberFormat(int format, int subId) { if (VDBG) logd("[setDisplayNumberFormat]+ format:" + format + " subId:" + subId); if (format < 0 || !isValidSubId(subId)) { logd("[setDisplayNumberFormat]- fail, return -1"); @@ -609,7 +607,7 @@ public class SubscriptionManager implements BaseColumns { * @return the number of records updated * @hide */ - public static int setDataRoaming(int roaming, long subId) { + public static int setDataRoaming(int roaming, int subId) { if (VDBG) logd("[setDataRoaming]+ roaming:" + roaming + " subId:" + subId); if (roaming < 0 || !isValidSubId(subId)) { logd("[setDataRoaming]- fail"); @@ -634,9 +632,8 @@ public class SubscriptionManager implements BaseColumns { * Get slotId associated with the subscription. * @return slotId as a positive integer or a negative value if an error either * SIM_NOT_INSERTED or INVALID_SLOT_ID. - * @hide - to be unhidden */ - public static int getSlotId(long subId) { + public static int getSlotId(int subId) { if (!isValidSubId(subId)) { logd("[getSlotId]- fail"); } @@ -657,13 +654,13 @@ public class SubscriptionManager implements BaseColumns { } /** @hide */ - public static long[] getSubId(int slotId) { + public static int[] getSubId(int slotId) { if (!isValidSlotId(slotId)) { logd("[getSubId]- fail"); return null; } - long[] subId = null; + int[] subId = null; try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -678,7 +675,7 @@ public class SubscriptionManager implements BaseColumns { } /** @hide */ - public static int getPhoneId(long subId) { + public static int getPhoneId(int subId) { if (!isValidSubId(subId)) { logd("[getPhoneId]- fail"); return INVALID_PHONE_ID; @@ -735,8 +732,8 @@ public class SubscriptionManager implements BaseColumns { * getDefaultDataSubId(). * @hide */ - public static long getDefaultSubId() { - long subId = INVALID_SUB_ID; + public static int getDefaultSubId() { + int subId = INVALID_SUB_ID; try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -752,8 +749,8 @@ public class SubscriptionManager implements BaseColumns { } /** @hide */ - public static long getDefaultVoiceSubId() { - long subId = INVALID_SUB_ID; + public static int getDefaultVoiceSubId() { + int subId = INVALID_SUB_ID; try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -769,7 +766,7 @@ public class SubscriptionManager implements BaseColumns { } /** @hide */ - public static void setDefaultVoiceSubId(long subId) { + public static void setDefaultVoiceSubId(int subId) { if (VDBG) logd("setDefaultVoiceSubId sub id = " + subId); try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -793,10 +790,9 @@ public class SubscriptionManager implements BaseColumns { /** * @return subId of the DefaultSms subscription or the value INVALID_SUB_ID if an error. - * @hide - to be unhidden */ - public static long getDefaultSmsSubId() { - long subId = INVALID_SUB_ID; + public static int getDefaultSmsSubId() { + int subId = INVALID_SUB_ID; try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -812,7 +808,7 @@ public class SubscriptionManager implements BaseColumns { } /** @hide */ - public static void setDefaultSmsSubId(long subId) { + public static void setDefaultSmsSubId(int subId) { if (VDBG) logd("setDefaultSmsSubId sub id = " + subId); try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -835,8 +831,8 @@ public class SubscriptionManager implements BaseColumns { } /** @hide */ - public static long getDefaultDataSubId() { - long subId = INVALID_SUB_ID; + public static int getDefaultDataSubId() { + int subId = INVALID_SUB_ID; try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -852,7 +848,7 @@ public class SubscriptionManager implements BaseColumns { } /** @hide */ - public static void setDefaultDataSubId(long subId) { + public static void setDefaultDataSubId(int subId) { if (VDBG) logd("setDataSubscription sub id = " + subId); try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -922,12 +918,20 @@ public class SubscriptionManager implements BaseColumns { /** * @return true if a valid subId else false - * @hide - to be unhidden */ - public static boolean isValidSubId(long subId) { + public static boolean isValidSubId(int subId) { return subId > INVALID_SUB_ID ; } + /** + * @return true if subId is an usable subId value else false. A + * usable subId means its neither a INVALID_SUB_ID nor a DEFAUL_SUB_ID. + * @hide + */ + public static boolean isUsableSubIdValue(int subId) { + return subId >= MIN_SUB_ID_VALUE && subId <= MAX_SUB_ID_VALUE; + } + /** @hide */ public static boolean isValidSlotId(int slotId) { // We are testing INVALID_SLOT_ID and slotId >= 0 independently because we should @@ -948,7 +952,7 @@ public class SubscriptionManager implements BaseColumns { /** @hide */ public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId) { - long[] subIds = SubscriptionManager.getSubId(phoneId); + int[] subIds = SubscriptionManager.getSubId(phoneId); if (subIds != null && subIds.length > 0) { putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]); } else { @@ -957,7 +961,7 @@ public class SubscriptionManager implements BaseColumns { } /** @hide */ - public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, long subId) { + public static void putPhoneIdAndSubIdExtra(Intent intent, int phoneId, int subId) { if (VDBG) logd("putPhoneIdAndSubIdExtra: phoneId=" + phoneId + " subId=" + subId); intent.putExtra(PhoneConstants.SUBSCRIPTION_KEY, subId); intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); @@ -971,8 +975,8 @@ public class SubscriptionManager implements BaseColumns { * is never null but the length maybe 0. * @hide */ - public static long[] getActiveSubIdList() { - long[] subId = null; + public static int[] getActiveSubIdList() { + int[] subId = null; try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); @@ -984,7 +988,7 @@ public class SubscriptionManager implements BaseColumns { } if (subId == null) { - subId = new long[0]; + subId = new int[0]; } return subId; diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 6ba151f..bd4ea56 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -572,8 +572,28 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ public String getDeviceSoftwareVersion() { + return getDeviceSoftwareVersion(getDefaultSim()); + } + + /** + * Returns the software version number for the device, for example, + * the IMEI/SV for GSM phones. Return null if the software version is + * not available. + * + * <p>Requires Permission: + * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} + * + * @param slotId of which deviceID is returned + */ + /** {@hide} */ + public String getDeviceSoftwareVersion(int slotId) { + // FIXME methods taking slot id should not use subscription, instead us Uicc directly + int[] subId = SubscriptionManager.getSubId(slotId); + if (subId == null || subId.length == 0) { + return null; + } try { - return getSubscriberInfo().getDeviceSvn(); + return getSubscriberInfo().getDeviceSvnUsingSubId(subId[0]); } catch (RemoteException ex) { return null; } catch (NullPointerException ex) { @@ -603,7 +623,11 @@ public class TelephonyManager { */ /** {@hide} */ public String getDeviceId(int slotId) { - long[] subId = SubscriptionManager.getSubId(slotId); + // FIXME methods taking slot id should not use subscription, instead us Uicc directly + int[] subId = SubscriptionManager.getSubId(slotId); + if (subId == null || subId.length == 0) { + return null; + } try { return getSubscriberInfo().getDeviceIdForSubscriber(subId[0]); } catch (RemoteException ex) { @@ -634,7 +658,7 @@ public class TelephonyManager { */ /** {@hide} */ public String getImei(int slotId) { - long[] subId = SubscriptionManager.getSubId(slotId); + int[] subId = SubscriptionManager.getSubId(slotId); try { return getSubscriberInfo().getImeiForSubscriber(subId[0]); } catch (RemoteException ex) { @@ -645,6 +669,32 @@ public class TelephonyManager { } /** + * Returns the NAI. Return null if NAI is not available. + * + */ + /** {@hide}*/ + public String getNai() { + return getNai(getDefaultSim()); + } + + /** + * Returns the NAI. Return null if NAI is not available. + * + * @param slotId of which Nai is returned + */ + /** {@hide}*/ + public String getNai(int slotId) { + int[] subId = SubscriptionManager.getSubId(slotId); + try { + return getSubscriberInfo().getNaiForSubscriber(subId[0]); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } + } + + /** * Returns the current location of the device. *<p> * If there is only one radio in the device and that radio has an LTE connection, @@ -698,7 +748,7 @@ public class TelephonyManager { * @param subId for which the location updates are enabled */ /** @hide */ - public void enableLocationUpdates(long subId) { + public void enableLocationUpdates(int subId) { try { getITelephony().enableLocationUpdatesForSubscriber(subId); } catch (RemoteException ex) { @@ -720,7 +770,7 @@ public class TelephonyManager { } /** @hide */ - public void disableLocationUpdates(long subId) { + public void disableLocationUpdates(int subId) { try { getITelephony().disableLocationUpdatesForSubscriber(subId); } catch (RemoteException ex) { @@ -785,24 +835,24 @@ public class TelephonyManager { */ /** {@hide} */ @SystemApi - public int getCurrentPhoneType(long subId) { - + public int getCurrentPhoneType(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); try{ ITelephony telephony = getITelephony(); if (telephony != null) { return telephony.getActivePhoneTypeForSubscriber(subId); } else { // This can happen when the ITelephony interface is not up yet. - return getPhoneTypeFromProperty(subId); + return getPhoneTypeFromProperty(phoneId); } } catch (RemoteException ex) { // This shouldn't happen in the normal case, as a backup we // read from the system property. - return getPhoneTypeFromProperty(subId); + return getPhoneTypeFromProperty(phoneId); } catch (NullPointerException ex) { // This shouldn't happen in the normal case, as a backup we // read from the system property. - return getPhoneTypeFromProperty(subId); + return getPhoneTypeFromProperty(phoneId); } } @@ -823,31 +873,29 @@ public class TelephonyManager { } private int getPhoneTypeFromProperty() { - return getPhoneTypeFromProperty(getDefaultSubscription()); + return getPhoneTypeFromProperty(getDefaultPhone()); } /** {@hide} */ - private int getPhoneTypeFromProperty(long subId) { - String type = - getTelephonyProperty - (TelephonyProperties.CURRENT_ACTIVE_PHONE, subId, null); - if (type != null) { - return (Integer.parseInt(type)); - } else { - return getPhoneTypeFromNetworkType(subId); + private int getPhoneTypeFromProperty(int phoneId) { + String type = getTelephonyProperty(phoneId, + TelephonyProperties.CURRENT_ACTIVE_PHONE, null); + if (type == null || type.equals("")) { + return getPhoneTypeFromNetworkType(phoneId); } + return Integer.parseInt(type); } private int getPhoneTypeFromNetworkType() { - return getPhoneTypeFromNetworkType(getDefaultSubscription()); + return getPhoneTypeFromNetworkType(getDefaultPhone()); } /** {@hide} */ - private int getPhoneTypeFromNetworkType(long subId) { + private int getPhoneTypeFromNetworkType(int phoneId) { // When the system property CURRENT_ACTIVE_PHONE, has not been set, // use the system property for default network type. // This is a fail safe, and can only happen at first boot. - String mode = getTelephonyProperty("ro.telephony.default_network", subId, null); + String mode = getTelephonyProperty(phoneId, "ro.telephony.default_network", null); if (mode != null) { return TelephonyManager.getPhoneType(Integer.parseInt(mode)); } @@ -999,10 +1047,9 @@ public class TelephonyManager { * @param subId */ /** {@hide} */ - public String getNetworkOperatorName(long subId) { - - return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ALPHA, - subId, ""); + public String getNetworkOperatorName(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); + return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ALPHA, ""); } /** @@ -1027,10 +1074,9 @@ public class TelephonyManager { * @param subId */ /** {@hide} */ - public String getNetworkOperator(long subId) { - - return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, - subId, ""); + public String getNetworkOperator(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); + return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_NUMERIC, ""); } /** @@ -1052,9 +1098,10 @@ public class TelephonyManager { * @param subId */ /** {@hide} */ - public boolean isNetworkRoaming(long subId) { - return "true".equals(getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, - subId, null)); + public boolean isNetworkRoaming(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); + return Boolean.parseBoolean(getTelephonyProperty(phoneId, + TelephonyProperties.PROPERTY_OPERATOR_ISROAMING, null)); } /** @@ -1080,9 +1127,9 @@ public class TelephonyManager { * @param subId for which Network CountryIso is returned */ /** {@hide} */ - public String getNetworkCountryIso(long subId) { - return getTelephonyProperty(TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, - subId, ""); + public String getNetworkCountryIso(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); + return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY, ""); } /** Network type is unknown */ @@ -1152,7 +1199,7 @@ public class TelephonyManager { * @see #NETWORK_TYPE_HSPAP */ /** {@hide} */ - public int getNetworkType(long subId) { + public int getNetworkType(int subId) { try { ITelephony telephony = getITelephony(); if (telephony != null) { @@ -1206,7 +1253,7 @@ public class TelephonyManager { * @param subId for which network type is returned */ /** {@hide} */ - public int getDataNetworkType(long subId) { + public int getDataNetworkType(int subId) { try{ ITelephony telephony = getITelephony(); if (telephony != null) { @@ -1238,7 +1285,7 @@ public class TelephonyManager { * */ /** {@hide} */ - public int getVoiceNetworkType(long subId) { + public int getVoiceNetworkType(int subId) { try{ ITelephony telephony = getITelephony(); if (telephony != null) { @@ -1395,7 +1442,7 @@ public class TelephonyManager { */ /** {@hide} */ // FIXME Input argument slotId should be of type int - public boolean hasIccCard(long slotId) { + public boolean hasIccCard(int slotId) { try { return getITelephony().hasIccCardUsingSlotId(slotId); @@ -1440,14 +1487,14 @@ public class TelephonyManager { /** {@hide} */ // FIXME the argument to pass is subId ?? public int getSimState(int slotId) { - long[] subId = SubscriptionManager.getSubId(slotId); - if (subId == null) { + int[] subId = SubscriptionManager.getSubId(slotId); + if (subId == null || subId.length == 0) { return SIM_STATE_ABSENT; } // FIXME Do not use a property to determine SIM_STATE, call // appropriate method on some object. - String prop = - getTelephonyProperty(TelephonyProperties.PROPERTY_SIM_STATE, subId[0], ""); + int phoneId = SubscriptionManager.getPhoneId(subId[0]); + String prop = getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_SIM_STATE, ""); if ("ABSENT".equals(prop)) { return SIM_STATE_ABSENT; } @@ -1480,7 +1527,16 @@ public class TelephonyManager { * @see #getSimState */ public String getSimOperator() { - long subId = getDefaultSubscription(); + int subId = SubscriptionManager.getDefaultDataSubId(); + if (!SubscriptionManager.isUsableSubIdValue(subId)) { + subId = SubscriptionManager.getDefaultSmsSubId(); + if (!SubscriptionManager.isUsableSubIdValue(subId)) { + subId = SubscriptionManager.getDefaultVoiceSubId(); + if (!SubscriptionManager.isUsableSubIdValue(subId)) { + subId = SubscriptionManager.getDefaultSubId(); + } + } + } Rlog.d(TAG, "getSimOperator(): default subId=" + subId); return getSimOperator(subId); } @@ -1496,9 +1552,10 @@ public class TelephonyManager { * @param subId for which SimOperator is returned */ /** {@hide} */ - public String getSimOperator(long subId) { - String operator = getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, - subId, ""); + public String getSimOperator(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); + String operator = getTelephonyProperty(phoneId, + TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC, ""); Rlog.d(TAG, "getSimOperator: subId=" + subId + " operator=" + operator); return operator; } @@ -1524,9 +1581,9 @@ public class TelephonyManager { * @param subId for which SimOperatorName is returned */ /** {@hide} */ - public String getSimOperatorName(long subId) { - return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, - subId, ""); + public String getSimOperatorName(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); + return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_ICC_OPERATOR_ALPHA, ""); } /** @@ -1542,9 +1599,10 @@ public class TelephonyManager { * @param subId for which SimCountryIso is returned */ /** {@hide} */ - public String getSimCountryIso(long subId) { - return getTelephonyProperty(TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, - subId, ""); + public String getSimCountryIso(int subId) { + int phoneId = SubscriptionManager.getPhoneId(subId); + return getTelephonyProperty(phoneId, TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY, + ""); } /** @@ -1567,7 +1625,7 @@ public class TelephonyManager { * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} */ /** {@hide} */ - public String getSimSerialNumber(long subId) { + public String getSimSerialNumber(int subId) { try { return getSubscriberInfo().getIccSerialNumberForSubscriber(subId); } catch (RemoteException ex) { @@ -1603,7 +1661,7 @@ public class TelephonyManager { * */ /** {@hide} */ - public int getLteOnCdmaMode(long subId) { + public int getLteOnCdmaMode(int subId) { try { return getITelephony().getLteOnCdmaModeForSubscriber(subId); } catch (RemoteException ex) { @@ -1643,7 +1701,7 @@ public class TelephonyManager { * @param subId whose subscriber id is returned */ /** {@hide} */ - public String getSubscriberId(long subId) { + public String getSubscriberId(int subId) { try { return getSubscriberInfo().getSubscriberIdForSubscriber(subId); } catch (RemoteException ex) { @@ -1682,7 +1740,7 @@ public class TelephonyManager { * @param subscription whose subscriber id is returned */ /** {@hide} */ - public String getGroupIdLevel1(long subId) { + public String getGroupIdLevel1(int subId) { try { return getSubscriberInfo().getGroupIdLevel1ForSubscriber(subId); } catch (RemoteException ex) { @@ -1714,7 +1772,7 @@ public class TelephonyManager { * @param subId whose phone number for line 1 is returned */ /** {@hide} */ - public String getLine1NumberForSubscriber(long subId) { + public String getLine1NumberForSubscriber(int subId) { String number = null; try { number = getITelephony().getLine1NumberForDisplay(subId); @@ -1746,7 +1804,6 @@ public class TelephonyManager { * * @param alphaTag alpha-tagging of the dailing nubmer * @param number The dialing number - * @hide */ public void setLine1NumberForDisplay(String alphaTag, String number) { setLine1NumberForDisplayForSubscriber(getDefaultSubscription(), alphaTag, number); @@ -1767,7 +1824,7 @@ public class TelephonyManager { * @param number The dialing number * @hide */ - public void setLine1NumberForDisplayForSubscriber(long subId, String alphaTag, String number) { + public void setLine1NumberForDisplayForSubscriber(int subId, String alphaTag, String number) { try { getITelephony().setLine1NumberForDisplayForSubscriber(subId, alphaTag, number); } catch (RemoteException ex) { @@ -1799,7 +1856,7 @@ public class TelephonyManager { * nobody seems to call this. */ /** {@hide} */ - public String getLine1AlphaTagForSubscriber(long subId) { + public String getLine1AlphaTagForSubscriber(int subId) { String alphaTag = null; try { alphaTag = getITelephony().getLine1AlphaTagForDisplay(subId); @@ -1842,7 +1899,7 @@ public class TelephonyManager { * @param subId for which msisdn is returned */ /** {@hide} */ - public String getMsisdn(long subId) { + public String getMsisdn(int subId) { try { return getSubscriberInfo().getMsisdnForSubscriber(subId); } catch (RemoteException ex) { @@ -1872,7 +1929,7 @@ public class TelephonyManager { * @param subId whose voice mail number is returned */ /** {@hide} */ - public String getVoiceMailNumber(long subId) { + public String getVoiceMailNumber(int subId) { try { return getSubscriberInfo().getVoiceMailNumberForSubscriber(subId); } catch (RemoteException ex) { @@ -1904,7 +1961,7 @@ public class TelephonyManager { * @param subId */ /** {@hide} */ - public String getCompleteVoiceMailNumber(long subId) { + public String getCompleteVoiceMailNumber(int subId) { try { return getSubscriberInfo().getCompleteVoiceMailNumberForSubscriber(subId); } catch (RemoteException ex) { @@ -1934,7 +1991,7 @@ public class TelephonyManager { * @param subId whose voice message count is returned */ /** {@hide} */ - public int getVoiceMessageCount(long subId) { + public int getVoiceMessageCount(int subId) { try { return getITelephony().getVoiceMessageCountForSubscriber(subId); } catch (RemoteException ex) { @@ -1966,7 +2023,7 @@ public class TelephonyManager { * voice mail number is returned */ /** {@hide} */ - public String getVoiceMailAlphaTag(long subId) { + public String getVoiceMailAlphaTag(int subId) { try { return getSubscriberInfo().getVoiceMailAlphaTagForSubscriber(subId); } catch (RemoteException ex) { @@ -2026,6 +2083,9 @@ public class TelephonyManager { } } + /** + * @hide + */ private IPhoneSubInfo getSubscriberInfo() { // get it each time because that process crashes a lot return IPhoneSubInfo.Stub.asInterface(ServiceManager.getService("iphonesubinfo")); @@ -2046,11 +2106,7 @@ public class TelephonyManager { * Returns a constant indicating the call state (cellular) on the device. */ public int getCallState() { - try { - return getTelecomService().getCallState(); - } catch (RemoteException | NullPointerException e) { - return CALL_STATE_IDLE; - } + return getCallState(getDefaultSubscription()); } /** @@ -2060,7 +2116,7 @@ public class TelephonyManager { * @param subId whose call state is returned */ /** {@hide} */ - public int getCallState(long subId) { + public int getCallState(int subId) { try { return getITelephony().getCallStateForSubscriber(subId); } catch (RemoteException ex) { @@ -2143,10 +2199,16 @@ public class TelephonyManager { } } + /** + * @hide + */ private ITelephony getITelephony() { return ITelephony.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_SERVICE)); } + /** + * @hide + */ private ITelecomService getTelecomService() { return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE)); } @@ -2205,7 +2267,7 @@ public class TelephonyManager { * Returns the CDMA ERI icon index to display for a subscription */ /** {@hide} */ - public int getCdmaEriIconIndex(long subId) { + public int getCdmaEriIconIndex(int subId) { try { return getITelephony().getCdmaEriIconIndexForSubscriber(subId); } catch (RemoteException ex) { @@ -2233,7 +2295,7 @@ public class TelephonyManager { * 1 - FLASHING */ /** {@hide} */ - public int getCdmaEriIconMode(long subId) { + public int getCdmaEriIconMode(int subId) { try { return getITelephony().getCdmaEriIconModeForSubscriber(subId); } catch (RemoteException ex) { @@ -2258,7 +2320,7 @@ public class TelephonyManager { * */ /** {@hide} */ - public String getCdmaEriText(long subId) { + public String getCdmaEriText(int subId) { try { return getITelephony().getCdmaEriTextForSubscriber(subId); } catch (RemoteException ex) { @@ -2382,6 +2444,7 @@ public class TelephonyManager { * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * * @param AID Application id. See ETSI 102.221 and 101.220. * @return an IccOpenLogicalChannelResponse object. @@ -2402,6 +2465,7 @@ public class TelephonyManager { * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * * @param channel is the channel id to be closed as retruned by a successful * iccOpenLogicalChannel. @@ -2423,6 +2487,7 @@ public class TelephonyManager { * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * * @param channel is the channel id to be closed as returned by a successful * iccOpenLogicalChannel. @@ -2454,6 +2519,7 @@ public class TelephonyManager { * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * * @param cla Class of the APDU command. * @param instruction Instruction of the APDU command. @@ -2481,6 +2547,7 @@ public class TelephonyManager { * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * * @param fileID * @param command @@ -2506,6 +2573,7 @@ public class TelephonyManager { * * <p>Requires Permission: * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} + * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * * @param content String containing SAT/USAT response in hexadecimal * format starting with command tag. See TS 102 223 for @@ -2624,14 +2692,20 @@ public class TelephonyManager { /** * Returns Default subscription. */ - private static long getDefaultSubscription() { + private static int getDefaultSubscription() { return SubscriptionManager.getDefaultSubId(); } + /** + * Returns Default phone. + */ + private static int getDefaultPhone() { + return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubId()); + } + /** {@hide} */ public int getDefaultSim() { - //TODO Need to get it from Telephony Devcontroller - return 0; + return SubscriptionManager.getSlotId(SubscriptionManager.getDefaultSubId()); } /** @@ -2639,11 +2713,12 @@ public class TelephonyManager { * * @hide */ - public static void setTelephonyProperty(String property, long subId, String value) { + public static void setTelephonyProperty(int phoneId, String property, String value) { + Rlog.d(TAG, "setTelephonyProperty property: " + property + " phoneId: " + phoneId + + " value: " + value); String propVal = ""; String p[] = null; String prop = SystemProperties.get(property); - int phoneId = SubscriptionManager.getPhoneId(subId); if (value == null) { value = ""; @@ -2653,7 +2728,10 @@ public class TelephonyManager { p = prop.split(","); } - if (phoneId < 0) return; + if (!SubscriptionManager.isValidPhoneId(phoneId)) { + Rlog.d(TAG, "setTelephonyProperty invalid phone id"); + return; + } for (int i = 0; i < phoneId; i++) { String str = ""; @@ -2738,6 +2816,12 @@ public class TelephonyManager { String valArray[] = null; String v = android.provider.Settings.Global.getString(cr, name); + if (index == Integer.MAX_VALUE) { + throw new RuntimeException("putIntAtIndex index == MAX_VALUE index=" + index); + } + if (index < 0) { + throw new RuntimeException("putIntAtIndex index < 0 index=" + index); + } if (v != null) { valArray = v.split(","); } @@ -2767,9 +2851,8 @@ public class TelephonyManager { * * @hide */ - public static String getTelephonyProperty(String property, long subId, String defaultVal) { + public static String getTelephonyProperty(int phoneId, String property, String defaultVal) { String propVal = null; - int phoneId = SubscriptionManager.getPhoneId(subId); String prop = SystemProperties.get(property); if ((prop != null) && (prop.length() > 0)) { String values[] = prop.split(","); @@ -2783,10 +2866,10 @@ public class TelephonyManager { /** @hide */ public int getSimCount() { if(isMultiSimEnabled()) { - //TODO Need to get it from Telephony Devcontroller + //FIXME Need to get it from Telephony Devcontroller return 2; } else { - return 1; + return 1; } } @@ -2851,7 +2934,7 @@ public class TelephonyManager { * @return the response of SIM Authentication, or null if not available * @hide */ - public String getIccSimChallengeResponse(long subId, int appType, String data) { + public String getIccSimChallengeResponse(int subId, int appType, String data) { try { return getSubscriberInfo().getIccSimChallengeResponse(subId, appType, data); } catch (RemoteException ex) { @@ -2955,7 +3038,6 @@ public class TelephonyManager { * Or the calling app has carrier privileges. @see #hasCarrierPrivileges * * @return true on success; false on any failure. - * @hide */ public boolean setGlobalPreferredNetworkType() { return setPreferredNetworkType(RILConstants.NETWORK_MODE_LTE_CDMA_EVDO_GSM_WCDMA); @@ -2963,23 +3045,10 @@ public class TelephonyManager { /** * Values used to return status for hasCarrierPrivileges call. - * @hide */ public static final int CARRIER_PRIVILEGE_STATUS_HAS_ACCESS = 1; - /** - * Values used to return status for hasCarrierPrivileges call. - * @hide - */ public static final int CARRIER_PRIVILEGE_STATUS_NO_ACCESS = 0; - /** - * Values used to return status for hasCarrierPrivileges call. - * @hide - */ public static final int CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED = -1; - /** - * Values used to return status for hasCarrierPrivileges call. - * @hide - */ public static final int CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES = -2; /** @@ -2996,7 +3065,6 @@ public class TelephonyManager { * CARRIER_PRIVILEGE_STATUS_RULES_NOT_LOADED if the carrier rules are not loaded. * CARRIER_PRIVILEGE_STATUS_ERROR_LOADING_RULES if there was an error loading carrier * rules (or if there are no rules). - * @hide */ public int hasCarrierPrivileges() { try { @@ -3023,7 +3091,6 @@ public class TelephonyManager { * * @param brand The brand name to display/set. * @return true if the operation was executed correctly. - * @hide */ public boolean setOperatorBrandOverride(String brand) { try { @@ -3048,7 +3115,7 @@ public class TelephonyManager { /** @hide */ @SystemApi - public String getCdmaMdn(long subId) { + public String getCdmaMdn(int subId) { try { return getITelephony().getCdmaMdn(subId); } catch (RemoteException ex) { @@ -3066,7 +3133,7 @@ public class TelephonyManager { /** @hide */ @SystemApi - public String getCdmaMin(long subId) { + public String getCdmaMin(int subId) { try { return getITelephony().getCdmaMin(subId); } catch (RemoteException ex) { @@ -3397,7 +3464,7 @@ public class TelephonyManager { * @param enable true means enabling the simplified UI. * @hide */ - public void enableSimplifiedNetworkSettingsForSubscriber(long subId, boolean enable) { + public void enableSimplifiedNetworkSettingsForSubscriber(int subId, boolean enable) { try { getITelephony().enableSimplifiedNetworkSettingsForSubscriber(subId, enable); } catch (RemoteException ex) { @@ -3430,7 +3497,7 @@ public class TelephonyManager { * @return true if the simplified UI is enabled. * @hide */ - public boolean getSimplifiedNetworkSettingsEnabledForSubscriber(long subId) { + public boolean getSimplifiedNetworkSettingsEnabledForSubscriber(int subId) { try { return getITelephony().getSimplifiedNetworkSettingsEnabledForSubscriber(subId); } catch (RemoteException ex) { @@ -3457,4 +3524,25 @@ public class TelephonyManager { } return -1; } + + /** @hide */ + @SystemApi + public void enableVideoCalling(boolean enable) { + try { + getITelephony().enableVideoCalling(enable); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#enableVideoCalling", e); + } + } + + /** @hide */ + @SystemApi + public boolean isVideoCallingEnabled() { + try { + return getITelephony().isVideoCallingEnabled(); + } catch (RemoteException e) { + Log.e(TAG, "Error calling ITelephony#isVideoCallingEnabled", e); + } + return false; + } } diff --git a/telephony/java/com/android/ims/internal/IImsCallSession.aidl b/telephony/java/com/android/ims/internal/IImsCallSession.aidl index 98b2d8a..16b0cd5 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSession.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSession.aidl @@ -160,10 +160,13 @@ interface IImsCallSession { void resume(in ImsStreamMediaProfile profile); /** - * Merges the active & hold call. When it succeeds, {@link Listener#callSessionMerged} - * is called. + * Merges the active & hold call. When the merge starts, + * {@link Listener#callSessionMergeStarted} is called. + * {@link Listener#callSessionMergeComplete} is called if the merge is successful, and + * {@link Listener#callSessionMergeFailed} is called if the merge fails. * - * @see Listener#callSessionMerged, Listener#callSessionMergeFailed + * @see Listener#callSessionMergeStarted, Listener#callSessionMergeComplete, + * Listener#callSessionMergeFailed */ void merge(); @@ -225,4 +228,10 @@ interface IImsCallSession { * intermediates between the propriety implementation and Telecomm/InCall. */ IImsVideoCallProvider getVideoCallProvider(); + + /** + * Determines if the current session is multiparty. + * @return {@code True} if the session is multiparty. + */ + boolean isMultiparty(); } diff --git a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl index acd1eb9..84d1c545 100644 --- a/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl +++ b/telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl @@ -48,10 +48,11 @@ interface IImsCallSessionListener { void callSessionResumeReceived(in IImsCallSession session, in ImsCallProfile profile); /** - * Notifiies the result of call merge operation. + * Notifies the result of call merge operation. */ - void callSessionMerged(in IImsCallSession session, + void callSessionMergeStarted(in IImsCallSession session, in IImsCallSession newSession, in ImsCallProfile profile); + void callSessionMergeComplete(in IImsCallSession session); void callSessionMergeFailed(in IImsCallSession session, in ImsReasonInfo reasonInfo); @@ -104,4 +105,14 @@ interface IImsCallSessionListener { in int srcAccessTech, in int targetAccessTech, in ImsReasonInfo reasonInfo); void callSessionHandoverFailed(in IImsCallSession session, in int srcAccessTech, in int targetAccessTech, in ImsReasonInfo reasonInfo); + + /** + * Notifies the TTY mode change by remote party. + * @param mode one of the following: + * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} + * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} + * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} + * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO} + */ + void callSessionTtyModeReceived(in IImsCallSession session, in int mode); } diff --git a/telephony/java/com/android/ims/internal/IImsConfig.aidl b/telephony/java/com/android/ims/internal/IImsConfig.aidl index e8d921e..c5ccf5f 100644 --- a/telephony/java/com/android/ims/internal/IImsConfig.aidl +++ b/telephony/java/com/android/ims/internal/IImsConfig.aidl @@ -73,9 +73,9 @@ interface IImsConfig { * * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants. * @param value in Integer format. - * @return void. + * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants. */ - void setProvisionedValue(int item, int value); + int setProvisionedValue(int item, int value); /** * Sets the value for IMS service/capabilities parameters by the operator device @@ -84,9 +84,9 @@ interface IImsConfig { * * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants. * @param value in String format. - * @return void. + * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants. */ - void setProvisionedStringValue(int item, String value); + int setProvisionedStringValue(int item, String value); /** * Gets the value of the specified IMS feature item for specified network type. diff --git a/telephony/java/com/android/ims/internal/IImsService.aidl b/telephony/java/com/android/ims/internal/IImsService.aidl index 5138305..b9cee42 100644 --- a/telephony/java/com/android/ims/internal/IImsService.aidl +++ b/telephony/java/com/android/ims/internal/IImsService.aidl @@ -26,6 +26,8 @@ import com.android.ims.internal.IImsEcbm; import com.android.ims.internal.IImsUt; import com.android.ims.internal.IImsConfig; +import android.os.Message; + /** * {@hide} */ @@ -64,10 +66,13 @@ interface IImsService { */ void turnOffIms(); - /** * ECBM interface for Emergency Callback mode mechanism. */ IImsEcbm getEcbmInterface(int serviceId); + /** + * Used to set current TTY Mode. + */ + void setUiTTYMode(int serviceId, int uiTtyMode, in Message onComplete); } diff --git a/telephony/java/com/android/internal/telephony/CallerInfo.java b/telephony/java/com/android/internal/telephony/CallerInfo.java index 88e5bd6..5cd5d4e 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfo.java +++ b/telephony/java/com/android/internal/telephony/CallerInfo.java @@ -301,7 +301,7 @@ public class CallerInfo { public static CallerInfo getCallerInfo(Context context, String number) { if (VDBG) Rlog.v(TAG, "getCallerInfo() based on number..."); - long subId = SubscriptionManager.getDefaultSubId(); + int subId = SubscriptionManager.getDefaultSubId(); return getCallerInfo(context, number, subId); } @@ -316,7 +316,7 @@ public class CallerInfo { * a matching number is not found, then a generic caller info is returned, * with all relevant fields empty or null. */ - public static CallerInfo getCallerInfo(Context context, String number, long subId) { + public static CallerInfo getCallerInfo(Context context, String number, int subId) { if (TextUtils.isEmpty(number)) { return null; @@ -418,12 +418,12 @@ public class CallerInfo { // string in the phone number field. /* package */ CallerInfo markAsVoiceMail() { - long subId = SubscriptionManager.getDefaultSubId(); + int subId = SubscriptionManager.getDefaultSubId(); return markAsVoiceMail(subId); } - /* package */ CallerInfo markAsVoiceMail(long subId) { + /* package */ CallerInfo markAsVoiceMail(int subId) { mIsVoiceMail = true; try { diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java index 0d18389..aae7617 100644 --- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java +++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java @@ -81,7 +81,7 @@ public class CallerInfoAsyncQuery { public int event; public String number; - public long subId; + public int subId; } @@ -388,7 +388,7 @@ public class CallerInfoAsyncQuery { public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, OnQueryCompleteListener listener, Object cookie) { - long subId = SubscriptionManager.getDefaultSubId(); + int subId = SubscriptionManager.getDefaultSubId(); return startQuery(token, context, number, listener, cookie, subId); } @@ -404,7 +404,7 @@ public class CallerInfoAsyncQuery { * the phone type of the incoming connection. */ public static CallerInfoAsyncQuery startQuery(int token, Context context, String number, - OnQueryCompleteListener listener, Object cookie, long subId) { + OnQueryCompleteListener listener, Object cookie, int subId) { if (DBG) { Rlog.d(LOG_TAG, "##### CallerInfoAsyncQuery startQuery()... #####"); diff --git a/telephony/java/com/android/internal/telephony/DcParamObject.java b/telephony/java/com/android/internal/telephony/DcParamObject.java new file mode 100644 index 0000000..139939c --- /dev/null +++ b/telephony/java/com/android/internal/telephony/DcParamObject.java @@ -0,0 +1,58 @@ +/* + * 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.internal.telephony; + +import android.os.Parcelable; +import android.os.Parcel; + +public class DcParamObject implements Parcelable { + + private int mSubId; + + public DcParamObject(int subId) { + mSubId = subId; + } + + public DcParamObject(Parcel in) { + readFromParcel(in); + } + + public int describeContents() { + return 0; + } + + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(mSubId); + } + + private void readFromParcel(Parcel in) { + mSubId = in.readInt(); + } + + public static final Parcelable.Creator<DcParamObject> CREATOR = new Parcelable.Creator<DcParamObject>() { + public DcParamObject createFromParcel(Parcel in) { + return new DcParamObject(in); + } + public DcParamObject[] newArray(int size) { + return new DcParamObject[size]; + } + }; + + public int getSubId() { + return mSubId; + } +} diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java index 7eef89a..a4e9486 100644 --- a/telephony/java/com/android/internal/telephony/DctConstants.java +++ b/telephony/java/com/android/internal/telephony/DctConstants.java @@ -99,6 +99,7 @@ public class DctConstants { public static final int EVENT_PROVISIONING_APN_ALARM = BASE + 39; public static final int CMD_NET_STAT_POLL = BASE + 40; public static final int EVENT_DATA_RAT_CHANGED = BASE + 41; + public static final int CMD_CLEAR_PROVISIONING_SPINNER = BASE + 42; /***** Constants *****/ @@ -115,6 +116,7 @@ public class DctConstants { public static final int APN_EMERGENCY_ID = 9; public static final int APN_NUM_TYPES = 10; + public static final int INVALID = -1; public static final int DISABLED = 0; public static final int ENABLED = 1; diff --git a/telephony/java/com/android/internal/telephony/IMms.aidl b/telephony/java/com/android/internal/telephony/IMms.aidl index ebfefd1..0322499 100644 --- a/telephony/java/com/android/internal/telephony/IMms.aidl +++ b/telephony/java/com/android/internal/telephony/IMms.aidl @@ -39,7 +39,7 @@ interface IMms { * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed */ - void sendMessage(long subId, String callingPkg, in Uri contentUri, + void sendMessage(int subId, String callingPkg, in Uri contentUri, String locationUrl, in Bundle configOverrides, in PendingIntent sentIntent); /** @@ -56,7 +56,7 @@ interface IMms { * @param downloadedIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is downloaded, or the download is failed */ - void downloadMessage(long subId, String callingPkg, String locationUrl, + void downloadMessage(int subId, String callingPkg, String locationUrl, in Uri contentUri, in Bundle configOverrides, in PendingIntent downloadedIntent); @@ -99,7 +99,7 @@ interface IMms { * * @param subId the SIM id */ - Bundle getCarrierConfigValues(long subId); + Bundle getCarrierConfigValues(int subId); /** * Import a text message into system's SMS store @@ -204,7 +204,7 @@ interface IMms { * @param sentIntent if not NULL this <code>PendingIntent</code> is * broadcast when the message is successfully sent, or failed */ - void sendStoredMessage(long subId, String callingPkg, in Uri messageUri, + void sendStoredMessage(int subId, String callingPkg, in Uri messageUri, in Bundle configOverrides, in PendingIntent sentIntent); /** diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl index c203442..eec5333 100644 --- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl +++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl @@ -27,16 +27,21 @@ interface IPhoneSubInfo { */ String getDeviceId(); + /** + * Retrieves the unique Network Access ID + */ + String getNaiForSubscriber(int subId); + /** * Retrieves the unique device ID of a subId for the device, e.g., IMEI * for GSM phones. */ - String getDeviceIdForSubscriber(long subId); + String getDeviceIdForSubscriber(int subId); /** * Retrieves the IMEI. */ - String getImeiForSubscriber(long subId); + String getImeiForSubscriber(int subId); /** * Retrieves the software version number for the device, e.g., IMEI/SV @@ -45,6 +50,12 @@ interface IPhoneSubInfo { String getDeviceSvn(); /** + * Retrieves the software version number of a subId for the device, e.g., IMEI/SV + * for GSM phones. + */ + String getDeviceSvnUsingSubId(int subId); + + /** * Retrieves the unique sbuscriber ID, e.g., IMSI for GSM phones. */ String getSubscriberId(); @@ -52,7 +63,7 @@ interface IPhoneSubInfo { /** * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones. */ - String getSubscriberIdForSubscriber(long subId); + String getSubscriberIdForSubscriber(int subId); /** * Retrieves the Group Identifier Level1 for GSM phones. @@ -62,7 +73,7 @@ interface IPhoneSubInfo { /** * Retrieves the Group Identifier Level1 for GSM phones of a subId. */ - String getGroupIdLevel1ForSubscriber(long subId); + String getGroupIdLevel1ForSubscriber(int subId); /** * Retrieves the serial number of the ICC, if applicable. @@ -72,7 +83,7 @@ interface IPhoneSubInfo { /** * Retrieves the serial number of a given subId. */ - String getIccSerialNumberForSubscriber(long subId); + String getIccSerialNumberForSubscriber(int subId); /** * Retrieves the phone number string for line 1. @@ -82,7 +93,7 @@ interface IPhoneSubInfo { /** * Retrieves the phone number string for line 1 of a subcription. */ - String getLine1NumberForSubscriber(long subId); + String getLine1NumberForSubscriber(int subId); /** @@ -93,7 +104,7 @@ interface IPhoneSubInfo { /** * Retrieves the alpha identifier for line 1 of a subId. */ - String getLine1AlphaTagForSubscriber(long subId); + String getLine1AlphaTagForSubscriber(int subId); /** @@ -104,7 +115,7 @@ interface IPhoneSubInfo { /** * Retrieves the Msisdn of a subId. */ - String getMsisdnForSubscriber(long subId); + String getMsisdnForSubscriber(int subId); /** * Retrieves the voice mail number. @@ -114,7 +125,7 @@ interface IPhoneSubInfo { /** * Retrieves the voice mail number of a given subId. */ - String getVoiceMailNumberForSubscriber(long subId); + String getVoiceMailNumberForSubscriber(int subId); /** * Retrieves the complete voice mail number. @@ -124,7 +135,7 @@ interface IPhoneSubInfo { /** * Retrieves the complete voice mail number for particular subId */ - String getCompleteVoiceMailNumberForSubscriber(long subId); + String getCompleteVoiceMailNumberForSubscriber(int subId); /** * Retrieves the alpha identifier associated with the voice mail number. @@ -135,7 +146,7 @@ interface IPhoneSubInfo { * Retrieves the alpha identifier associated with the voice mail number * of a subId. */ - String getVoiceMailAlphaTagForSubscriber(long subId); + String getVoiceMailAlphaTagForSubscriber(int subId); /** * Returns the IMS private user identity (IMPI) that was loaded from the ISIM. @@ -188,5 +199,5 @@ interface IPhoneSubInfo { * @param data authentication challenge data * @return challenge response */ - String getIccSimChallengeResponse(long subId, int appType, String data); + String getIccSimChallengeResponse(int subId, int appType, String data); } diff --git a/telephony/java/com/android/internal/telephony/ISms.aidl b/telephony/java/com/android/internal/telephony/ISms.aidl index 32bb8b4..560af45 100644 --- a/telephony/java/com/android/internal/telephony/ISms.aidl +++ b/telephony/java/com/android/internal/telephony/ISms.aidl @@ -47,7 +47,7 @@ interface ISms { * @param subId the subId id. * @return list of SmsRawData of all sms on ICC */ - List<SmsRawData> getAllMessagesFromIccEfForSubscriber(in long subId, String callingPkg); + List<SmsRawData> getAllMessagesFromIccEfForSubscriber(in int subId, String callingPkg); /** * Update the specified message on the ICC. @@ -75,7 +75,7 @@ interface ISms { * @return success or not * */ - boolean updateMessageOnIccEfForSubscriber(in long subId, String callingPkg, + boolean updateMessageOnIccEfForSubscriber(in int subId, String callingPkg, int messageIndex, int newStatus, in byte[] pdu); /** @@ -99,7 +99,7 @@ interface ISms { * @return success or not * */ - boolean copyMessageToIccEfForSubscriber(in long subId, String callingPkg, int status, + boolean copyMessageToIccEfForSubscriber(in int subId, String callingPkg, int status, in byte[] pdu, in byte[] smsc); /** @@ -152,7 +152,7 @@ interface ISms { * raw pdu of the status report is in the extended data ("pdu"). * @param subId the subId id. */ - void sendDataForSubscriber(long subId, String callingPkg, in String destAddr, + void sendDataForSubscriber(int subId, String callingPkg, in String destAddr, in String scAddr, in int destPort, in byte[] data, in PendingIntent sentIntent, in PendingIntent deliveryIntent); @@ -206,7 +206,7 @@ interface ISms { * raw pdu of the status report is in the extended data ("pdu"). * @param subId the subId on which the SMS has to be sent. */ - void sendTextForSubscriber(in long subId, String callingPkg, in String destAddr, + void sendTextForSubscriber(in int subId, String callingPkg, in String destAddr, in String scAddr, in String text, in PendingIntent sentIntent, in PendingIntent deliveryIntent); @@ -283,7 +283,7 @@ interface ISms { * extended data ("pdu"). * @param subId the subId on which the SMS has to be sent. */ - void sendMultipartTextForSubscriber(in long subId, String callingPkg, + void sendMultipartTextForSubscriber(in int subId, String callingPkg, in String destinationAddress, in String scAddress, in List<String> parts, in List<PendingIntent> sentIntents, in List<PendingIntent> deliveryIntents); @@ -315,7 +315,7 @@ interface ISms { * * @see #disableCellBroadcast(int) */ - boolean enableCellBroadcastForSubscriber(in long subId, int messageIdentifier); + boolean enableCellBroadcastForSubscriber(in int subId, int messageIdentifier); /** * Disable reception of cell broadcast (SMS-CB) messages with the given @@ -344,7 +344,7 @@ interface ISms { * * @see #enableCellBroadcast(int) */ - boolean disableCellBroadcastForSubscriber(in long subId, int messageIdentifier); + boolean disableCellBroadcastForSubscriber(in int subId, int messageIdentifier); /* * Enable reception of cell broadcast (SMS-CB) messages with the given @@ -377,7 +377,7 @@ interface ISms { * * @see #disableCellBroadcastRange(int, int) */ - boolean enableCellBroadcastRangeForSubscriber(long subId, int startMessageId, int endMessageId); + boolean enableCellBroadcastRangeForSubscriber(int subId, int startMessageId, int endMessageId); /** * Disable reception of cell broadcast (SMS-CB) messages with the given @@ -410,7 +410,7 @@ interface ISms { * * @see #enableCellBroadcastRange(int, int, int) */ - boolean disableCellBroadcastRangeForSubscriber(long subId, int startMessageId, + boolean disableCellBroadcastRangeForSubscriber(int subId, int startMessageId, int endMessageId); /** @@ -423,7 +423,7 @@ interface ISms { * Returns the premium SMS send permission for the specified package. * Requires system permission. */ - int getPremiumSmsPermissionForSubscriber(long subId, String packageName); + int getPremiumSmsPermissionForSubscriber(int subId, String packageName); /** * Set the SMS send permission for the specified package. @@ -439,7 +439,7 @@ interface ISms { * Set the SMS send permission for the specified package. * Requires system permission. */ - void setPremiumSmsPermissionForSubscriber(long subId, String packageName, int permission); + void setPremiumSmsPermissionForSubscriber(int subId, String packageName, int permission); /** * SMS over IMS is supported if IMS is registered and SMS is supported @@ -459,13 +459,13 @@ interface ISms { * * @see #getImsSmsFormat() */ - boolean isImsSmsSupportedForSubscriber(long subId); + boolean isImsSmsSupportedForSubscriber(int subId); /* * get user prefered SMS subId * @return subId id */ - long getPreferredSmsSubscription(); + int getPreferredSmsSubscription(); /** * Gets SMS format supported on IMS. SMS over IMS format is @@ -489,7 +489,7 @@ interface ISms { * * @see #isImsSmsSupported() */ - String getImsSmsFormatForSubscriber(long subId); + String getImsSmsFormatForSubscriber(int subId); /* * Get SMS prompt property, enabled or not @@ -524,7 +524,7 @@ interface ISms { * broadcast when the message is delivered to the recipient. The * raw pdu of the status report is in the extended data ("pdu"). */ - void sendStoredText(long subId, String callingPkg, in Uri messageUri, String scAddress, + void sendStoredText(int subId, String callingPkg, in Uri messageUri, String scAddress, in PendingIntent sentIntent, in PendingIntent deliveryIntent); /** @@ -560,7 +560,7 @@ interface ISms { * to the recipient. The raw pdu of the status report is in the * extended data ("pdu"). */ - void sendStoredMultipartText(long subId, String callingPkg, in Uri messageUri, + void sendStoredMultipartText(int subId, String callingPkg, in Uri messageUri, String scAddress, in List<PendingIntent> sentIntents, in List<PendingIntent> deliveryIntents); } diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl index b87365e..daf850e 100755 --- a/telephony/java/com/android/internal/telephony/ISub.aidl +++ b/telephony/java/com/android/internal/telephony/ISub.aidl @@ -25,7 +25,7 @@ interface ISub { * @param subId The unique SubInfoRecord index in database * @return SubInfoRecord, maybe null */ - SubInfoRecord getSubInfoForSubscriber(long subId); + SubInfoRecord getSubInfoForSubscriber(int subId); /** * Get the SubInfoRecord according to an IccId @@ -79,7 +79,7 @@ interface ISub { * @param subId the unique SubInfoRecord index in database * @return the number of records updated */ - int setColor(int color, long subId); + int setColor(int color, int subId); /** * Set display name by simInfo index @@ -87,7 +87,7 @@ interface ISub { * @param subId the unique SubInfoRecord index in database * @return the number of records updated */ - int setDisplayName(String displayName, long subId); + int setDisplayName(String displayName, int subId); /** * Set display name by simInfo index with name source @@ -96,7 +96,7 @@ interface ISub { * @param nameSource, 0: DEFAULT_SOURCE, 1: SIM_SOURCE, 2: USER_INPUT * @return the number of records updated */ - int setDisplayNameUsingSrc(String displayName, long subId, long nameSource); + int setDisplayNameUsingSrc(String displayName, int subId, long nameSource); /** * Set phone number by subId @@ -104,7 +104,7 @@ interface ISub { * @param subId the unique SubInfoRecord index in database * @return the number of records updated */ - int setDisplayNumber(String number, long subId); + int setDisplayNumber(String number, int subId); /** * Set number display format. 0: none, 1: the first four digits, 2: the last four digits @@ -112,7 +112,7 @@ interface ISub { * @param subId the unique SubInfoRecord index in database * @return the number of records updated */ - int setDisplayNumberFormat(int format, long subId); + int setDisplayNumberFormat(int format, int subId); /** * Set data roaming by simInfo index @@ -120,35 +120,35 @@ interface ISub { * @param subId the unique SubInfoRecord index in database * @return the number of records updated */ - int setDataRoaming(int roaming, long subId); + int setDataRoaming(int roaming, int subId); - int getSlotId(long subId); + int getSlotId(int subId); - long[] getSubId(int slotId); + int[] getSubId(int slotId); - long getDefaultSubId(); + int getDefaultSubId(); int clearSubInfo(); - int getPhoneId(long subId); + int getPhoneId(int subId); /** * Get the default data subscription * @return Id of the data subscription */ - long getDefaultDataSubId(); + int getDefaultDataSubId(); - void setDefaultDataSubId(long subId); + void setDefaultDataSubId(int subId); - long getDefaultVoiceSubId(); + int getDefaultVoiceSubId(); - void setDefaultVoiceSubId(long subId); + void setDefaultVoiceSubId(int subId); - long getDefaultSmsSubId(); + int getDefaultSmsSubId(); - void setDefaultSmsSubId(long subId); + void setDefaultSmsSubId(int subId); void clearDefaultsForInactiveSubIds(); - long[] getActiveSubIdList(); + int[] getActiveSubIdList(); } diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index 0868f41..13f0e3f 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -21,13 +21,14 @@ import android.os.Bundle; import android.telephony.CellInfo; import android.telephony.IccOpenLogicalChannelResponse; import android.telephony.NeighboringCellInfo; +import android.telephony.RadioAccessFamily; import java.util.List; /** * Interface used to interact with the phone. Mostly this is used by the * TelephonyManager class. A few places are still using this directly. - * Please clean them up if possible and use TelephonyManager insteadl. + * Please clean them up if possible and use TelephonyManager instead. * * {@hide} */ @@ -59,7 +60,7 @@ interface ITelephony { * @param subId user preferred subId. * @return whether it hung up */ - boolean endCallForSubscriber(long subId); + boolean endCallForSubscriber(int subId); /** * Answer the currently-ringing call. @@ -79,6 +80,23 @@ interface ITelephony { void answerRingingCall(); /** + * Answer the currently-ringing call on particular subId . + * + * If there's already a current active call, that call will be + * automatically put on hold. If both lines are currently in use, the + * current active call will be ended. + * + * TODO: provide a flag to let the caller specify what policy to use + * if both lines are in use. (The current behavior is hardwired to + * "answer incoming, end ongoing", which is how the CALL button + * is specced to behave.) + * + * TODO: this should be a oneway call (especially since it's called + * directly from the key queue thread). + */ + void answerRingingCallForSubscriber(int subId); + + /** * Silence the ringer if an incoming call is currently ringing. * (If vibrating, stop the vibrator also.) * @@ -103,7 +121,7 @@ interface ITelephony { * @param subId user preferred subId. * @return true if the phone state is OFFHOOK. */ - boolean isOffhookForSubscriber(long subId); + boolean isOffhookForSubscriber(int subId); /** * Check if an incoming phone call is ringing or call waiting @@ -112,7 +130,7 @@ interface ITelephony { * @param subId user preferred subId. * @return true if the phone state is RINGING. */ - boolean isRingingForSubscriber(long subId); + boolean isRingingForSubscriber(int subId); /** * Check if an incoming phone call is ringing or call waiting. @@ -132,7 +150,7 @@ interface ITelephony { * @param subId user preferred subId. * @return true if the phone state is IDLE. */ - boolean isIdleForSubscriber(long subId); + boolean isIdleForSubscriber(int subId); /** * Check to see if the radio is on or not. @@ -145,7 +163,7 @@ interface ITelephony { * @param subId user preferred subId. * @return returns true if the radio is on. */ - boolean isRadioOnForSubscriber(long subId); + boolean isRadioOnForSubscriber(int subId); /** * Check if the SIM pin lock is enabled. @@ -167,7 +185,7 @@ interface ITelephony { * @param subId user preferred subId. * @return whether the operation was a success. */ - boolean supplyPinForSubscriber(long subId, String pin); + boolean supplyPinForSubscriber(int subId, String pin); /** * Supply puk to unlock the SIM and set SIM pin to new pin. @@ -186,7 +204,7 @@ interface ITelephony { * @param subId user preferred subId. * @return whether the operation was a success. */ - boolean supplyPukForSubscriber(long subId, String puk, String pin); + boolean supplyPukForSubscriber(int subId, String puk, String pin); /** * Supply a pin to unlock the SIM. Blocks until a result is determined. @@ -204,7 +222,7 @@ interface ITelephony { * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code * retValue[1] = number of attempts remaining if known otherwise -1 */ - int[] supplyPinReportResultForSubscriber(long subId, String pin); + int[] supplyPinReportResultForSubscriber(int subId, String pin); /** * Supply puk to unlock the SIM and set SIM pin to new pin. @@ -226,7 +244,7 @@ interface ITelephony { * @return retValue[0] = Phone.PIN_RESULT_SUCCESS on success. Otherwise error code * retValue[1] = number of attempts remaining if known otherwise -1 */ - int[] supplyPukReportResultForSubscriber(long subId, String puk, String pin); + int[] supplyPukReportResultForSubscriber(int subId, String puk, String pin); /** * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated @@ -245,7 +263,7 @@ interface ITelephony { * @param subId user preferred subId. * @return true if MMI command is executed. */ - boolean handlePinMmiForSubscriber(long subId, String dialString); + boolean handlePinMmiForSubscriber(int subId, String dialString); /** * Toggles the radio on or off. @@ -256,7 +274,7 @@ interface ITelephony { * Toggles the radio on or off on particular subId. * @param subId user preferred subId. */ - void toggleRadioOnOffForSubscriber(long subId); + void toggleRadioOnOffForSubscriber(int subId); /** * Set the radio to on or off @@ -267,7 +285,7 @@ interface ITelephony { * Set the radio to on or off on particular subId. * @param subId user preferred subId. */ - boolean setRadioForSubscriber(long subId, boolean turnOn); + boolean setRadioForSubscriber(int subId, boolean turnOn); /** * Set the radio to on or off unconditionally @@ -283,7 +301,7 @@ interface ITelephony { * Request to update location information for a subscrition in service state * @param subId user preferred subId. */ - void updateServiceLocationForSubscriber(long subId); + void updateServiceLocationForSubscriber(int subId); /** * Enable location update notifications. @@ -294,7 +312,7 @@ interface ITelephony { * Enable location update notifications. * @param subId user preferred subId. */ - void enableLocationUpdatesForSubscriber(long subId); + void enableLocationUpdatesForSubscriber(int subId); /** * Disable location update notifications. @@ -305,7 +323,7 @@ interface ITelephony { * Disable location update notifications. * @param subId user preferred subId. */ - void disableLocationUpdatesForSubscriber(long subId); + void disableLocationUpdatesForSubscriber(int subId); /** * Allow mobile data connections. @@ -334,7 +352,7 @@ interface ITelephony { /** * Returns the call state for a subId. */ - int getCallStateForSubscriber(long subId); + int getCallStateForSubscriber(int subId); int getDataActivity(); int getDataState(); @@ -352,7 +370,7 @@ interface ITelephony { * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE * @param subId user preferred subId. */ - int getActivePhoneTypeForSubscriber(long subId); + int getActivePhoneTypeForSubscriber(int subId); /** * Returns the CDMA ERI icon index to display @@ -363,7 +381,7 @@ interface ITelephony { * Returns the CDMA ERI icon index to display on particular subId. * @param subId user preferred subId. */ - int getCdmaEriIconIndexForSubscriber(long subId); + int getCdmaEriIconIndexForSubscriber(int subId); /** * Returns the CDMA ERI icon mode, @@ -378,7 +396,7 @@ interface ITelephony { * 1 - FLASHING * @param subId user preferred subId. */ - int getCdmaEriIconModeForSubscriber(long subId); + int getCdmaEriIconModeForSubscriber(int subId); /** * Returns the CDMA ERI text, @@ -389,7 +407,7 @@ interface ITelephony { * Returns the CDMA ERI text for particular subId, * @param subId user preferred subId. */ - String getCdmaEriTextForSubscriber(long subId); + String getCdmaEriTextForSubscriber(int subId); /** * Returns true if OTA service provisioning needs to run. @@ -408,7 +426,7 @@ interface ITelephony { * @param subId user preferred subId. * Returns the unread count of voicemails */ - int getVoiceMessageCountForSubscriber(long subId); + int getVoiceMessageCountForSubscriber(int subId); /** * Returns the network type for data transmission @@ -420,7 +438,7 @@ interface ITelephony { * @param subId user preferred subId. * Returns the network type */ - int getNetworkTypeForSubscriber(long subId); + int getNetworkTypeForSubscriber(int subId); /** * Returns the network type for data transmission @@ -432,7 +450,7 @@ interface ITelephony { * @param subId user preferred subId. * Returns the network type */ - int getDataNetworkTypeForSubscriber(long subId); + int getDataNetworkTypeForSubscriber(int subId); /** * Returns the network type for voice @@ -444,7 +462,7 @@ interface ITelephony { * @param subId user preferred subId. * Returns the network type */ - int getVoiceNetworkTypeForSubscriber(long subId); + int getVoiceNetworkTypeForSubscriber(int subId); /** * Return true if an ICC card is present @@ -456,7 +474,7 @@ interface ITelephony { * @param slotId user preferred slotId. * Return true if an ICC card is present */ - boolean hasIccCardUsingSlotId(long slotId); + boolean hasIccCardUsingSlotId(int slotId); /** * Return if the current radio is LTE on CDMA. This @@ -476,7 +494,7 @@ interface ITelephony { * @return {@link Phone#LTE_ON_CDMA_UNKNOWN}, {@link Phone#LTE_ON_CDMA_FALSE} * or {@link PHone#LTE_ON_CDMA_TRUE} */ - int getLteOnCdmaModeForSubscriber(long subId); + int getLteOnCdmaModeForSubscriber(int subId); /** * Returns the all observed cell information of the device. @@ -671,13 +689,13 @@ interface ITelephony { * Return MDN string for CDMA phone. * @param subId user preferred subId. */ - String getCdmaMdn(long subId); + String getCdmaMdn(int subId); /** * Return MIN string for CDMA phone. * @param subId user preferred subId. */ - String getCdmaMin(long subId); + String getCdmaMin(int subId); /** * Has the calling application been granted special privileges by the carrier. @@ -715,7 +733,7 @@ interface ITelephony { * @param subId for which the simplified UI should be enabled or disabled. * @param enable true means enabling the simplified UI. */ - void enableSimplifiedNetworkSettingsForSubscriber(long subId, boolean enable); + void enableSimplifiedNetworkSettingsForSubscriber(int subId, boolean enable); /** * Get whether a simplified Mobile Network Settings UI is enabled for the @@ -724,7 +742,7 @@ interface ITelephony { * @param subId for which the simplified UI should be enabled or disabled. * @return true if the simplified UI is enabled. */ - boolean getSimplifiedNetworkSettingsEnabledForSubscriber(long subId); + boolean getSimplifiedNetworkSettingsEnabledForSubscriber(int subId); /** * Set the line 1 phone number string and its alphatag for the current ICCID @@ -736,7 +754,7 @@ interface ITelephony { * @param alphaTag alpha-tagging of the dailing nubmer * @param number The dialing number */ - void setLine1NumberForDisplayForSubscriber(long subId, String alphaTag, String number); + void setLine1NumberForDisplayForSubscriber(int subId, String alphaTag, String number); /** * Returns the displayed dialing number string if it was set previously via @@ -745,7 +763,7 @@ interface ITelephony { * @param subId whose dialing number for line 1 is returned. * @return the displayed dialing number if set, or null if not set. */ - String getLine1NumberForDisplay(long subId); + String getLine1NumberForDisplay(int subId); /** * Returns the displayed alphatag of the dialing number if it was set @@ -755,7 +773,7 @@ interface ITelephony { * @return the displayed alphatag of the dialing number if set, or null if * not set. */ - String getLine1AlphaTagForDisplay(long subId); + String getLine1AlphaTagForDisplay(int subId); /** * Override the operator branding for the current ICCID. @@ -796,4 +814,35 @@ interface ITelephony { * Shutdown Mobile Radios */ void shutdownMobileRadios(); + + /** + * Set phone radio type and access technology. + * + * @param rafs an RadioAccessFamily array to indicate all phone's + * new radio access family. The length of RadioAccessFamily + * must equ]]al to phone count. + */ + void setRadioCapability(in RadioAccessFamily[] rafs); + + /** + * Get phone radio type and access technology. + * + * @param phoneId which phone you want to get + * @return phone radio type and access technology + */ + int getRadioAccessFamily(in int phoneId); + + /** + * Enables or disables video calling. + * + * @param enable Whether to enable video calling. + */ + void enableVideoCalling(boolean enable); + + /** + * Whether video calling has been enabled by the user. + * + * @return {@code True} if the user has enabled video calling, {@code false} otherwise. + */ + boolean isVideoCallingEnabled(); } diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl index 39defcf..ee3f8b0 100644 --- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl @@ -30,28 +30,28 @@ import com.android.internal.telephony.IPhoneStateListener; interface ITelephonyRegistry { void listen(String pkg, IPhoneStateListener callback, int events, boolean notifyNow); - void listenForSubscriber(in long subId, String pkg, IPhoneStateListener callback, int events, + void listenForSubscriber(in int subId, String pkg, IPhoneStateListener callback, int events, boolean notifyNow); void notifyCallState(int state, String incomingNumber); - void notifyCallStateForSubscriber(in long subId, int state, String incomingNumber); - void notifyServiceStateForPhoneId(in int phoneId, in long subId, in ServiceState state); + void notifyCallStateForSubscriber(in int subId, int state, String incomingNumber); + void notifyServiceStateForPhoneId(in int phoneId, in int subId, in ServiceState state); void notifySignalStrength(in SignalStrength signalStrength); - void notifySignalStrengthForSubscriber(in long subId, in SignalStrength signalStrength); - void notifyMessageWaitingChangedForPhoneId(in int phoneId, in long subId, in boolean mwi); + void notifySignalStrengthForSubscriber(in int subId, in SignalStrength signalStrength); + void notifyMessageWaitingChangedForPhoneId(in int phoneId, in int subId, in boolean mwi); void notifyCallForwardingChanged(boolean cfi); - void notifyCallForwardingChangedForSubscriber(in long subId, boolean cfi); + void notifyCallForwardingChangedForSubscriber(in int subId, boolean cfi); void notifyDataActivity(int state); - void notifyDataActivityForSubscriber(in long subId, int state); + void notifyDataActivityForSubscriber(in int subId, int state); void notifyDataConnection(int state, boolean isDataConnectivityPossible, String reason, String apn, String apnType, in LinkProperties linkProperties, in NetworkCapabilities networkCapabilities, int networkType, boolean roaming); - void notifyDataConnectionForSubscriber(long subId, int state, boolean isDataConnectivityPossible, + void notifyDataConnectionForSubscriber(int subId, int state, boolean isDataConnectivityPossible, String reason, String apn, String apnType, in LinkProperties linkProperties, in NetworkCapabilities networkCapabilities, int networkType, boolean roaming); void notifyDataConnectionFailed(String reason, String apnType); - void notifyDataConnectionFailedForSubscriber(long subId, String reason, String apnType); + void notifyDataConnectionFailedForSubscriber(int subId, String reason, String apnType); void notifyCellLocation(in Bundle cellLocation); - void notifyCellLocationForSubscriber(in long subId, in Bundle cellLocation); + void notifyCellLocationForSubscriber(in int subId, in Bundle cellLocation); void notifyOtaspChanged(in int otaspMode); void notifyCellInfo(in List<CellInfo> cellInfo); void notifyPreciseCallState(int ringingCallState, int foregroundCallState, @@ -59,8 +59,8 @@ interface ITelephonyRegistry { void notifyDisconnectCause(int disconnectCause, int preciseDisconnectCause); void notifyPreciseDataConnectionFailed(String reason, String apnType, String apn, String failCause); - void notifyCellInfoForSubscriber(in long subId, in List<CellInfo> cellInfo); + void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo); void notifyDataConnectionRealTimeInfo(in DataConnectionRealTimeInfo dcRtInfo); void notifyVoLteServiceStateChanged(in VoLteServiceState lteState); - void notifyOemHookRawEventForSubscriber(in long subId, in byte[] rawData); + void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData); } diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java index 62b5596..b8e8064 100644 --- a/telephony/java/com/android/internal/telephony/PhoneConstants.java +++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java @@ -160,9 +160,6 @@ public class PhoneConstants { public static final int SUB2 = 1; public static final int SUB3 = 2; - public static final int EVENT_SUBSCRIPTION_ACTIVATED = 500; - public static final int EVENT_SUBSCRIPTION_DEACTIVATED = 501; - // TODO: Remove these constants and use an int instead. public static final int SIM_ID_1 = 0; public static final int SIM_ID_2 = 1; @@ -186,4 +183,7 @@ public class PhoneConstants { // Initial MTU value. public static final int UNSET_MTU = 0; + + //FIXME maybe this shouldn't be here - sprout only + public static final int CAPABILITY_3G = 1; } diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java index e730bde..b5e82e3 100644 --- a/telephony/java/com/android/internal/telephony/RILConstants.java +++ b/telephony/java/com/android/internal/telephony/RILConstants.java @@ -161,6 +161,7 @@ cat include/telephony/ril.h | \ public static final int DATA_PROFILE_FOTA = 3; public static final int DATA_PROFILE_CBS = 4; public static final int DATA_PROFILE_OEM_BASE = 1000; + public static final int DATA_PROFILE_INVALID = 0xFFFFFFFF; int RIL_REQUEST_GET_SIM_STATUS = 1; int RIL_REQUEST_ENTER_SIM_PIN = 2; @@ -291,6 +292,8 @@ cat include/telephony/ril.h | \ int RIL_REQUEST_SET_DC_RT_INFO_RATE = 127; int RIL_REQUEST_SET_DATA_PROFILE = 128; int RIL_REQUEST_SHUTDOWN = 129; + int RIL_REQUEST_GET_RADIO_CAPABILITY = 130; + int RIL_REQUEST_SET_RADIO_CAPABILITY = 131; int RIL_UNSOL_RESPONSE_BASE = 1000; int RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED = 1000; @@ -334,4 +337,6 @@ cat include/telephony/ril.h | \ int RIL_UNSOL_UICC_SUBSCRIPTION_STATUS_CHANGED = 1038; int RIL_UNSOL_SRVCC_STATE_NOTIFY = 1039; int RIL_UNSOL_HARDWARE_CONFIG_CHANGED = 1040; + int RIL_UNSOL_DC_RT_INFO_CHANGED = 1041; + int RIL_UNSOL_RADIO_CAPABILITY = 1042; } diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java index e7aca90..d05e7d1 100644 --- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java +++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java @@ -401,4 +401,23 @@ public class TelephonyIntents { */ public static final String ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED = "android.intent.action.ACTION_DEFAULT_SMS_SUBSCRIPTION_CHANGED"; + + /* + * Broadcast Action: An attempt to set phone radio type and access technology has changed. + * This has the following extra values: + * <ul> + * <li><em>phones radio access family </em> - A RadioAccessFamily + * array, contain phone ID and new radio access family for each phone.</li> + * </ul> + */ + public static final String ACTION_SET_RADIO_CAPABILITY_DONE = + "android.intent.action.ACTION_SET_RADIO_CAPABILITY_DONE"; + + public static final String EXTRA_RADIO_ACCESS_FAMILY = "rafs"; + + /* + * Broadcast Action: An attempt to set phone radio access family has failed. + */ + public static final String ACTION_SET_RADIO_CAPABILITY_FAILED = + "android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED"; } diff --git a/test-runner/src/android/test/ActivityUnitTestCase.java b/test-runner/src/android/test/ActivityUnitTestCase.java index 8aa8824..40cca90 100644 --- a/test-runner/src/android/test/ActivityUnitTestCase.java +++ b/test-runner/src/android/test/ActivityUnitTestCase.java @@ -26,6 +26,9 @@ import android.os.Bundle; import android.os.IBinder; import android.test.mock.MockApplication; import android.view.Window; +import android.util.Log; + + /** * This class provides isolated testing of a single activity. The activity under test will @@ -73,6 +76,7 @@ import android.view.Window; public abstract class ActivityUnitTestCase<T extends Activity> extends ActivityTestCase { + private static final String TAG = "ActivityUnitTestCase"; private Class<T> mActivityClass; private Context mActivityContext; @@ -132,27 +136,28 @@ public abstract class ActivityUnitTestCase<T extends Activity> if (mApplication == null) { setApplication(new MockApplication()); } - ComponentName cn = new ComponentName(mActivityClass.getPackage().getName(), + ComponentName cn = new ComponentName(mActivityClass.getPackage().getName(), mActivityClass.getName()); intent.setComponent(cn); ActivityInfo info = new ActivityInfo(); CharSequence title = mActivityClass.getName(); mMockParent = new MockParent(); String id = null; - + newActivity = (T) getInstrumentation().newActivity(mActivityClass, mActivityContext, token, mApplication, intent, info, title, mMockParent, id, lastNonConfigurationInstance); } catch (Exception e) { + Log.w(TAG, "Catching exception", e); assertNotNull(newActivity); } - + assertNotNull(newActivity); setActivity(newActivity); mAttached = true; } - + T result = getActivity(); if (result != null) { getInstrumentation().callActivityOnCreate(getActivity(), savedInstanceState); diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java index afe1d5d..7f1dc71 100644 --- a/test-runner/src/android/test/mock/MockPackageManager.java +++ b/test-runner/src/android/test/mock/MockPackageManager.java @@ -793,4 +793,11 @@ public class MockPackageManager extends PackageManager { public Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) { throw new UnsupportedOperationException(); } + + /** + * @hide + */ + public Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo) { + throw new UnsupportedOperationException(); + } } diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml index bc2f1fd..8531944 100644 --- a/tests/HwAccelerationTest/AndroidManifest.xml +++ b/tests/HwAccelerationTest/AndroidManifest.xml @@ -342,6 +342,24 @@ </activity> <activity + android:name="HardwareCanvasTextureViewActivity" + android:label="TextureView/HardwareCanvas"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity + android:name="HardwareCanvasSurfaceViewActivity" + android:label="SurfaceView/HardwareCanvas"> + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + <category android:name="com.android.test.hwui.TEST" /> + </intent-filter> + </activity> + + <activity android:name="GLTextureViewActivity" android:label="TextureView/OpenGL"> <intent-filter> diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java new file mode 100644 index 0000000..b1431c5 --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasSurfaceViewActivity.java @@ -0,0 +1,124 @@ +/* + * 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.test.hwui; + +import android.app.Activity; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.os.Bundle; +import android.view.Gravity; +import android.view.Surface; +import android.view.SurfaceHolder; +import android.view.SurfaceHolder.Callback; +import android.view.SurfaceView; +import android.widget.FrameLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class HardwareCanvasSurfaceViewActivity extends Activity implements Callback { + private SurfaceView mSurfaceView; + private HardwareCanvasSurfaceViewActivity.RenderingThread mThread; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + FrameLayout content = new FrameLayout(this); + + mSurfaceView = new SurfaceView(this); + mSurfaceView.getHolder().addCallback(this); + + content.addView(mSurfaceView, new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.MATCH_PARENT, + FrameLayout.LayoutParams.MATCH_PARENT, + Gravity.CENTER)); + setContentView(content); + } + + @Override + public void surfaceCreated(SurfaceHolder holder) { + mThread = new RenderingThread(holder.getSurface()); + mThread.start(); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + mThread.setSize(width, height); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + if (mThread != null) mThread.stopRendering(); + } + + private static class RenderingThread extends Thread { + private final Surface mSurface; + private volatile boolean mRunning = true; + private int mWidth, mHeight; + + public RenderingThread(Surface surface) { + mSurface = surface; + } + + void setSize(int width, int height) { + mWidth = width; + mHeight = height; + } + + @Override + public void run() { + float x = 0.0f; + float y = 0.0f; + float speedX = 5.0f; + float speedY = 3.0f; + + Paint paint = new Paint(); + paint.setColor(0xff00ff00); + + while (mRunning && !Thread.interrupted()) { + final Canvas canvas = mSurface.lockHardwareCanvas(); + try { + canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); + canvas.drawRect(x, y, x + 20.0f, y + 20.0f, paint); + } finally { + mSurface.unlockCanvasAndPost(canvas); + } + + if (x + 20.0f + speedX >= mWidth || x + speedX <= 0.0f) { + speedX = -speedX; + } + if (y + 20.0f + speedY >= mHeight || y + speedY <= 0.0f) { + speedY = -speedY; + } + + x += speedX; + y += speedY; + + try { + Thread.sleep(15); + } catch (InterruptedException e) { + // Interrupted + } + } + } + + void stopRendering() { + interrupt(); + mRunning = false; + } + } +} diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasTextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasTextureViewActivity.java new file mode 100644 index 0000000..63a6efa --- /dev/null +++ b/tests/HwAccelerationTest/src/com/android/test/hwui/HardwareCanvasTextureViewActivity.java @@ -0,0 +1,124 @@ +/* + * 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.test.hwui; + +import android.app.Activity; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.PorterDuff; +import android.graphics.SurfaceTexture; +import android.os.Bundle; +import android.view.Gravity; +import android.view.Surface; +import android.view.TextureView; +import android.widget.FrameLayout; + +@SuppressWarnings({"UnusedDeclaration"}) +public class HardwareCanvasTextureViewActivity extends Activity + implements TextureView.SurfaceTextureListener { + private TextureView mTextureView; + private HardwareCanvasTextureViewActivity.RenderingThread mThread; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + FrameLayout content = new FrameLayout(this); + + mTextureView = new TextureView(this); + mTextureView.setSurfaceTextureListener(this); + mTextureView.setOpaque(false); + + content.addView(mTextureView, new FrameLayout.LayoutParams(500, 500, Gravity.CENTER)); + setContentView(content); + } + + @Override + public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { + mThread = new RenderingThread(mTextureView); + mThread.start(); + } + + @Override + public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { + // Ignored + } + + @Override + public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { + if (mThread != null) mThread.stopRendering(); + return true; + } + + @Override + public void onSurfaceTextureUpdated(SurfaceTexture surface) { + // Ignored + } + + private static class RenderingThread extends Thread { + private final TextureView mView; + private final Surface mSurface; + private volatile boolean mRunning = true; + + public RenderingThread(TextureView view) { + mView = view; + mSurface = new Surface(mView.getSurfaceTexture()); + } + + @Override + public void run() { + float x = 0.0f; + float y = 0.0f; + float speedX = 5.0f; + float speedY = 3.0f; + + Paint paint = new Paint(); + paint.setColor(0xff00ff00); + + while (mRunning && !Thread.interrupted()) { + final Canvas canvas = mSurface.lockHardwareCanvas(); + try { + canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); + canvas.drawRect(x, y, x + 20.0f, y + 20.0f, paint); + } finally { + mSurface.unlockCanvasAndPost(canvas); + } + + if (x + 20.0f + speedX >= mView.getWidth() || x + speedX <= 0.0f) { + speedX = -speedX; + } + if (y + 20.0f + speedY >= mView.getHeight() || y + speedY <= 0.0f) { + speedY = -speedY; + } + + x += speedX; + y += speedY; + + try { + Thread.sleep(15); + } catch (InterruptedException e) { + // Interrupted + } + } + } + + void stopRendering() { + interrupt(); + mRunning = false; + } + } +} diff --git a/tests/VectorDrawableTest/AndroidManifest.xml b/tests/VectorDrawableTest/AndroidManifest.xml index 7796953..991ec57 100644 --- a/tests/VectorDrawableTest/AndroidManifest.xml +++ b/tests/VectorDrawableTest/AndroidManifest.xml @@ -18,7 +18,7 @@ <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.test.dynamic" > - <uses-sdk android:minSdkVersion="20" /> + <uses-sdk android:minSdkVersion="21" /> <application android:hardwareAccelerated="true" diff --git a/tests/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml b/tests/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml new file mode 100644 index 0000000..867abc7 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/alpha_animation_progress_bar.xml @@ -0,0 +1,24 @@ +<!-- 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. +--> + +<set xmlns:android="http://schemas.android.com/apk/res/android" > + + <objectAnimator + android:duration="1350" + android:propertyName="alpha" + android:valueFrom="1" + android:valueTo="0.2" /> + +</set>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_left.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_left.xml new file mode 100644 index 0000000..b465ead --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_left.xml @@ -0,0 +1,61 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="scaleX" + android:valueFrom="1" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="scaleX" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="scaleY" + android:valueFrom="1" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="scaleY" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="-45" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_right.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_right.xml new file mode 100644 index 0000000..49ac165 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_dot_right.xml @@ -0,0 +1,61 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="scaleX" + android:valueFrom="1" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="scaleX" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="scaleY" + android:valueFrom="1" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="scaleY" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="45" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_ic_signal_wifi_4_bar_48px_outlines_.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_ic_signal_wifi_4_bar_48px_outlines_.xml new file mode 100644 index 0000000..1bdfde6 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_ic_signal_wifi_4_bar_48px_outlines_.xml @@ -0,0 +1,31 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="alpha" + android:valueFrom="1" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="alpha" + android:valueFrom="1" + android:valueTo="0.5" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_mask.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_mask.xml new file mode 100644 index 0000000..47efa18 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_mask.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 30.0523681641 -35.8077850342 30.0523681641 c 0.0 0.0 12.925994873 12.9778747559 12.925994873 12.9778747559 c 0.0 0.0 -2.61700439453 2.09387207031 -2.61700439453 2.09387207031 c 0.0 0.0 -13.1259613037 -12.9893035889 -13.1259613037 -12.9893035889 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" + android:valueTo="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 30.0523681641 -35.8077850342 30.0523681641 c 0.0 0.0 12.925994873 12.9778747559 12.925994873 12.9778747559 c 0.0 0.0 -2.61700439453 2.09387207031 -2.61700439453 2.09387207031 c 0.0 0.0 -13.1259613037 -12.9893035889 -13.1259613037 -12.9893035889 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="133" + android:propertyName="pathData" + android:valueFrom="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 30.0523681641 -35.8077850342 30.0523681641 c 0.0 0.0 12.925994873 12.9778747559 12.925994873 12.9778747559 c 0.0 0.0 -2.61700439453 2.09387207031 -2.61700439453 2.09387207031 c 0.0 0.0 -13.1259613037 -12.9893035889 -13.1259613037 -12.9893035889 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" + android:valueTo="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 29.7398681641 -35.8077850342 29.7398681641 c 0.0 0.0 27.2634735107 27.4966583252 27.2634735107 27.4966583252 c 0.0 0.0 -2.61700439453 2.4063873291 -2.61700439453 2.4063873291 c 0.0 0.0 -27.4634399414 -27.508102417 -27.4634399414 -27.508102417 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_path_1.xml b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_path_1.xml new file mode 100644 index 0000000..41fe866 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_bluethooth_v2_animation_path_1.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 10.6188659668 6.56344604492 c 0.0 0.0 21.7386016846 23.1297454834 21.7386016846 23.1297454834 " + android:valueTo="M 10.6188659668 6.56344604492 c 0.0 0.0 21.7386016846 23.1297454834 21.7386016846 23.1297454834 " + android:valueType="pathType" + android:interpolator="@interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator" /> + <objectAnimator + android:duration="350" + android:propertyName="pathData" + android:valueFrom="M 10.6188659668 6.56344604492 c 0.0 0.0 21.7386016846 23.1297454834 21.7386016846 23.1297454834 " + android:valueTo="M 8.62858581543 4.33430480957 c 0.0 0.0 28.1998138428 30.2359008789 28.1998138428 30.2359008789 " + android:valueType="pathType" + android:interpolator="@interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_frame.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_frame.xml new file mode 100644 index 0000000..9cea85d --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_frame.xml @@ -0,0 +1,31 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="367" + android:propertyName="alpha" + android:valueFrom="0.5" + android:valueTo="0.5" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="333" + android:propertyName="alpha" + android:valueFrom="0.5" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_screen.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_screen.xml new file mode 100644 index 0000000..61b018b --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_screen.xml @@ -0,0 +1,31 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="367" + android:propertyName="alpha" + android:valueFrom="0" + android:valueTo="0" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="333" + android:propertyName="alpha" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave1.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave1.xml new file mode 100644 index 0000000..002f7b2 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave1.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z" + android:valueTo="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="500" + android:propertyName="pathData" + android:valueFrom="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z" + android:valueTo="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave2.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave2.xml new file mode 100644 index 0000000..0c2ee21 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave2.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z" + android:valueTo="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="333" + android:propertyName="pathData" + android:valueFrom="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z" + android:valueTo="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave3.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave3.xml new file mode 100644 index 0000000..a75b2eaf --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave3.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z" + android:valueTo="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="167" + android:propertyName="pathData" + android:valueFrom="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z" + android:valueTo="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave5.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave5.xml new file mode 100644 index 0000000..7e79b94 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave5.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z" + android:valueTo="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="500" + android:propertyName="pathData" + android:valueFrom="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z" + android:valueTo="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave6.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave6.xml new file mode 100644 index 0000000..0917e0e --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_wave6.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z" + android:valueTo="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="333" + android:propertyName="pathData" + android:valueFrom="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z" + android:valueTo="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_waves.xml b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_waves.xml new file mode 100644 index 0000000..9cea85d --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_cast_v2_animation_waves.xml @@ -0,0 +1,31 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="367" + android:propertyName="alpha" + android:valueFrom="0.5" + android:valueTo="0.5" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="333" + android:propertyName="alpha" + android:valueFrom="0.5" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml new file mode 100644 index 0000000..17499d5 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_fill_outlines.xml @@ -0,0 +1,22 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="333" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="180" + android:interpolator="@android:interpolator/fast_out_slow_in" /> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml new file mode 100644 index 0000000..17499d5 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_hourglass_frame.xml @@ -0,0 +1,22 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="333" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="180" + android:interpolator="@android:interpolator/fast_out_slow_in" /> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml new file mode 100644 index 0000000..541792e --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_hourglass_animation_mask_1.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="333" + android:propertyName="pathData" + android:valueFrom="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z" + android:valueTo="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="1000" + android:propertyName="pathData" + android:valueFrom="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z" + android:valueTo="M 24 0.00173950195312 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6982574463 0 10.6982574463 c 0 0.0 24 0.0 24 0.0 c 0 0.0 0 -10.6982574463 0 -10.6982574463 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_start.xml b/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_start.xml new file mode 100644 index 0000000..c26c8ed --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_start.xml @@ -0,0 +1,86 @@ +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="833" + android:propertyName="translateX" + android:valueFrom="144" + android:valueTo="144" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="100" + android:propertyName="translateX" + android:valueFrom="144" + android:valueTo="147.411817411" + android:interpolator="@interpolator/ic_open_ball_start_translatex_interpolator" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="167" + android:propertyName="translateY" + android:valueFrom="144.58457376" + android:valueTo="144.58457376" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="333" + android:propertyName="translateY" + android:valueFrom="144.58457376" + android:valueTo="196.11111456" + android:interpolator="@interpolator/ic_open_ball_start_translatey_interpolator_1" /> + <objectAnimator + android:duration="333" + android:propertyName="translateY" + android:valueFrom="196.11111456" + android:valueTo="196.11111456" + android:interpolator="@interpolator/ic_open_ball_start_translatey_interpolator_2" /> + <objectAnimator + android:duration="100" + android:propertyName="translateY" + android:valueFrom="196.11111456" + android:valueTo="129.468428513" + android:interpolator="@interpolator/ic_open_ball_start_translatey_interpolator_3" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="167" + android:propertyName="scaleX" + android:valueFrom="0" + android:valueTo="0.71187984" + android:interpolator="@interpolator/ic_open_ball_start_scalex_interpolator_1" /> + <objectAnimator + android:duration="667" + android:propertyName="scaleX" + android:valueFrom="0.71187984" + android:valueTo="0.71187984" + android:interpolator="@interpolator/ic_open_ball_start_scalex_interpolator_2" /> + <objectAnimator + android:duration="100" + android:propertyName="scaleX" + android:valueFrom="0.71187984" + android:valueTo="0.586201598553" + android:interpolator="@interpolator/ic_open_ball_start_scalex_interpolator_3" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="167" + android:propertyName="scaleY" + android:valueFrom="0" + android:valueTo="0.71187984" + android:interpolator="@interpolator/ic_open_ball_start_scaley_interpolator_1" /> + <objectAnimator + android:duration="667" + android:propertyName="scaleY" + android:valueFrom="0.71187984" + android:valueTo="0.71187984" + android:interpolator="@interpolator/ic_open_ball_start_scaley_interpolator_2" /> + <objectAnimator + android:duration="100" + android:propertyName="scaleY" + android:valueFrom="0.71187984" + android:valueTo="0.586201598553" + android:interpolator="@interpolator/ic_open_ball_start_scaley_interpolator_3" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_swoop.xml b/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_swoop.xml new file mode 100644 index 0000000..5096514 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_open_animation_ball_swoop.xml @@ -0,0 +1,17 @@ +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="933" + android:propertyName="rotation" + android:valueFrom="-90" + android:valueTo="-90" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="1367" + android:propertyName="rotation" + android:valueFrom="-90" + android:valueTo="-87" + android:interpolator="@android:interpolator/linear" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1.xml b/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1.xml new file mode 100644 index 0000000..ef8496e --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1.xml @@ -0,0 +1,48 @@ +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="500" + android:propertyName="pathData" + android:valueFrom="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z" + android:valueTo="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="267" + android:propertyName="pathData" + android:valueFrom="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z" + android:valueTo="M 0,-6 c -9.625,0 -23.5648803711,6.97859191895 -23.5648803711,16.1035919189 c 0.0,8.875 6.62738037109,8.39640808105 23.5648803711,8.39640808105 c 17.0625,0.0 23.8825073242,0.375 23.8825073242,-8.25 c 0.0,-8.625 -14.2574920654,-16.25 -23.8825073242,-16.25 Z" + android:valueType="pathType" + android:interpolator="@interpolator/ic_open_path_1_pathdata_interpolator_1" /> + <objectAnimator + android:duration="33" + android:propertyName="pathData" + android:valueFrom="M 0,-6 c -9.625,0 -23.5648803711,6.97859191895 -23.5648803711,16.1035919189 c 0.0,8.875 6.62738037109,8.39640808105 23.5648803711,8.39640808105 c 17.0625,0.0 23.8825073242,0.375 23.8825073242,-8.25 c 0.0,-8.625 -14.2574920654,-16.25 -23.8825073242,-16.25 Z" + android:valueTo="M 0,-6 c -9.625,0 -23.5648803711,6.97859191895 -23.5648803711,16.1035919189 c 0.0,8.875 6.62738037109,8.39640808105 23.5648803711,8.39640808105 c 17.0625,0.0 23.8825073242,0.375 23.8825073242,-8.25 c 0.0,-8.625 -14.2574920654,-16.25 -23.8825073242,-16.25 Z" + android:valueType="pathType" + android:interpolator="@interpolator/ic_open_path_1_pathdata_interpolator_2" /> + <objectAnimator + android:duration="67" + android:propertyName="pathData" + android:valueFrom="M 0,-6 c -9.625,0 -23.5648803711,6.97859191895 -23.5648803711,16.1035919189 c 0.0,8.875 6.62738037109,8.39640808105 23.5648803711,8.39640808105 c 17.0625,0.0 23.8825073242,0.375 23.8825073242,-8.25 c 0.0,-8.625 -14.2574920654,-16.25 -23.8825073242,-16.25 Z" + android:valueTo="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z" + android:valueType="pathType" + android:interpolator="@interpolator/ic_open_path_1_pathdata_interpolator_3" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="933" + android:propertyName="fillAlpha" + android:valueFrom="1" + android:valueTo="1" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="17" + android:propertyName="fillAlpha" + android:valueFrom="1" + android:valueTo="0" + android:interpolator="@android:interpolator/linear" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1_1.xml b/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1_1.xml new file mode 100644 index 0000000..4961204 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_open_animation_path_1_1.xml @@ -0,0 +1,74 @@ +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="917" + android:propertyName="strokeAlpha" + android:valueFrom="0" + android:valueTo="0" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="17" + android:propertyName="strokeAlpha" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:interpolator/linear" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="917" + android:propertyName="strokeWidth" + android:valueFrom="0" + android:valueTo="0" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="17" + android:propertyName="strokeWidth" + android:valueFrom="0" + android:valueTo="20" + android:interpolator="@android:interpolator/linear" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="933" + android:propertyName="trimPathStart" + android:valueFrom="0.06" + android:valueTo="0.06" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="383" + android:propertyName="trimPathStart" + android:valueFrom="0.06" + android:valueTo="0.19231" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="983" + android:propertyName="trimPathStart" + android:valueFrom="0.19231" + android:valueTo="0.999" + android:interpolator="@interpolator/ic_open_path_1_1_trimpathstart_interpolator_2" /> + </set> + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="933" + android:propertyName="trimPathEnd" + android:valueFrom="0.061" + android:valueTo="0.061" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="300" + android:propertyName="trimPathEnd" + android:valueFrom="0.061" + android:valueTo="0.19231" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="1067" + android:propertyName="trimPathEnd" + android:valueFrom="0.19231" + android:valueTo="1" + android:interpolator="@interpolator/ic_open_path_1_1_trimpathend_interpolator_2" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml new file mode 100644 index 0000000..496e3ed --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_arrows_1.xml @@ -0,0 +1,37 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="333" + android:startOffset="317" + android:propertyXName="scaleX" + android:propertyYName="scaleY" + android:pathData="M 1 1 l -0.1 -0.1 " + android:valueType="pathType" + android:interpolator="@interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator" /> + <objectAnimator + android:duration="617" + android:startOffset="200" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="-221" + android:interpolator="@interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator" /> + <objectAnimator + android:duration="83" + android:startOffset="600" + android:propertyName="alpha" + android:valueFrom="1" + android:valueTo="0" /> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml new file mode 100644 index 0000000..47e1e71 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_1.xml @@ -0,0 +1,23 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="400" + android:startOffset="200" + android:propertyName="rotation" + android:valueFrom="0" + android:valueTo="-135" + android:interpolator="@interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator" /> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml new file mode 100644 index 0000000..f1126cf --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_rotate_2_portrait_v2_animation_device_2.xml @@ -0,0 +1,24 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <objectAnimator + android:duration="217" + android:startOffset="267" + android:propertyName="pathData" + android:valueFrom="M -3.5 -20.5 c -1.19999694824 -1.19999694824 -3.10000610352 -1.19999694824 -4.19999694824 0.0 c 0.0 0.0 -12.8000030518 12.6999969482 -12.8000030518 12.6999969482 c -1.19999694824 1.19999694824 -1.19999694824 3.10000610352 0.0 4.19999694824 c 0.0 0.0 24.0 24.0000152588 24.0 24.0000152588 c 1.19999694824 1.19999694824 3.10000610352 1.19999694824 4.19999694824 0.0 c 0.0 0.0 12.6999969482 -12.700012207 12.6999969482 -12.700012207 c 1.20001220703 -1.19999694824 1.20001220703 -3.09999084473 0.0 -4.19999694824 c 0.0 0.0 -23.8999938965 -24.0 -23.8999938965 -24.0 Z M 2.84999084473 15.5500183105 c 0.0 0.0 -18.6000061035 -18.5000457764 -18.6000061035 -18.5000457764 c 0.0 0.0 12.5999908447 -12.8000030518 12.5999908447 -12.8000030518 c 0.0 0.0 18.6000213623 18.5000457764 18.6000213623 18.5000457764 c 0.0 0.0 -12.6000061035 12.8000030518 -12.6000061035 12.8000030518 Z" + android:valueTo="M -3.34053039551 -22.9980926514 c -1.3207244873 -1.3207244873 -3.46876525879 -1.26383972168 -4.74829101563 0.125762939453 c 0.0 0.0 -14.8512420654 14.7411804199 -14.8512420654 14.7411804199 c -1.39259338379 1.392578125 -1.44947814941 3.54061889648 -0.125762939453 4.74827575684 c 0.0 0.0 26.4143981934 26.4144134521 26.4143981934 26.4144134521 c 1.3207244873 1.3207244873 3.46876525879 1.26382446289 4.74829101562 -0.125762939453 c 0.0 0.0 14.7381896973 -14.7381896973 14.7381896973 -14.7381896973 c 1.392578125 -1.39259338379 1.44947814941 -3.54061889648 0.125762939453 -4.74829101562 c 0.0 0.0 -26.3013458252 -26.417388916 -26.3013458252 -26.417388916 Z M 2.87156677246 16.9857940674 c 0.0 0.0 -19.7573547363 -19.7573699951 -19.7573547363 -19.7573699951 c 0.0 0.0 14.0142059326 -14.2142181396 14.0142059326 -14.2142181396 c 0.0 0.0 19.7573699951 19.7573699951 19.7573699951 19.7573699951 c 0.0 0.0 -14.0142211914 14.2142181396 -14.0142211914 14.2142181396 Z" + android:valueType="pathType" + android:interpolator="@interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator" /> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml new file mode 100644 index 0000000..993493b --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_cross_1.xml @@ -0,0 +1,31 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="alpha" + android:valueFrom="0" + android:valueTo="0" + android:interpolator="@android:interpolator/linear" /> + <objectAnimator + android:duration="17" + android:propertyName="alpha" + android:valueFrom="0" + android:valueTo="1" + android:interpolator="@android:interpolator/linear" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml new file mode 100644 index 0000000..1bdfde6 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_ic_signal_airplane.xml @@ -0,0 +1,31 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="alpha" + android:valueFrom="1" + android:valueTo="1" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="alpha" + android:valueFrom="1" + android:valueTo="0.5" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml new file mode 100644 index 0000000..94b0a32 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_mask_2.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 9.55097961426 9.55285644531 9.55097961426 9.55285644531 c 0.0 0.0 -2.61698913574 2.09387207031 -2.61698913574 2.09387207031 c 0.0 0.0 -9.75096130371 -9.56428527832 -9.75096130371 -9.56428527832 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" + android:valueTo="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 9.55097961426 9.55285644531 9.55097961426 9.55285644531 c 0.0 0.0 -2.61698913574 2.09387207031 -2.61698913574 2.09387207031 c 0.0 0.0 -9.75096130371 -9.56428527832 -9.75096130371 -9.56428527832 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + <objectAnimator + android:duration="350" + android:propertyName="pathData" + android:valueFrom="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 9.55097961426 9.55285644531 9.55097961426 9.55285644531 c 0.0 0.0 -2.61698913574 2.09387207031 -2.61698913574 2.09387207031 c 0.0 0.0 -9.75096130371 -9.56428527832 -9.75096130371 -9.56428527832 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" + android:valueTo="M 37.8337860107 -40.3974914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 40.9884796143 40.9278411865 40.9884796143 40.9278411865 c 0.0 0.0 -2.61700439453 2.0938873291 -2.61700439453 2.0938873291 c 0.0 0.0 -41.1884460449 -40.9392852783 -41.1884460449 -40.9392852783 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" + android:valueType="pathType" + android:interpolator="@android:interpolator/fast_out_slow_in" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml new file mode 100644 index 0000000..0a4a7c4 --- /dev/null +++ b/tests/VectorDrawableTest/res/anim/ic_signal_airplane_v2_animation_path_1_1.xml @@ -0,0 +1,33 @@ +<!-- 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. +--> +<set xmlns:android="http://schemas.android.com/apk/res/android" > + <set + android:ordering="sequentially" > + <objectAnimator + android:duration="200" + android:propertyName="pathData" + android:valueFrom="M 7.54049682617 3.9430847168 c 0.0 0.0 0.324981689453 0.399978637695 0.324981689453 0.399978637695 " + android:valueTo="M 7.54049682617 3.9430847168 c 0.0 0.0 0.324981689453 0.399978637695 0.324981689453 0.399978637695 " + android:valueType="pathType" + android:interpolator="@interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator" /> + <objectAnimator + android:duration="350" + android:propertyName="pathData" + android:valueFrom="M 7.54049682617 3.9430847168 c 0.0 0.0 0.324981689453 0.399978637695 0.324981689453 0.399978637695 " + android:valueTo="M 7.54049682617 3.9430847168 c 0.0 0.0 31.5749816895 31.4499664307 31.5749816895 31.4499664307 " + android:valueType="pathType" + android:interpolator="@interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator" /> + </set> +</set> diff --git a/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml index 6621e41..4d46ee8 100644 --- a/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml +++ b/tests/VectorDrawableTest/res/drawable/animation_vector_progress_bar.xml @@ -19,5 +19,7 @@ <target android:name="pie1" android:animation="@anim/trim_path_animation_progress_bar" /> - + <target + android:name="root_bar" + android:animation="@anim/alpha_animation_progress_bar" /> </animated-vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2.xml b/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2.xml new file mode 100644 index 0000000..5f068fc --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2.xml @@ -0,0 +1,81 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="48dp" + android:width="48dp" + android:viewportHeight="48" + android:viewportWidth="48" + android:name="root_bt"> + <group + android:name="ic_signal_wifi_4_bar_48px_outlines_" + android:translateX="21.9995" + android:translateY="25.73401" > + <group + android:name="ic_signal_wifi_4_bar_48px_outlines__pivot" + android:translateX="-23.21545" + android:translateY="-18.86649" > + <clip-path + android:name="mask" + android:pathData="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 30.0523681641 -35.8077850342 30.0523681641 c 0.0 0.0 12.925994873 12.9778747559 12.925994873 12.9778747559 c 0.0 0.0 -2.61700439453 2.09387207031 -2.61700439453 2.09387207031 c 0.0 0.0 -13.1259613037 -12.9893035889 -13.1259613037 -12.9893035889 c 0.0 0.0 -34.6200408936 26.9699249268 -34.6200408936 26.9699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" /> + <group + android:name="cross" + android:rotation="-1.88453332239" > + <path + android:name="path_1" + android:pathData="M 10.6188659668 6.56344604492 c 0.0 0.0 21.7386016846 23.1297454834 21.7386016846 23.1297454834 " + android:strokeColor="#FF777777" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + <group + android:name="bluetooth" + android:translateX="23.38789" + android:translateY="18.72031" > + <path + android:name="path_4" + android:pathData="M 11.3999938965 -8.60000610352 c 0.0 0.0 -11.3999938965 -11.3999938965 -11.3999938965 -11.3999938965 c 0 0 -2 0 -2 0 c 0 0 0 15.1999969482 0 15.1999969482 c 0 0.0 -9.19999694824 -9.19999694824 -9.19999694824 -9.19999694824 c 0.0 0 -2.80000305176 2.80000305176 -2.80000305176 2.80000305176 c 0 0.0 11.1999969482 11.1999969482 11.1999969482 11.1999969482 c 0.0 0 -11.1999969482 11.1999969482 -11.1999969482 11.1999969482 c 0 0.0 2.80000305176 2.80000305176 2.80000305176 2.80000305176 c 0.0 0 9.19999694824 -9.19999694824 9.19999694824 -9.19999694824 c 0 0.0 0 15.1999969482 0 15.1999969482 c 0 0 2 0 2 0 c 0 0 11.3999938965 -11.3999938965 11.3999938965 -11.3999938965 c 0.0 0.0 -8.59999084473 -8.60000610352 -8.59999084473 -8.60000610352 c 0.0 0 8.59999084473 -8.60000610352 8.59999084473 -8.60000610352 Z M 2 -12.3000030518 c 0 0.0 3.80000305176 3.80000305176 3.80000305176 3.80000305176 c 0.0 0.0 -3.80000305176 3.69999694824 -3.80000305176 3.69999694824 c 0 0.0 0 -7.5 0 -7.5 Z M 5.80000305176 8.60000610352 c 0.0 0.0 -3.80000305176 3.69999694824 -3.80000305176 3.69999694824 c 0 0.0 0 -7.5 0 -7.5 c 0 0.0 3.80000305176 3.80000305176 3.80000305176 3.80000305176 Z" + android:fillColor="#FF777777" /> + </group> + <group + android:name="dot_left" + android:translateX="20.16992" + android:translateY="18.64258" > + <group + android:name="dot_left_pivot" + android:translateX="-20.16992" + android:translateY="-18.64258" > + <path + android:name="dot_left_1" + android:pathData="M 13.3878936768 18.7203063965 c 0.0 0.0 -4.0 -4.0 -4.0 -4.0 c 0.0 0.0 -4.0 4.0 -4.0 4.0 c 0.0 0.0 4.0 4.0 4.0 4.0 c 0.0 0.0 4.0 -4.0 4.0 -4.0 Z" + android:fillColor="#FF777777" /> + </group> + </group> + <group + android:name="dot_right" + android:translateX="26.16094" + android:translateY="18.60898" > + <group + android:name="dot_right_pivot" + android:translateX="-26.16094" + android:translateY="-18.60898" > + <path + android:name="dot_right_1" + android:pathData="M 37.3878936768 14.7203063965 c 0.0 0.0 -4.0 4.0 -4.0 4.0 c 0.0 0.0 4.0 4.0 4.0 4.0 c 0.0 0.0 4.0 -4.0 4.0 -4.0 c 0.0 0.0 -4.0 -4.0 -4.0 -4.0 Z" + android:fillColor="#FF777777" /> + </group> + </group> + </group> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2_animation.xml new file mode 100644 index 0000000..aa05468 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_bluethooth_v2_animation.xml @@ -0,0 +1,32 @@ +<!-- 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/ic_bluethooth_v2" > + <target + android:name="root_bt" + android:animation="@anim/ic_bluethooth_v2_animation_ic_signal_wifi_4_bar_48px_outlines_" /> + <target + android:name="mask" + android:animation="@anim/ic_bluethooth_v2_animation_mask" /> + <target + android:name="path_1" + android:animation="@anim/ic_bluethooth_v2_animation_path_1" /> + <target + android:name="dot_left" + android:animation="@anim/ic_bluethooth_v2_animation_dot_left" /> + <target + android:name="dot_right" + android:animation="@anim/ic_bluethooth_v2_animation_dot_right" /> +</animated-vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_cast_v2.xml b/tests/VectorDrawableTest/res/drawable/ic_cast_v2.xml new file mode 100644 index 0000000..207804a --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_cast_v2.xml @@ -0,0 +1,123 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="48dp" + android:width="48dp" + android:viewportHeight="48" + android:viewportWidth="48" > + <group + android:name="ic_cast_connected_48px_outlines" + android:translateX="24" + android:translateY="24" > + <group + android:name="ic_cast_connected_48px_outlines_pivot" + android:translateX="-24" + android:translateY="-24" > + <clip-path + android:name="mask_1" + android:pathData="M 46.6999969482 3.80000305176 c 0.0 0.0 -44.6999664307 0.0 -44.6999664307 0.0 c 0.0 0.0 0.29997253418 38.25 0.29997253418 38.25 c 0.0 0.0 44.8000030518 -0.100021362305 44.8000030518 -0.100021362305 c 0.0 0.0 -0.400009155273 -38.1499786377 -0.400009155273 -38.1499786377 Z" /> + <group + android:name="waves" + android:alpha="0.5" > + <group + android:name="wave1_position" + android:translateX="2" + android:translateY="42" > + <path + android:name="wave1" + android:pathData="M 0 -4.0 a 4 4 0 0 1 4 4 a 4 4 0 0 1 -4 4 a 4 4 0 0 1 -4 -4 a 4 4 0 0 1 4 -4 Z" + android:strokeColor="#FF777777" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + <group + android:name="wave2_position" + android:translateX="2" + android:translateY="42" > + <path + android:name="wave2" + android:pathData="M 0 -12.0 a 12 12 0 0 1 12 12 a 12 12 0 0 1 -12 12 a 12 12 0 0 1 -12 -12 a 12 12 0 0 1 12 -12 Z" + android:strokeColor="#FF777777" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + <group + android:name="wave3_position" + android:translateX="2" + android:translateY="42" > + <path + android:name="wave3" + android:pathData="M 0 -20.0 a 20 20 0 0 1 20 20 a 20 20 0 0 1 -20 20 a 20 20 0 0 1 -20 -20 a 20 20 0 0 1 20 -20 Z" + android:strokeColor="#FF777777" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + <group + android:name="wave5_position" + android:translateX="2" + android:translateY="42" > + <path + android:name="wave5" + android:pathData="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z" + android:strokeColor="#FF777777" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + <group + android:name="wave6_position" + android:translateX="2" + android:translateY="42" > + <path + android:name="wave6" + android:pathData="M 0 -0.0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 a 0 0 0 0 1 0 0 Z" + android:strokeColor="#FF777777" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + <group + android:name="ellipse_path_1_position" + android:translateX="2" + android:translateY="42" > + <path + android:name="ellipse_path_1" + android:pathData="M 0 -2.0 a 2 2 0 0 1 2 2 a 2 2 0 0 1 -2 2 a 2 2 0 0 1 -2 -2 a 2 2 0 0 1 2 -2 Z" + android:strokeColor="#FF777777" + android:strokeWidth="4" + android:fillColor="#00000000" /> + </group> + </group> + <group + android:name="screen" + android:translateX="24" + android:translateY="24" + android:alpha="0" > + <path + android:name="screen_1" + android:pathData="M 14 -10 c 0 0 -28 0 -28 0 c 0 0 0 3.30000305176 0 3.30000305176 c 7.89999389648 2.59999084473 14.1999969482 8.80000305176 16.6999969482 16.6999969482 c 0.0 0 11.3000030518 0 11.3000030518 0 c 0 0 0 -20 0 -20 Z" + android:fillColor="#FF777777" /> + </group> + <group + android:name="frame" + android:translateX="24" + android:translateY="24" + android:alpha="0.5" > + <path + android:name="box" + android:pathData="M 18 -18 c 0 0 -36 0 -36 0 c -2.19999694824 0 -4 1.80000305176 -4 4 c 0 0 0 6 0 6 c 0 0 4 0 4 0 c 0 0 0 -6 0 -6 c 0 0 36 0 36 0 c 0 0 0 28 0 28 c 0 0 -14 0 -14 0 c 0 0 0 4 0 4 c 0 0 14 0 14 0 c 2.19999694824 0 4 -1.80000305176 4 -4 c 0 0 0 -28 0 -28 c 0 -2.19999694824 -1.80000305176 -4 -4 -4 Z" + android:fillColor="#FF777777" /> + </group> + </group> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_cast_v2_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_cast_v2_animation.xml new file mode 100644 index 0000000..7884212 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_cast_v2_animation.xml @@ -0,0 +1,41 @@ +<!-- 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/ic_cast_v2" > + <target + android:name="waves" + android:animation="@anim/ic_cast_v2_animation_waves" /> + <target + android:name="wave1" + android:animation="@anim/ic_cast_v2_animation_wave1" /> + <target + android:name="wave2" + android:animation="@anim/ic_cast_v2_animation_wave2" /> + <target + android:name="wave3" + android:animation="@anim/ic_cast_v2_animation_wave3" /> + <target + android:name="wave5" + android:animation="@anim/ic_cast_v2_animation_wave5" /> + <target + android:name="wave6" + android:animation="@anim/ic_cast_v2_animation_wave6" /> + <target + android:name="screen" + android:animation="@anim/ic_cast_v2_animation_screen" /> + <target + android:name="frame" + android:animation="@anim/ic_cast_v2_animation_frame" /> +</animated-vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_hourglass.xml b/tests/VectorDrawableTest/res/drawable/ic_hourglass.xml new file mode 100644 index 0000000..5b40922 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_hourglass.xml @@ -0,0 +1,74 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="24dp" + android:width="24dp" + android:viewportHeight="24" + android:viewportWidth="24" > + <group + android:name="hourglass_frame" + android:translateX="12" + android:translateY="12" + android:scaleX="0.75" + android:scaleY="0.75" > + <group + android:name="hourglass_frame_pivot" + android:translateX="-12" + android:translateY="-12" > + <group + android:name="group_2_2" + android:translateX="12" + android:translateY="6.5" > + <path + android:name="path_2_2" + android:pathData="M 6.52099609375 -3.89300537109 c 0.0 0.0 -6.52099609375 6.87901306152 -6.52099609375 6.87901306152 c 0 0.0 -6.52099609375 -6.87901306152 -6.52099609375 -6.87901306152 c 0.0 0.0 13.0419921875 0.0 13.0419921875 0.0 Z M 9.99800109863 -6.5 c 0.0 0.0 -19.9960021973 0.0 -19.9960021973 0.0 c -0.890991210938 0.0 -1.33700561523 1.07699584961 -0.707000732422 1.70700073242 c 0.0 0.0 10.7050018311 11.2929992676 10.7050018311 11.2929992676 c 0 0.0 10.7050018311 -11.2929992676 10.7050018311 -11.2929992676 c 0.630004882812 -0.630004882812 0.183990478516 -1.70700073242 -0.707000732422 -1.70700073242 Z" + android:fillColor="#FF777777" /> + </group> + <group + android:name="group_1_2" + android:translateX="12" + android:translateY="17.5" > + <path + android:name="path_2_1" + android:pathData="M 0 -2.98600769043 c 0 0.0 6.52099609375 6.87901306152 6.52099609375 6.87901306152 c 0.0 0.0 -13.0419921875 0.0 -13.0419921875 0.0 c 0.0 0.0 6.52099609375 -6.87901306152 6.52099609375 -6.87901306152 Z M 0 -6.5 c 0 0.0 -10.7050018311 11.2929992676 -10.7050018311 11.2929992676 c -0.630004882812 0.630004882812 -0.184005737305 1.70700073242 0.707000732422 1.70700073242 c 0.0 0.0 19.9960021973 0.0 19.9960021973 0.0 c 0.890991210938 0.0 1.33699035645 -1.07699584961 0.707000732422 -1.70700073242 c 0.0 0.0 -10.7050018311 -11.2929992676 -10.7050018311 -11.2929992676 Z" + android:fillColor="#FF777777" /> + </group> + </group> + </group> + <group + android:name="fill_outlines" + android:translateX="12" + android:translateY="12" + android:scaleX="0.75" + android:scaleY="0.75" > + <group + android:name="fill_outlines_pivot" + android:translateX="-12" + android:translateY="-12" > + <clip-path + android:name="mask_1" + android:pathData="M 24 13.3999938965 c 0 0.0 -24 0.0 -24 0.0 c 0 0.0 0 10.6000061035 0 10.6000061035 c 0 0 24 0 24 0 c 0 0 0 -10.6000061035 0 -10.6000061035 Z" /> + <group + android:name="group_1_3" + android:translateX="12" + android:translateY="12" > + <path + android:name="path_1_6" + android:pathData="M 10.7100067139 10.2900085449 c 0.629989624023 0.629989624023 0.179992675781 1.70999145508 -0.710006713867 1.70999145508 c 0 0 -20 0 -20 0 c -0.889999389648 0 -1.33999633789 -1.08000183105 -0.710006713867 -1.70999145508 c 0.0 0.0 9.76000976562 -10.2900085449 9.76000976563 -10.2900085449 c 0.0 0 -9.76000976562 -10.2899932861 -9.76000976563 -10.2899932861 c -0.629989624023 -0.630004882812 -0.179992675781 -1.71000671387 0.710006713867 -1.71000671387 c 0 0 20 0 20 0 c 0.889999389648 0 1.33999633789 1.08000183105 0.710006713867 1.71000671387 c 0.0 0.0 -9.76000976562 10.2899932861 -9.76000976563 10.2899932861 c 0.0 0 9.76000976562 10.2900085449 9.76000976563 10.2900085449 Z" + android:fillColor="#FF777777" /> + </group> + </group> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml new file mode 100644 index 0000000..3d87376 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_hourglass_animation.xml @@ -0,0 +1,26 @@ +<!-- 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/ic_hourglass" > + <target + android:name="hourglass_frame" + android:animation="@anim/ic_hourglass_animation_hourglass_frame" /> + <target + android:name="fill_outlines" + android:animation="@anim/ic_hourglass_animation_fill_outlines" /> + <target + android:name="mask_1" + android:animation="@anim/ic_hourglass_animation_mask_1" /> +</animated-vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_open.xml b/tests/VectorDrawableTest/res/drawable/ic_open.xml new file mode 100644 index 0000000..ad96094 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_open.xml @@ -0,0 +1,56 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="288dp" + android:width="288dp" + android:viewportHeight="288" + android:viewportWidth="288" > + <group + android:name="ball_start" + android:translateX="147.411817411" + android:translateY="129.468428513" + android:scaleX="0.586201598553" + android:scaleY="0.586201598553" > + <group + android:name="shape_1" + android:scaleX="0.76" + android:scaleY="0.748114397321" > + <path + android:name="path_1" + android:pathData="M 0,-17.3838043213 c -9.625,0.0 -17.0795440674,8.28025817871 -17.0795440674,17.4052734375 c 0.0,9.75645446777 7.51704406738,17.6295623779 17.0795440674,17.353515625 c 11.5579986572,-0.333648681641 17.2784118652,-8.72853088379 17.2784118652,-17.353515625 c 0.0,-8.62501525879 -7.65341186523,-17.4052734375 -17.2784118652,-17.4052734375 Z" + android:fillColor="#FFFF9000" + android:fillAlpha="0" /> + </group> + </group> + <group + android:name="ball_swoop" + android:translateX="144" + android:translateY="144" + android:scaleX="0.752248" + android:scaleY="0.752248" + android:rotation="-87.6585365854" > + <path + android:name="path_1_1" + android:pathData="M -56.7679443359,1.03857421875 c 0.0,0.0 191.916503906,-13.9097290039 191.916503906,88.0704345703 c 0.0,58.4487304688 -83.6709594727,90.1372070312 -137.004882812,90.1372070312 c -82.1782226562,0.0 -177.867431641,-63.5512695312 -177.867431641,-178.207641602 c 0.0,-115.985717773 98.7650146484,-178.160949707 177.986938477,-178.160949707 c 76.2376251221,0.0 178.1640625,60.6796875 178.1640625,178.185058594 " + android:strokeColor="#FFFF9000" + android:strokeAlpha="1" + android:strokeWidth="20" + android:strokeLineCap="round" + android:trimPathStart="0.93025" + android:trimPathEnd="0.96248" + android:trimPathOffset="0" + android:fillColor="#00000000" /> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_open_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_open_animation.xml new file mode 100644 index 0000000..83ee90b --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_open_animation.xml @@ -0,0 +1,29 @@ +<!-- 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/ic_open" > + <target + android:name="ball_start" + android:animation="@anim/ic_open_animation_ball_start" /> + <target + android:name="path_1" + android:animation="@anim/ic_open_animation_path_1" /> + <target + android:name="ball_swoop" + android:animation="@anim/ic_open_animation_ball_swoop" /> + <target + android:name="path_1_1" + android:animation="@anim/ic_open_animation_path_1_1" /> +</animated-vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml b/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml new file mode 100644 index 0000000..b549423 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2.xml @@ -0,0 +1,59 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="48dp" + android:viewportHeight="48" + android:viewportWidth="48" + android:width="48dp" > + + <group + android:name="ic_screen_rotation_48px_outlines_1" + android:translateX="24" + android:translateY="24" > + <group + android:name="ic_screen_rotation_48px_outlines_1_pivot" + android:translateX="-24.15" + android:translateY="-24.25" > + <group + android:name="arrows_1" + android:translateX="24.1" + android:translateY="24.1" > + <group + android:name="arrows_1_pivot" + android:translateX="-24.1" + android:translateY="-24.1" > + <path + android:name="arrow_top_1" + android:fillColor="#FF777777" + android:pathData="M 33.1499938965 5.25 c 6.5 3.10000610352 11.1999969482 9.40000915527 11.8999938965 17.0 c 0.0 0.0 3.00001525879 0.0 3.00001525879 0.0 c -1.00001525879 -12.3000030518 -11.3000030518 -22.0 -23.9000091553 -22.0 c -0.399993896484 0.0 -0.899993896484 0.0 -1.30000305176 0.100006103516 c 0.0 0.0 7.60000610352 7.59999084473 7.60000610352 7.59999084473 c 0.0 0.0 2.69999694824 -2.69999694824 2.69999694824 -2.69999694824 Z" /> + <path + android:name="arrow_bottom_1" + android:fillColor="#FF777777" + android:pathData="M 15.1499938965 43.25 c -6.5 -3.09999084473 -11.1999969482 -9.5 -11.8999938965 -17.0 c 0.0 0.0 -3.0 0.0 -3.0 0.0 c 1.0 12.3000030518 11.299987793 22.0 23.8999938965 22.0 c 0.399993896484 0.0 0.899993896484 0.0 1.30000305176 -0.0999908447266 c 0.0 0.0 -7.60000610352 -7.60000610352 -7.60000610352 -7.60000610352 c 0.0 0.0 -2.69999694824 2.69999694824 -2.69999694824 2.69999694824 Z" /> + </group> + </group> + <group + android:name="device_1" + android:translateX="24.14999" + android:translateY="24.25" > + <path + android:name="device_2" + android:fillColor="#FF777777" + android:pathData="M -3.5 -20.5 c -1.19999694824 -1.19999694824 -3.10000610352 -1.19999694824 -4.19999694824 0.0 c 0.0 0.0 -12.8000030518 12.6999969482 -12.8000030518 12.6999969482 c -1.19999694824 1.19999694824 -1.19999694824 3.10000610352 0.0 4.19999694824 c 0.0 0.0 24.0 24.0000152588 24.0 24.0000152588 c 1.19999694824 1.19999694824 3.10000610352 1.19999694824 4.19999694824 0.0 c 0.0 0.0 12.6999969482 -12.700012207 12.6999969482 -12.700012207 c 1.20001220703 -1.19999694824 1.20001220703 -3.09999084473 0.0 -4.19999694824 c 0.0 0.0 -23.8999938965 -24.0 -23.8999938965 -24.0 Z M 2.84999084473 15.5500183105 c 0.0 0.0 -18.6000061035 -18.5000457764 -18.6000061035 -18.5000457764 c 0.0 0.0 12.5999908447 -12.8000030518 12.5999908447 -12.8000030518 c 0.0 0.0 18.6000213623 18.5000457764 18.6000213623 18.5000457764 c 0.0 0.0 -12.6000061035 12.8000030518 -12.6000061035 12.8000030518 Z" /> + </group> + </group> + </group> + +</vector>
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml new file mode 100644 index 0000000..199fbf8 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_rotate_2_portrait_v2_animation.xml @@ -0,0 +1,26 @@ +<!-- 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/ic_rotate_2_portrait_v2" > + <target + android:name="arrows_1" + android:animation="@anim/ic_rotate_2_portrait_v2_animation_arrows_1" /> + <target + android:name="device_1" + android:animation="@anim/ic_rotate_2_portrait_v2_animation_device_1" /> + <target + android:name="device_2" + android:animation="@anim/ic_rotate_2_portrait_v2_animation_device_2" /> +</animated-vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml b/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml new file mode 100644 index 0000000..8b2a1a8 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2.xml @@ -0,0 +1,52 @@ +<!-- 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="48dp" + android:width="48dp" + android:viewportHeight="48" + android:viewportWidth="48" > + <group + android:name="ic_signal_airplane" + android:translateX="21.9995" + android:translateY="25.73401" > + <group + android:name="ic_signal_airplane_pivot" + android:translateX="-23.21545" + android:translateY="-18.86649" > + <clip-path + android:name="mask_2" + android:pathData="M 37.8337860107 -40.4599914551 c 0.0 0.0 -35.8077850342 31.5523681641 -35.8077850342 31.5523681641 c 0.0 0.0 9.55097961426 9.55285644531 9.55097961426 9.55285644531 c 0.0 0.0 -2.61698913574 2.09387207031 -2.61698913574 2.09387207031 c 0.0 0.0 -9.75096130371 -9.56428527832 -9.75096130371 -9.56428527832 c 0.0 0.0 -34.6200408936 25.4699249268 -34.6200408936 25.4699249268 c 0.0 0.0 55.9664764404 69.742401123 55.9664764404 69.742401123 c 0.0 0.0 73.2448120117 -59.1047973633 73.2448120117 -59.1047973633 c 0.0 0.0 -55.9664916992 -69.7423400879 -55.9664916992 -69.7423400879 Z" /> + <group + android:name="cross_1" + android:alpha="0" > + <path + android:name="path_1_1" + android:pathData="M 7.54049682617 3.9430847168 c 0.0 0.0 0.324981689453 0.399978637695 0.324981689453 0.399978637695 " + android:strokeColor="#FF777777" + android:strokeWidth="3.5" + android:fillColor="#00000000" /> + </group> + <group + android:name="plane" + android:translateX="23.481" + android:translateY="18.71151" > + <path + android:name="path_3_2" + android:pathData="M 18.9439849854 7.98849487305 c 0.0 0.0 0.0 -4.0 0.0 -4.0 c 0.0 0.0 -16.0 -10.0 -16.0 -10.0 c 0.0 0.0 0.0 -11.0 0.0 -11.0 c 0.0 -1.70001220703 -1.30000305176 -3.0 -3.0 -3.0 c -1.69999694824 0.0 -3.0 1.29998779297 -3.0 3.0 c 0.0 0.0 0.0 11.0 0.0 11.0 c 0.0 0.0 -16.0 10.0 -16.0 10.0 c 0.0 0.0 0.0 4.0 0.0 4.0 c 0.0 0.0 16.0 -5.0 16.0 -5.0 c 0.0 0.0 0.0 11.0 0.0 11.0 c 0.0 0.0 -4.0 3.0 -4.0 3.0 c 0.0 0.0 0.0 3.0 0.0 3.0 c 0.0 0.0 7.0 -2.0 7.0 -2.0 c 0.0 0.0 7.0 2.0 7.0 2.0 c 0.0 0.0 0.0 -3.0 0.0 -3.0 c 0.0 0.0 -4.0 -3.0 -4.0 -3.0 c 0.0 0.0 0.0 -11.0 0.0 -11.0 c 0.0 0.0 16.0 5.0 16.0 5.0 Z" + android:fillColor="#FF777777" /> + </group> + </group> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml b/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml new file mode 100644 index 0000000..bde2b38 --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/ic_signal_airplane_v2_animation.xml @@ -0,0 +1,29 @@ +<!-- 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. +--> +<animated-vector xmlns:android="http://schemas.android.com/apk/res/android" + android:drawable="@drawable/ic_signal_airplane_v2" > + <target + android:name="ic_signal_airplane" + android:animation="@anim/ic_signal_airplane_v2_animation_ic_signal_airplane" /> + <target + android:name="mask_2" + android:animation="@anim/ic_signal_airplane_v2_animation_mask_2" /> + <target + android:name="cross_1" + android:animation="@anim/ic_signal_airplane_v2_animation_cross_1" /> + <target + android:name="path_1_1" + android:animation="@anim/ic_signal_airplane_v2_animation_path_1_1" /> +</animated-vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable29.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable29.xml new file mode 100644 index 0000000..c0e9b2a --- /dev/null +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable29.xml @@ -0,0 +1,28 @@ +<!-- + 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. +--> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:height="48dp" + android:width="48dp" + android:viewportHeight="1" + android:viewportWidth="1" > + + <group> + <path + android:name="box1" + android:pathData="l0.0.0.5.0.0.5-0.5.0.0-.5z" + android:fillColor="#ff00ff00"/> + </group> +</vector> diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml index 4544cae..22cd995 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable_progress_bar.xml @@ -17,7 +17,8 @@ android:height="64dp" android:width="64dp" android:viewportHeight="64" - android:viewportWidth="64" > + android:viewportWidth="64" + android:name="root_bar" > <group android:name="root" diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml index 0cffa0a..489596c 100644 --- a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml +++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator.xml @@ -1,2 +1,16 @@ +<!-- 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. +--> <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:pathData="m0,0q0.4,0.05 0.6,0.3t0.3,0.3l0.1,0.4" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml index 935d5b5..3d125e4 100644 --- a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml +++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_favorite.xml @@ -1,2 +1,16 @@ +<!-- 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. +--> <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:pathData="L0.1, 0 C0.10066,0 0.198,1 0.2, 1 L 1,1" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml index 8c57395..6877bd9 100644 --- a/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml +++ b/tests/VectorDrawableTest/res/interpolator/custom_path_interpolator_grouping_1_01.xml @@ -1,2 +1,16 @@ +<!-- 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. +--> <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:pathData="L 0.09 1 L 1,1" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator.xml new file mode 100644 index 0000000..4917f77 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_bluethooth_v2_path_1_pathdata_interpolator.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.16666666667 0.0 0.2 1.0 1.0 1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_1.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_1.xml new file mode 100644 index 0000000..601cfc6 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_1.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.33333333,0.0 0.202777547991,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_2.xml new file mode 100644 index 0000000..5011ef9 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_2.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.0103034467173,0.0 0.701918866569,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_3.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_3.xml new file mode 100644 index 0000000..7b0af97 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scalex_interpolator_3.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.649706648701,0.0 0.884285938423,1.92358061843 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_1.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_1.xml new file mode 100644 index 0000000..601cfc6 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_1.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.33333333,0.0 0.202777547991,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_2.xml new file mode 100644 index 0000000..5011ef9 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_2.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.0103034467173,0.0 0.701918866569,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_3.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_3.xml new file mode 100644 index 0000000..7b0af97 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_scaley_interpolator_3.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.649706648701,0.0 0.884285938423,1.92358061843 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatex_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatex_interpolator.xml new file mode 100644 index 0000000..ea11d1f --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatex_interpolator.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.353876322169,0.0 0.686452288267,-1.02094740172 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_1.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_1.xml new file mode 100644 index 0000000..7bd5c49 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_1.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.754478769148,0.0 0.97,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_2.xml new file mode 100644 index 0000000..b0ab6e8 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_2.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.33333333,0.0 0.83333333333,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_3.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_3.xml new file mode 100644 index 0000000..61060a6 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_ball_start_translatey_interpolator_3.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.324310863613,0.0 0.735625629425,-0.0161527278292 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathend_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathend_interpolator_2.xml new file mode 100644 index 0000000..7e19ef6 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathend_interpolator_2.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.744517024668,0.120263649138 0.135947812437,0.994319475209 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathstart_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathstart_interpolator_2.xml new file mode 100644 index 0000000..1280715 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_1_trimpathstart_interpolator_2.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.781904890372,0.126303002187 0.188007240906,0.953418294755 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_1.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_1.xml new file mode 100644 index 0000000..ddf966e --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_1.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.000100000000012,0.0 0.0,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_2.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_2.xml new file mode 100644 index 0000000..624e304 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_2.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 9.99999999007e-05,0.0 0.0,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_3.xml b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_3.xml new file mode 100644 index 0000000..3ebee0b --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_open_path_1_pathdata_interpolator_3.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.000100000000051,0.0 0.83333333333,1.0 1.0,1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml new file mode 100644 index 0000000..f798a84 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_rotation_interpolator.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.4 0.0 0.2 1.0 1.0 1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml new file mode 100644 index 0000000..314cf44 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_arrows_1_scalex_interpolator.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0.0 0.0 L 1.0 1.0 " /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml new file mode 100644 index 0000000..f798a84 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_1_rotation_interpolator.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.4 0.0 0.2 1.0 1.0 1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml new file mode 100644 index 0000000..f798a84 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_rotate_2_portrait_v2_device_2_pathdata_interpolator.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.4 0.0 0.2 1.0 1.0 1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml new file mode 100644 index 0000000..4917f77 --- /dev/null +++ b/tests/VectorDrawableTest/res/interpolator/ic_signal_airplane_v2_path_1_1_pathdata_interpolator.xml @@ -0,0 +1,16 @@ +<!-- 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. +--> +<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" + android:pathData="M 0 0 c 0.16666666667 0.0 0.2 1.0 1.0 1.0" /> diff --git a/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml index b2770cd..54b5ebd 100644 --- a/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml +++ b/tests/VectorDrawableTest/res/interpolator/trim_end_interpolator.xml @@ -1,2 +1,16 @@ +<!-- 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. +--> <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:pathData="C0.2,0 0.1,1 0.5, 1 L 1,1" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml b/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml index 798f7e6..c06c196 100644 --- a/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml +++ b/tests/VectorDrawableTest/res/interpolator/trim_start_interpolator.xml @@ -1,2 +1,16 @@ +<!-- 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. +--> <pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android" android:pathData="L0.5,0 C 0.7,0 0.6,1 1, 1" />
\ No newline at end of file diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java index 05bf166..3045839 100644 --- a/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/AnimatedVectorDrawableTest.java @@ -26,6 +26,12 @@ public class AnimatedVectorDrawableTest extends Activity implements View.OnClick private static final String LOGCAT = "AnimatedVectorDrawableTest"; protected int[] icon = { + R.drawable.ic_open_animation, + R.drawable.ic_rotate_2_portrait_v2_animation, + R.drawable.ic_signal_airplane_v2_animation, + R.drawable.ic_hourglass_animation, + R.drawable.ic_cast_v2_animation, + R.drawable.ic_bluethooth_v2_animation, R.drawable.animation_vector_linear_progress_bar, R.drawable.animation_vector_drawable_grouping_1, R.drawable.animation_vector_progress_bar, diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java index 37e0435..1cd6533 100644 --- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java +++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java @@ -56,6 +56,7 @@ public class VectorDrawablePerformance extends Activity { R.drawable.vector_drawable26, R.drawable.vector_drawable27, R.drawable.vector_drawable28, + R.drawable.vector_drawable29, }; @Override diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp index 2849c84..2d35129 100644 --- a/tools/aapt/AaptAssets.cpp +++ b/tools/aapt/AaptAssets.cpp @@ -1140,9 +1140,10 @@ bail: ssize_t AaptAssets::slurpFullTree(Bundle* bundle, const String8& srcDir, const AaptGroupEntry& kind, const String8& resType, - sp<FilePathStore>& fullResPaths) + sp<FilePathStore>& fullResPaths, + const bool overwrite) { - ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths); + ssize_t res = AaptDir::slurpFullTree(bundle, srcDir, kind, resType, fullResPaths, overwrite); if (res > 0) { mGroupEntries.add(kind); } diff --git a/tools/aapt/AaptAssets.h b/tools/aapt/AaptAssets.h index d809c5b..7ae5368 100644 --- a/tools/aapt/AaptAssets.h +++ b/tools/aapt/AaptAssets.h @@ -591,7 +591,8 @@ private: const String8& srcDir, const AaptGroupEntry& kind, const String8& resType, - sp<FilePathStore>& fullResPaths); + sp<FilePathStore>& fullResPaths, + const bool overwrite=false); ssize_t slurpResourceTree(Bundle* bundle, const String8& srcDir); ssize_t slurpResourceZip(Bundle* bundle, const char* filename); diff --git a/tools/aapt/AaptConfig.cpp b/tools/aapt/AaptConfig.cpp index 32a0cd3..f447462 100644 --- a/tools/aapt/AaptConfig.cpp +++ b/tools/aapt/AaptConfig.cpp @@ -240,7 +240,9 @@ void applyVersionForCompatibility(ConfigDescription* config) { } uint16_t minSdk = 0; - if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY + if (config->density == ResTable_config::DENSITY_ANY) { + minSdk = SDK_L; + } else if (config->smallestScreenWidthDp != ResTable_config::SCREENWIDTH_ANY || config->screenWidthDp != ResTable_config::SCREENWIDTH_ANY || config->screenHeightDp != ResTable_config::SCREENHEIGHT_ANY) { minSdk = SDK_HONEYCOMB_MR2; @@ -255,8 +257,6 @@ void applyVersionForCompatibility(ConfigDescription* config) { != ResTable_config::SCREENLONG_ANY || config->density != ResTable_config::DENSITY_DEFAULT) { minSdk = SDK_DONUT; - } else if ((config->density == ResTable_config::DENSITY_ANY)) { - minSdk = SDK_L; } if (minSdk > config->sdkVersion) { diff --git a/tools/aapt/Android.mk b/tools/aapt/Android.mk index 6d3b73d..0ccf0f5 100644 --- a/tools/aapt/Android.mk +++ b/tools/aapt/Android.mk @@ -125,6 +125,7 @@ include $(BUILD_HOST_EXECUTABLE) # Build the host tests: libaapt_tests # ========================================================== include $(CLEAR_VARS) +LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk LOCAL_MODULE := libaapt_tests diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp index 70044f2..b7484a3 100644 --- a/tools/aapt/Command.cpp +++ b/tools/aapt/Command.cpp @@ -308,6 +308,7 @@ enum { PUBLIC_KEY_ATTR = 0x010103a6, CATEGORY_ATTR = 0x010103e8, BANNER_ATTR = 0x10103f2, + ISGAME_ATTR = 0x10103f4, }; String8 getComponentName(String8 &pkgName, String8 &componentName) { @@ -1125,13 +1126,35 @@ int doDump(Bundle* bundle) error.string()); goto bail; } + + String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR, &error); + if (error != "") { + fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n", + error.string()); + goto bail; + } printf("application: label='%s' ", ResTable::normalizeForOutput(label.string()).string()); - printf("icon='%s'\n", ResTable::normalizeForOutput(icon.string()).string()); + printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string()); + if (banner != "") { + printf(" banner='%s'", ResTable::normalizeForOutput(banner.string()).string()); + } + printf("\n"); if (testOnly != 0) { printf("testOnly='%d'\n", testOnly); } + int32_t isGame = AaptXml::getResolvedIntegerAttribute(res, tree, + ISGAME_ATTR, 0, &error); + if (error != "") { + fprintf(stderr, "ERROR getting 'android:isGame' attribute: %s\n", + error.string()); + goto bail; + } + if (isGame != 0) { + printf("application-isGame\n"); + } + int32_t debuggable = AaptXml::getResolvedIntegerAttribute(res, tree, DEBUGGABLE_ATTR, 0, &error); if (error != "") { diff --git a/tools/aapt/ConfigDescription.h b/tools/aapt/ConfigDescription.h index 779c423..4f999a2 100644 --- a/tools/aapt/ConfigDescription.h +++ b/tools/aapt/ConfigDescription.h @@ -28,10 +28,12 @@ struct ConfigDescription : public android::ResTable_config { memset(this, 0, sizeof(*this)); size = sizeof(android::ResTable_config); } + ConfigDescription(const android::ResTable_config&o) { *static_cast<android::ResTable_config*>(this) = o; size = sizeof(android::ResTable_config); } + ConfigDescription(const ConfigDescription&o) { *static_cast<android::ResTable_config*>(this) = o; } @@ -41,6 +43,7 @@ struct ConfigDescription : public android::ResTable_config { size = sizeof(android::ResTable_config); return *this; } + ConfigDescription& operator=(const ConfigDescription& o) { *static_cast<android::ResTable_config*>(this) = o; return *this; diff --git a/tools/aapt/ResourceIdCache.cpp b/tools/aapt/ResourceIdCache.cpp index d7b2d10..8835fb0 100644 --- a/tools/aapt/ResourceIdCache.cpp +++ b/tools/aapt/ResourceIdCache.cpp @@ -10,7 +10,6 @@ #include "ResourceIdCache.h" #include <map> - static size_t mHits = 0; static size_t mMisses = 0; static size_t mCollisions = 0; diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java index bef5181..4993262 100644 --- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java @@ -213,6 +213,10 @@ public class FontFamily_Delegate { return null; } + @Nullable + /*package*/ static String getFontLocation() { + return sFontLocation; + } // ---- native methods ---- diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java index 276e134..b9460b4 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java @@ -27,6 +27,8 @@ import java.io.File; import java.util.ArrayList; import java.util.List; +import static android.graphics.FontFamily_Delegate.getFontLocation; + /** * Delegate implementing the native methods of android.graphics.Typeface * @@ -48,8 +50,6 @@ public final class Typeface_Delegate { private static final DelegateManager<Typeface_Delegate> sManager = new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class); - // ---- delegate helper data ---- - private static String sFontLocation; // ---- delegate data ---- @@ -61,11 +61,8 @@ public final class Typeface_Delegate { private static long sDefaultTypeface; + // ---- Public Helper methods ---- - public static synchronized void setFontLocation(String fontLocation) { - sFontLocation = fontLocation; - FontFamily_Delegate.setFontLocation(fontLocation); - } public static Typeface_Delegate getDelegate(long nativeTypeface) { return sManager.getDelegate(nativeTypeface); @@ -131,6 +128,18 @@ public final class Typeface_Delegate { return fonts; } + /** + * Clear the default typefaces when disposing bridge. + */ + public static void resetDefaults() { + // Sometimes this is called before the Bridge is initialized. In that case, we don't want to + // initialize Typeface because the SDK fonts location hasn't been set. + if (FontFamily_Delegate.getFontLocation() != null) { + Typeface.sDefaults = null; + } + } + + // ---- native methods ---- @LayoutlibDelegate @@ -193,7 +202,7 @@ public final class Typeface_Delegate { @LayoutlibDelegate /*package*/ static File getSystemFontConfigLocation() { - return new File(sFontLocation); + return new File(getFontLocation()); } // ---- Private delegate/helper methods ---- diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java index 3d0e1e8..825731b 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java @@ -38,7 +38,7 @@ import com.ibm.icu.util.ULocale; import android.content.res.BridgeAssetManager; import android.graphics.Bitmap; -import android.graphics.Typeface_Accessor; +import android.graphics.FontFamily_Delegate; import android.graphics.Typeface_Delegate; import android.os.Looper; import android.os.Looper_Accessor; @@ -250,7 +250,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { } // load the fonts. - Typeface_Delegate.setFontLocation(fontLocation.getAbsolutePath()); + FontFamily_Delegate.setFontLocation(fontLocation.getAbsolutePath()); // now parse com.android.internal.R (and only this one as android.R is a subset of // the internal version), and put the content in the maps. @@ -303,7 +303,7 @@ public final class Bridge extends com.android.ide.common.rendering.api.Bridge { BridgeAssetManager.clearSystem(); // dispose of the default typeface. - Typeface_Accessor.resetDefaults(); + Typeface_Delegate.resetDefaults(); return true; } diff --git a/tools/split-select/Abi.cpp b/tools/split-select/Abi.cpp new file mode 100644 index 0000000..20654b6 --- /dev/null +++ b/tools/split-select/Abi.cpp @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#include "Abi.h" + +namespace split { +namespace abi { + +static const std::vector<Variant> sNoneVariants = {}; +static const std::vector<Variant> sArmVariants = + {Variant::armeabi, Variant::armeabi_v7a, Variant::arm64_v8a}; +static const std::vector<Variant> sIntelVariants = {Variant::x86, Variant::x86_64}; +static const std::vector<Variant> sMipsVariants = {Variant::mips, Variant::mips64}; + +Family getFamily(Variant variant) { + switch (variant) { + case Variant::none: + return Family::none; + case Variant::armeabi: + case Variant::armeabi_v7a: + case Variant::arm64_v8a: + return Family::arm; + case Variant::x86: + case Variant::x86_64: + return Family::intel; + case Variant::mips: + case Variant::mips64: + return Family::mips; + } + return Family::none; +} + +const std::vector<Variant>& getVariants(Family family) { + switch (family) { + case Family::none: + return sNoneVariants; + case Family::arm: + return sArmVariants; + case Family::intel: + return sIntelVariants; + case Family::mips: + return sMipsVariants; + } + return sNoneVariants; +} + +const char* toString(Variant variant) { + switch (variant) { + case Variant::none: + return ""; + case Variant::armeabi: + return "armeabi"; + case Variant::armeabi_v7a: + return "armeabi-v7a"; + case Variant::arm64_v8a: + return "arm64-v8a"; + case Variant::x86: + return "x86"; + case Variant::x86_64: + return "x86_64"; + case Variant::mips: + return "mips"; + case Variant::mips64: + return "mips64"; + } + return ""; +} + +} // namespace abi +} // namespace split diff --git a/tools/split-select/Abi.h b/tools/split-select/Abi.h new file mode 100644 index 0000000..3e00eba --- /dev/null +++ b/tools/split-select/Abi.h @@ -0,0 +1,50 @@ +/* + * 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. + */ + +#ifndef H_ANDROID_SPLIT_ABI +#define H_ANDROID_SPLIT_ABI + +#include <vector> + +namespace split { +namespace abi { + +enum class Variant { + none = 0, + armeabi, + armeabi_v7a, + arm64_v8a, + x86, + x86_64, + mips, + mips64, +}; + +enum class Family { + none, + arm, + intel, + mips, +}; + +Family getFamily(Variant variant); +const std::vector<Variant>& getVariants(Family family); +const char* toString(Variant variant); + +} // namespace abi +} // namespace split + +#endif // H_ANDROID_SPLIT_ABI diff --git a/tools/split-select/Android.mk b/tools/split-select/Android.mk new file mode 100644 index 0000000..d0b7287 --- /dev/null +++ b/tools/split-select/Android.mk @@ -0,0 +1,119 @@ +# +# 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. +# + +# This tool is prebuilt if we're doing an app-only build. +ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),) + +# TODO(adamlesinski): Enable OS X builds when I figure out how +# to build with clang and libc++ +ifneq ($(HOST_OS),darwin) + +# ========================================================== +# Setup some common variables for the different build +# targets here. +# ========================================================== +LOCAL_PATH:= $(call my-dir) + +main := Main.cpp +sources := \ + Abi.cpp \ + Grouper.cpp \ + Rule.cpp \ + RuleGenerator.cpp \ + SplitDescription.cpp + +testSources := \ + Grouper_test.cpp \ + Rule_test.cpp \ + RuleGenerator_test.cpp + +cIncludes := \ + external/zlib \ + frameworks/base/tools + +hostLdLibs := +hostStaticLibs := \ + libaapt \ + libandroidfw \ + libpng \ + liblog \ + libutils \ + libcutils \ + libexpat \ + libziparchive-host + +cFlags := -std=c++11 -Wall -Werror + +ifeq ($(HOST_OS),linux) + hostLdLibs += -lrt -ldl -lpthread +endif + +# Statically link libz for MinGW (Win SDK under Linux), +# and dynamically link for all others. +ifneq ($(strip $(USE_MINGW)),) + hostStaticLibs += libz +else + hostLdLibs += -lz +endif + + +# ========================================================== +# Build the host static library: libsplit-select +# ========================================================== +include $(CLEAR_VARS) +LOCAL_MODULE := libsplit-select + +LOCAL_SRC_FILES := $(sources) + +LOCAL_C_INCLUDES += $(cIncludes) +LOCAL_CFLAGS += $(cFlags) -D_DARWIN_UNLIMITED_STREAMS + +include $(BUILD_HOST_STATIC_LIBRARY) + + +# ========================================================== +# Build the host tests: libsplit-select_tests +# ========================================================== +include $(CLEAR_VARS) +LOCAL_MODULE := libsplit-select_tests +LOCAL_MODULE_TAGS := tests + +LOCAL_SRC_FILES := $(testSources) + +LOCAL_C_INCLUDES += $(cIncludes) +LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs) +LOCAL_LDLIBS += $(hostLdLibs) +LOCAL_CFLAGS += $(cFlags) + +include $(BUILD_HOST_NATIVE_TEST) + +# ========================================================== +# Build the host executable: split-select +# ========================================================== +include $(CLEAR_VARS) +LOCAL_MODULE := split-select + +LOCAL_SRC_FILES := $(main) + +LOCAL_C_INCLUDES += $(cIncludes) +LOCAL_STATIC_LIBRARIES += libsplit-select $(hostStaticLibs) +LOCAL_LDLIBS += $(hostLdLibs) +LOCAL_CFLAGS += $(cFlags) + +include $(BUILD_HOST_EXECUTABLE) + +endif # Not OS X +endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK diff --git a/tools/split-select/Grouper.cpp b/tools/split-select/Grouper.cpp new file mode 100644 index 0000000..15edf89 --- /dev/null +++ b/tools/split-select/Grouper.cpp @@ -0,0 +1,83 @@ +/* + * 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. + */ + +#include "Grouper.h" + +#include "SplitDescription.h" + +#include <utils/KeyedVector.h> +#include <utils/Vector.h> + +using namespace android; + +namespace split { + +template <typename Key, typename Value> +static void addToVector(KeyedVector<Key, SortedVector<Value> >& group, + const Key& key, const Value& value) { + ssize_t idx = group.indexOfKey(key); + if (idx < 0) { + idx = group.add(key, SortedVector<Value>()); + } + group.editValueAt(idx).add(value); +} + +Vector<SortedVector<SplitDescription> > +groupByMutualExclusivity(const Vector<SplitDescription>& splits) { + Vector<SortedVector<SplitDescription> > groups; + + // Find mutually exclusive splits and group them. + KeyedVector<SplitDescription, SortedVector<SplitDescription> > densityGroups; + KeyedVector<SplitDescription, SortedVector<SplitDescription> > abiGroups; + KeyedVector<SplitDescription, SortedVector<SplitDescription> > localeGroups; + for (const SplitDescription& split : splits) { + if (split.config.density != 0) { + SplitDescription key(split); + key.config.density = 0; + key.config.sdkVersion = 0; // Ignore density so we can support anydpi. + addToVector(densityGroups, key, split); + } else if (split.abi != abi::Variant::none) { + SplitDescription key(split); + key.abi = abi::Variant::none; + addToVector(abiGroups, key, split); + } else if (split.config.locale != 0) { + SplitDescription key(split); + key.config.clearLocale(); + addToVector(localeGroups, key, split); + } else { + groups.add(); + groups.editTop().add(split); + } + } + + const size_t densityCount = densityGroups.size(); + for (size_t i = 0; i < densityCount; i++) { + groups.add(densityGroups[i]); + } + + const size_t abiCount = abiGroups.size(); + for (size_t i = 0; i < abiCount; i++) { + groups.add(abiGroups[i]); + } + + const size_t localeCount = localeGroups.size(); + for (size_t i = 0; i < localeCount; i++) { + groups.add(localeGroups[i]); + } + return groups; +} + +} // namespace split diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Accessor.java b/tools/split-select/Grouper.h index adad2ac..5cb0b5b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Accessor.java +++ b/tools/split-select/Grouper.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 The Android Open Source Project + * 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. @@ -14,14 +14,19 @@ * limitations under the License. */ -package android.graphics; +#ifndef H_ANDROID_SPLIT_GROUPER +#define H_ANDROID_SPLIT_GROUPER -/** - * Class allowing access to package-protected methods/fields. - */ -public class Typeface_Accessor { +#include "SplitDescription.h" + +#include <utils/SortedVector.h> +#include <utils/Vector.h> + +namespace split { + +android::Vector<android::SortedVector<SplitDescription> > +groupByMutualExclusivity(const android::Vector<SplitDescription>& splits); + +} // namespace split - public static void resetDefaults() { - Typeface.sDefaults = null; - } -} +#endif // H_ANDROID_SPLIT_GROUPER diff --git a/tools/split-select/Grouper_test.cpp b/tools/split-select/Grouper_test.cpp new file mode 100644 index 0000000..4d146cd --- /dev/null +++ b/tools/split-select/Grouper_test.cpp @@ -0,0 +1,151 @@ +/* + * 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. + */ + +#include "Grouper.h" + +#include "SplitDescription.h" + +#include <gtest/gtest.h> +#include <initializer_list> +#include <utils/String8.h> +#include <utils/Vector.h> + +using namespace android; + +namespace split { + +class GrouperTest : public ::testing::Test { +protected: + virtual void SetUp() { + Vector<SplitDescription> splits; + addSplit(splits, "en-rUS-sw600dp-hdpi"); + addSplit(splits, "fr-rFR-sw600dp-hdpi"); + addSplit(splits, "fr-rFR-sw600dp-xhdpi"); + addSplit(splits, ":armeabi"); + addSplit(splits, "en-rUS-sw300dp-xhdpi"); + addSplit(splits, "large"); + addSplit(splits, "pl-rPL"); + addSplit(splits, "xlarge"); + addSplit(splits, "en-rUS-sw600dp-xhdpi"); + addSplit(splits, "en-rUS-sw300dp-hdpi"); + addSplit(splits, "xxhdpi"); + addSplit(splits, "hdpi"); + addSplit(splits, "de-rDE"); + addSplit(splits, "xhdpi"); + addSplit(splits, ":x86"); + addSplit(splits, "anydpi"); + addSplit(splits, "v7"); + addSplit(splits, "v8"); + addSplit(splits, "sw600dp"); + addSplit(splits, "sw300dp"); + mGroups = groupByMutualExclusivity(splits); + } + + void addSplit(Vector<SplitDescription>& splits, const char* str); + void expectHasGroupWithSplits(std::initializer_list<const char*> l); + + Vector<SortedVector<SplitDescription> > mGroups; +}; + +TEST_F(GrouperTest, shouldHaveCorrectNumberOfGroups) { + EXPECT_EQ(12u, mGroups.size()); +} + +TEST_F(GrouperTest, shouldGroupDensities) { + expectHasGroupWithSplits({"en-rUS-sw300dp-hdpi", "en-rUS-sw300dp-xhdpi"}); + expectHasGroupWithSplits({"en-rUS-sw600dp-hdpi", "en-rUS-sw600dp-xhdpi"}); + expectHasGroupWithSplits({"fr-rFR-sw600dp-hdpi", "fr-rFR-sw600dp-xhdpi"}); + expectHasGroupWithSplits({"hdpi", "xhdpi", "xxhdpi", "anydpi"}); +} + +TEST_F(GrouperTest, shouldGroupAbi) { + expectHasGroupWithSplits({":armeabi", ":x86"}); +} + +TEST_F(GrouperTest, shouldGroupLocale) { + expectHasGroupWithSplits({"pl-rPL", "de-rDE"}); +} + +TEST_F(GrouperTest, shouldGroupEachSplitIntoItsOwnGroup) { + expectHasGroupWithSplits({"large"}); + expectHasGroupWithSplits({"xlarge"}); + expectHasGroupWithSplits({"v7"}); + expectHasGroupWithSplits({"v8"}); + expectHasGroupWithSplits({"sw600dp"}); + expectHasGroupWithSplits({"sw300dp"}); +} + +// +// Helper methods +// + +void GrouperTest::expectHasGroupWithSplits(std::initializer_list<const char*> l) { + Vector<SplitDescription> splits; + for (const char* str : l) { + splits.add(); + if (!SplitDescription::parse(String8(str), &splits.editTop())) { + ADD_FAILURE() << "Failed to parse SplitDescription " << str; + return; + } + } + const size_t splitCount = splits.size(); + + const size_t groupCount = mGroups.size(); + for (size_t i = 0; i < groupCount; i++) { + const SortedVector<SplitDescription>& group = mGroups[i]; + if (group.size() != splitCount) { + continue; + } + + size_t found = 0; + for (size_t j = 0; j < splitCount; j++) { + if (group.indexOf(splits[j]) >= 0) { + found++; + } + } + + if (found == splitCount) { + return; + } + } + + String8 errorMessage("Failed to find expected group ["); + for (size_t i = 0; i < splitCount; i++) { + if (i != 0) { + errorMessage.append(", "); + } + errorMessage.append(splits[i].toString()); + } + errorMessage.append("].\nActual:\n"); + + for (size_t i = 0; i < groupCount; i++) { + errorMessage.appendFormat("Group %d:\n", int(i + 1)); + const SortedVector<SplitDescription>& group = mGroups[i]; + for (size_t j = 0; j < group.size(); j++) { + errorMessage.append(" "); + errorMessage.append(group[j].toString()); + errorMessage.append("\n"); + } + } + ADD_FAILURE() << errorMessage.string(); +} + +void GrouperTest::addSplit(Vector<SplitDescription>& splits, const char* str) { + splits.add(); + EXPECT_TRUE(SplitDescription::parse(String8(str), &splits.editTop())); +} + +} // namespace split diff --git a/tools/split-select/Main.cpp b/tools/split-select/Main.cpp new file mode 100644 index 0000000..d6251c3 --- /dev/null +++ b/tools/split-select/Main.cpp @@ -0,0 +1,314 @@ +/* + * 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. + */ + +#include <algorithm> +#include <cstdio> + +#include "aapt/AaptUtil.h" + +#include "Grouper.h" +#include "Rule.h" +#include "RuleGenerator.h" +#include "SplitDescription.h" + +#include <androidfw/AssetManager.h> +#include <androidfw/ResourceTypes.h> +#include <utils/KeyedVector.h> +#include <utils/Vector.h> + +using namespace android; + +namespace split { + +static void usage() { + fprintf(stderr, + "split-select --help\n" + "split-select --target <config> --split <path/to/apk> [--split <path/to/apk> [...]]\n" + "split-select --generate --split <path/to/apk> [--split <path/to/apk> [...]]\n" + "\n" + " --help Displays more information about this program.\n" + " --target <config> Performs the Split APK selection on the given configuration.\n" + " --generate Generates the logic for selecting the Split APK, in JSON format.\n" + " --split <path/to/apk> Includes a Split APK in the selection process.\n" + "\n" + " Where <config> is an extended AAPT resource qualifier of the form\n" + " 'resource-qualifiers:extended-qualifiers', where 'resource-qualifiers' is an AAPT resource\n" + " qualifier (ex: en-rUS-sw600dp-xhdpi), and 'extended-qualifiers' is an ordered list of one\n" + " qualifier (or none) from each category:\n" + " Architecture: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips\n"); +} + +static void help() { + usage(); + fprintf(stderr, "\n" + " Generates the logic for selecting a Split APK given some target Android device configuration.\n" + " Using the flag --generate will emit a JSON encoded tree of rules that must be satisfied in order\n" + " to install the given Split APK. Using the flag --target along with the device configuration\n" + " will emit the set of Split APKs to install, following the same logic that would have been emitted\n" + " via JSON.\n"); +} + +class SplitSelector { +public: + SplitSelector() = default; + SplitSelector(const Vector<SplitDescription>& splits); + + Vector<SplitDescription> getBestSplits(const SplitDescription& target) const; + + template <typename RuleGenerator> + KeyedVector<SplitDescription, sp<Rule> > getRules() const; + +private: + Vector<SortedVector<SplitDescription> > mGroups; +}; + +SplitSelector::SplitSelector(const Vector<SplitDescription>& splits) + : mGroups(groupByMutualExclusivity(splits)) { +} + +static void selectBestFromGroup(const SortedVector<SplitDescription>& splits, + const SplitDescription& target, Vector<SplitDescription>& splitsOut) { + SplitDescription bestSplit; + bool isSet = false; + const size_t splitCount = splits.size(); + for (size_t j = 0; j < splitCount; j++) { + const SplitDescription& thisSplit = splits[j]; + if (!thisSplit.match(target)) { + continue; + } + + if (!isSet || thisSplit.isBetterThan(bestSplit, target)) { + isSet = true; + bestSplit = thisSplit; + } + } + + if (isSet) { + splitsOut.add(bestSplit); + } +} + +Vector<SplitDescription> SplitSelector::getBestSplits(const SplitDescription& target) const { + Vector<SplitDescription> bestSplits; + const size_t groupCount = mGroups.size(); + for (size_t i = 0; i < groupCount; i++) { + selectBestFromGroup(mGroups[i], target, bestSplits); + } + return bestSplits; +} + +template <typename RuleGenerator> +KeyedVector<SplitDescription, sp<Rule> > SplitSelector::getRules() const { + KeyedVector<SplitDescription, sp<Rule> > rules; + + const size_t groupCount = mGroups.size(); + for (size_t i = 0; i < groupCount; i++) { + const SortedVector<SplitDescription>& splits = mGroups[i]; + const size_t splitCount = splits.size(); + for (size_t j = 0; j < splitCount; j++) { + sp<Rule> rule = Rule::simplify(RuleGenerator::generate(splits, j)); + if (rule != NULL) { + rules.add(splits[j], rule); + } + } + } + return rules; +} + +Vector<SplitDescription> select(const SplitDescription& target, const Vector<SplitDescription>& splits) { + const SplitSelector selector(splits); + return selector.getBestSplits(target); +} + +void generate(const KeyedVector<String8, Vector<SplitDescription> >& splits) { + Vector<SplitDescription> allSplits; + const size_t apkSplitCount = splits.size(); + for (size_t i = 0; i < apkSplitCount; i++) { + allSplits.appendVector(splits[i]); + } + const SplitSelector selector(allSplits); + KeyedVector<SplitDescription, sp<Rule> > rules(selector.getRules<RuleGenerator>()); + + fprintf(stdout, "[\n"); + for (size_t i = 0; i < apkSplitCount; i++) { + sp<Rule> masterRule = new Rule(); + masterRule->op = Rule::OR_SUBRULES; + const Vector<SplitDescription>& splitDescriptions = splits[i]; + const size_t splitDescriptionCount = splitDescriptions.size(); + for (size_t j = 0; j < splitDescriptionCount; j++) { + masterRule->subrules.add(rules.valueFor(splitDescriptions[j])); + } + masterRule = Rule::simplify(masterRule); + fprintf(stdout, " {\n \"path\": \"%s\",\n \"rules\": %s\n }%s\n", + splits.keyAt(i).string(), + masterRule->toJson(2).string(), + i < apkSplitCount - 1 ? "," : ""); + } + fprintf(stdout, "]\n"); +} + +static void removeRuntimeQualifiers(ConfigDescription* outConfig) { + outConfig->imsi = 0; + outConfig->orientation = ResTable_config::ORIENTATION_ANY; + outConfig->screenWidth = ResTable_config::SCREENWIDTH_ANY; + outConfig->screenHeight = ResTable_config::SCREENHEIGHT_ANY; + outConfig->uiMode &= ResTable_config::UI_MODE_NIGHT_ANY; +} + +static Vector<SplitDescription> extractSplitDescriptionsFromApk(const String8& path) { + AssetManager assetManager; + Vector<SplitDescription> splits; + int32_t cookie = 0; + if (!assetManager.addAssetPath(path, &cookie)) { + return splits; + } + + const ResTable& res = assetManager.getResources(false); + if (res.getError() == NO_ERROR) { + Vector<ResTable_config> configs; + res.getConfigurations(&configs); + const size_t configCount = configs.size(); + for (size_t i = 0; i < configCount; i++) { + splits.add(); + splits.editTop().config = configs[i]; + } + } + + AssetDir* dir = assetManager.openNonAssetDir(cookie, "lib"); + if (dir != NULL) { + const size_t fileCount = dir->getFileCount(); + for (size_t i = 0; i < fileCount; i++) { + splits.add(); + Vector<String8> parts = AaptUtil::splitAndLowerCase(dir->getFileName(i), '-'); + if (parseAbi(parts, 0, &splits.editTop()) < 0) { + fprintf(stderr, "Malformed library %s\n", dir->getFileName(i).string()); + splits.pop(); + } + } + delete dir; + } + return splits; +} + +static int main(int argc, char** argv) { + // Skip over the first argument. + argc--; + argv++; + + bool generateFlag = false; + String8 targetConfigStr; + Vector<String8> splitApkPaths; + while (argc > 0) { + const String8 arg(*argv); + if (arg == "--target") { + argc--; + argv++; + if (argc < 1) { + fprintf(stderr, "Missing parameter for --split.\n"); + usage(); + return 1; + } + targetConfigStr.setTo(*argv); + } else if (arg == "--split") { + argc--; + argv++; + if (argc < 1) { + fprintf(stderr, "Missing parameter for --split.\n"); + usage(); + return 1; + } + splitApkPaths.add(String8(*argv)); + } else if (arg == "--generate") { + generateFlag = true; + } else if (arg == "--help") { + help(); + return 0; + } else { + fprintf(stderr, "Unknown argument '%s'\n", arg.string()); + usage(); + return 1; + } + argc--; + argv++; + } + + if (!generateFlag && targetConfigStr == "") { + usage(); + return 1; + } + + if (splitApkPaths.size() == 0) { + usage(); + return 1; + } + + SplitDescription targetSplit; + if (!generateFlag) { + if (!SplitDescription::parse(targetConfigStr, &targetSplit)) { + fprintf(stderr, "Invalid --target config: '%s'\n", + targetConfigStr.string()); + usage(); + return 1; + } + + // We don't want to match on things that will change at run-time + // (orientation, w/h, etc.). + removeRuntimeQualifiers(&targetSplit.config); + } + + KeyedVector<String8, Vector<SplitDescription> > apkPathSplitMap; + KeyedVector<SplitDescription, String8> splitApkPathMap; + Vector<SplitDescription> splitConfigs; + const size_t splitCount = splitApkPaths.size(); + for (size_t i = 0; i < splitCount; i++) { + Vector<SplitDescription> splits = extractSplitDescriptionsFromApk(splitApkPaths[i]); + if (splits.isEmpty()) { + fprintf(stderr, "Invalid --split path: '%s'. No splits found.\n", + splitApkPaths[i].string()); + usage(); + return 1; + } + apkPathSplitMap.replaceValueFor(splitApkPaths[i], splits); + const size_t apkSplitDescriptionCount = splits.size(); + for (size_t j = 0; j < apkSplitDescriptionCount; j++) { + splitApkPathMap.replaceValueFor(splits[j], splitApkPaths[i]); + } + splitConfigs.appendVector(splits); + } + + if (!generateFlag) { + Vector<SplitDescription> matchingConfigs = select(targetSplit, splitConfigs); + const size_t matchingConfigCount = matchingConfigs.size(); + SortedVector<String8> matchingSplitPaths; + for (size_t i = 0; i < matchingConfigCount; i++) { + matchingSplitPaths.add(splitApkPathMap.valueFor(matchingConfigs[i])); + } + + const size_t matchingSplitApkPathCount = matchingSplitPaths.size(); + for (size_t i = 0; i < matchingSplitApkPathCount; i++) { + fprintf(stderr, "%s\n", matchingSplitPaths[i].string()); + } + } else { + generate(apkPathSplitMap); + } + return 0; +} + +} // namespace split + +int main(int argc, char** argv) { + return split::main(argc, argv); +} diff --git a/tools/split-select/Rule.cpp b/tools/split-select/Rule.cpp new file mode 100644 index 0000000..9559fe2 --- /dev/null +++ b/tools/split-select/Rule.cpp @@ -0,0 +1,196 @@ +/* + * 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. + */ + +#include "Rule.h" + +#include <utils/String8.h> + +using namespace android; + +namespace split { + +inline static void indentStr(String8& str, int indent) { + while (indent > 0) { + str.append(" "); + indent--; + } +} + +String8 Rule::toJson(int indent) const { + String8 str; + indentStr(str, indent); + str.append("{\n"); + indent++; + indentStr(str, indent); + str.append("\"op\": \""); + switch (op) { + case ALWAYS_TRUE: + str.append("ALWAYS_TRUE"); + break; + case GREATER_THAN: + str.append("GREATER_THAN"); + break; + case LESS_THAN: + str.append("LESS_THAN"); + break; + case EQUALS: + str.append("EQUALS"); + break; + case AND_SUBRULES: + str.append("AND_SUBRULES"); + break; + case OR_SUBRULES: + str.append("OR_SUBRULES"); + break; + case CONTAINS_ANY: + str.append("CONTAINS_ANY"); + break; + default: + str.appendFormat("%d", op); + break; + } + str.append("\""); + + if (negate) { + str.append(",\n"); + indentStr(str, indent); + str.append("\"negate\": true"); + } + + bool includeKey = true; + switch (op) { + case AND_SUBRULES: + case OR_SUBRULES: + includeKey = false; + break; + default: + break; + } + + if (includeKey) { + str.append(",\n"); + indentStr(str, indent); + str.append("\"property\": \""); + switch (key) { + case NONE: + str.append("NONE"); + break; + case SDK_VERSION: + str.append("SDK_VERSION"); + break; + case SCREEN_DENSITY: + str.append("SCREEN_DENSITY"); + break; + case NATIVE_PLATFORM: + str.append("NATIVE_PLATFORM"); + break; + case LANGUAGE: + str.append("LANGUAGE"); + break; + default: + str.appendFormat("%d", key); + break; + } + str.append("\""); + } + + if (op == AND_SUBRULES || op == OR_SUBRULES) { + str.append(",\n"); + indentStr(str, indent); + str.append("\"subrules\": [\n"); + const size_t subruleCount = subrules.size(); + for (size_t i = 0; i < subruleCount; i++) { + str.append(subrules[i]->toJson(indent + 1)); + if (i != subruleCount - 1) { + str.append(","); + } + str.append("\n"); + } + indentStr(str, indent); + str.append("]"); + } else { + switch (key) { + case SDK_VERSION: + case SCREEN_DENSITY: { + str.append(",\n"); + indentStr(str, indent); + str.append("\"args\": ["); + const size_t argCount = longArgs.size(); + for (size_t i = 0; i < argCount; i++) { + if (i != 0) { + str.append(", "); + } + str.appendFormat("%d", longArgs[i]); + } + str.append("]"); + break; + } + case LANGUAGE: + case NATIVE_PLATFORM: { + str.append(",\n"); + indentStr(str, indent); + str.append("\"args\": ["); + const size_t argCount = stringArgs.size(); + for (size_t i = 0; i < argCount; i++) { + if (i != 0) { + str.append(", "); + } + str.append(stringArgs[i]); + } + str.append("]"); + break; + } + default: + break; + } + } + str.append("\n"); + indent--; + indentStr(str, indent); + str.append("}"); + return str; +} + +sp<Rule> Rule::simplify(sp<Rule> rule) { + if (rule->op != AND_SUBRULES && rule->op != OR_SUBRULES) { + return rule; + } + + Vector<sp<Rule> > newSubrules; + newSubrules.setCapacity(rule->subrules.size()); + const size_t subruleCount = rule->subrules.size(); + for (size_t i = 0; i < subruleCount; i++) { + sp<Rule> simplifiedRule = simplify(rule->subrules.editItemAt(i)); + if (simplifiedRule != NULL) { + if (simplifiedRule->op == rule->op) { + newSubrules.appendVector(simplifiedRule->subrules); + } else { + newSubrules.add(simplifiedRule); + } + } + } + + const size_t newSubruleCount = newSubrules.size(); + if (newSubruleCount == 0) { + return NULL; + } else if (subruleCount == 1) { + return newSubrules.editTop(); + } + rule->subrules = newSubrules; + return rule; +} + +} // namespace split diff --git a/tools/split-select/Rule.h b/tools/split-select/Rule.h new file mode 100644 index 0000000..8029931 --- /dev/null +++ b/tools/split-select/Rule.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + +#ifndef H_ANDROID_SPLIT_RULE +#define H_ANDROID_SPLIT_RULE + +#include "SplitDescription.h" + +#include <utils/RefBase.h> +#include <utils/StrongPointer.h> +#include <utils/String8.h> +#include <utils/Vector.h> + +namespace split { + +struct Rule : public virtual android::RefBase { + inline Rule(); + + enum Operator { + LESS_THAN = 1, + GREATER_THAN, + EQUALS, + CONTAINS_ANY, + CONTAINS_ALL, + IS_TRUE, + IS_FALSE, + AND_SUBRULES, + OR_SUBRULES, + ALWAYS_TRUE, + }; + + Operator op; + + enum Key { + NONE = 0, + SDK_VERSION, + SCREEN_DENSITY, + LANGUAGE, + NATIVE_PLATFORM, + TOUCH_SCREEN, + SCREEN_SIZE, + SCREEN_LAYOUT, + }; + + Key key; + bool negate; + + android::Vector<android::String8> stringArgs; + android::Vector<int> longArgs; + android::Vector<double> doubleArgs; + android::Vector<android::sp<Rule> > subrules; + + android::String8 toJson(int indent=0) const; + + static android::sp<Rule> simplify(android::sp<Rule> rule); +}; + +Rule::Rule() +: op(ALWAYS_TRUE) +, key(NONE) +, negate(false) {} + +} // namespace split + +#endif // H_ANDROID_SPLIT_RULE diff --git a/tools/split-select/RuleGenerator.cpp b/tools/split-select/RuleGenerator.cpp new file mode 100644 index 0000000..669ae78 --- /dev/null +++ b/tools/split-select/RuleGenerator.cpp @@ -0,0 +1,153 @@ +/* + * 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. + */ + +#include "RuleGenerator.h" + +#include <algorithm> +#include <cmath> +#include <vector> +#include <androidfw/ResourceTypes.h> + +using namespace android; + +namespace split { + +// Calculate the point at which the density selection changes between l and h. +static inline int findMid(int l, int h) { + double root = sqrt((h*h) + (8*l*h)); + return (double(-h) + root) / 2.0; +} + +sp<Rule> RuleGenerator::generateDensity(const Vector<int>& allDensities, size_t index) { + sp<Rule> densityRule = new Rule(); + densityRule->op = Rule::AND_SUBRULES; + + const bool anyDensity = allDensities[index] == ResTable_config::DENSITY_ANY; + sp<Rule> any = new Rule(); + any->op = Rule::EQUALS; + any->key = Rule::SCREEN_DENSITY; + any->longArgs.add((int)ResTable_config::DENSITY_ANY); + any->negate = !anyDensity; + densityRule->subrules.add(any); + + if (!anyDensity) { + if (index > 0) { + sp<Rule> gt = new Rule(); + gt->op = Rule::GREATER_THAN; + gt->key = Rule::SCREEN_DENSITY; + gt->longArgs.add(findMid(allDensities[index - 1], allDensities[index]) - 1); + densityRule->subrules.add(gt); + } + + if (index + 1 < allDensities.size() && allDensities[index + 1] != ResTable_config::DENSITY_ANY) { + sp<Rule> lt = new Rule(); + lt->op = Rule::LESS_THAN; + lt->key = Rule::SCREEN_DENSITY; + lt->longArgs.add(findMid(allDensities[index], allDensities[index + 1])); + densityRule->subrules.add(lt); + } + } + return densityRule; +} + +sp<Rule> RuleGenerator::generateAbi(const Vector<abi::Variant>& splitAbis, size_t index) { + const abi::Variant thisAbi = splitAbis[index]; + const std::vector<abi::Variant>& familyVariants = abi::getVariants(abi::getFamily(thisAbi)); + + std::vector<abi::Variant>::const_iterator start = + std::find(familyVariants.begin(), familyVariants.end(), thisAbi); + + std::vector<abi::Variant>::const_iterator end = familyVariants.end(); + if (index + 1 < splitAbis.size()) { + end = std::find(start, familyVariants.end(), splitAbis[index + 1]); + } + + sp<Rule> abiRule = new Rule(); + abiRule->op = Rule::CONTAINS_ANY; + abiRule->key = Rule::NATIVE_PLATFORM; + while (start != end) { + abiRule->stringArgs.add(String8(abi::toString(*start))); + ++start; + } + return abiRule; +} + +sp<Rule> RuleGenerator::generate(const SortedVector<SplitDescription>& group, size_t index) { + sp<Rule> rootRule = new Rule(); + rootRule->op = Rule::AND_SUBRULES; + + if (group[index].config.locale != 0) { + sp<Rule> locale = new Rule(); + locale->op = Rule::EQUALS; + locale->key = Rule::LANGUAGE; + char str[RESTABLE_MAX_LOCALE_LEN]; + group[index].config.getBcp47Locale(str); + locale->stringArgs.add(String8(str)); + rootRule->subrules.add(locale); + } + + if (group[index].config.sdkVersion != 0) { + sp<Rule> sdk = new Rule(); + sdk->op = Rule::GREATER_THAN; + sdk->key = Rule::SDK_VERSION; + sdk->longArgs.add(group[index].config.sdkVersion - 1); + rootRule->subrules.add(sdk); + } + + if (group[index].config.density != 0) { + size_t densityIndex = 0; + Vector<int> allDensities; + allDensities.add(group[index].config.density); + + const size_t groupSize = group.size(); + for (size_t i = 0; i < groupSize; i++) { + if (group[i].config.density != group[index].config.density) { + // This group differs by density. + allDensities.clear(); + for (size_t j = 0; j < groupSize; j++) { + allDensities.add(group[j].config.density); + } + densityIndex = index; + break; + } + } + rootRule->subrules.add(generateDensity(allDensities, densityIndex)); + } + + if (group[index].abi != abi::Variant::none) { + size_t abiIndex = 0; + Vector<abi::Variant> allVariants; + allVariants.add(group[index].abi); + + const size_t groupSize = group.size(); + for (size_t i = 0; i < groupSize; i++) { + if (group[i].abi != group[index].abi) { + // This group differs by ABI. + allVariants.clear(); + for (size_t j = 0; j < groupSize; j++) { + allVariants.add(group[j].abi); + } + abiIndex = index; + break; + } + } + rootRule->subrules.add(generateAbi(allVariants, abiIndex)); + } + + return rootRule; +} + +} // namespace split diff --git a/tools/split-select/RuleGenerator.h b/tools/split-select/RuleGenerator.h new file mode 100644 index 0000000..619acd9 --- /dev/null +++ b/tools/split-select/RuleGenerator.h @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#ifndef H_ANDROID_SPLIT_RULE_GENERATOR +#define H_ANDROID_SPLIT_RULE_GENERATOR + +#include "Abi.h" +#include "Rule.h" +#include "SplitDescription.h" + +#include <utils/SortedVector.h> +#include <utils/Vector.h> + +namespace split { + +struct RuleGenerator { + // Generate rules for a Split given the group of mutually exclusive splits it belongs to + static android::sp<Rule> generate(const android::SortedVector<SplitDescription>& group, size_t index); + + static android::sp<Rule> generateAbi(const android::Vector<abi::Variant>& allVariants, size_t index); + static android::sp<Rule> generateDensity(const android::Vector<int>& allDensities, size_t index); +}; + +} // namespace split + +#endif // H_ANDROID_SPLIT_RULE_GENERATOR diff --git a/tools/split-select/RuleGenerator_test.cpp b/tools/split-select/RuleGenerator_test.cpp new file mode 100644 index 0000000..60baabe --- /dev/null +++ b/tools/split-select/RuleGenerator_test.cpp @@ -0,0 +1,155 @@ +/* + * 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. + */ + +#include "RuleGenerator.h" + +#include <algorithm> +#include <gtest/gtest.h> +#include <utils/String8.h> + +using namespace android; + +namespace split { + +static void expectDensityRule(const Vector<int>& densities, int density, int greaterThan, int lessThan); +static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, + std::initializer_list<const char*> matches); + +TEST(RuleGeneratorTest, testAbiRules) { + Vector<abi::Variant> abis; + abis.add(abi::Variant::armeabi); + abis.add(abi::Variant::armeabi_v7a); + abis.add(abi::Variant::x86); + std::sort(abis.begin(), abis.end()); + + expectAbiRule(abis, abi::Variant::armeabi, {"armeabi"}); + expectAbiRule(abis, abi::Variant::armeabi_v7a, {"armeabi-v7a", "arm64-v8a"}); + expectAbiRule(abis, abi::Variant::x86, {"x86", "x86_64"}); +} + +TEST(RuleGeneratorTest, testDensityRules) { + Vector<int> densities; + densities.add(ConfigDescription::DENSITY_HIGH); + densities.add(ConfigDescription::DENSITY_XHIGH); + densities.add(ConfigDescription::DENSITY_XXHIGH); + densities.add(ConfigDescription::DENSITY_ANY); + + ASSERT_LT(263, ConfigDescription::DENSITY_XHIGH); + ASSERT_GT(262, ConfigDescription::DENSITY_HIGH); + ASSERT_LT(363, ConfigDescription::DENSITY_XXHIGH); + ASSERT_GT(362, ConfigDescription::DENSITY_XHIGH); + + expectDensityRule(densities, ConfigDescription::DENSITY_HIGH, 0, 263); + expectDensityRule(densities, ConfigDescription::DENSITY_XHIGH, 262, 363); + expectDensityRule(densities, ConfigDescription::DENSITY_XXHIGH, 362, 0); + expectDensityRule(densities, ConfigDescription::DENSITY_ANY, 0, 0); +} + +// +// Helper methods. +// + +static void expectDensityRule(const Vector<int>& densities, int density, int greaterThan, int lessThan) { + const int* iter = std::find(densities.begin(), densities.end(), density); + if (densities.end() == iter) { + ADD_FAILURE() << density << "dpi was not in the density list."; + return; + } + + sp<Rule> rule = RuleGenerator::generateDensity(densities, iter - densities.begin()); + if (rule->op != Rule::AND_SUBRULES) { + ADD_FAILURE() << "Op in rule for " << density << "dpi is not Rule::AND_SUBRULES."; + return; + } + + size_t index = 0; + + bool isAnyDpi = density == ConfigDescription::DENSITY_ANY; + + sp<Rule> anyDpiRule = rule->subrules[index++]; + EXPECT_EQ(Rule::EQUALS, anyDpiRule->op) + << "for " << density << "dpi ANY DPI rule"; + EXPECT_EQ(Rule::SCREEN_DENSITY, anyDpiRule->key) + << "for " << density << "dpi ANY DPI rule"; + EXPECT_EQ(isAnyDpi == false, anyDpiRule->negate) + << "for " << density << "dpi ANY DPI rule"; + if (anyDpiRule->longArgs.size() == 1) { + EXPECT_EQ(ConfigDescription::DENSITY_ANY, anyDpiRule->longArgs[0]) + << "for " << density << "dpi ANY DPI rule"; + } else { + EXPECT_EQ(1u, anyDpiRule->longArgs.size()) + << "for " << density << "dpi ANY DPI rule"; + } + + + if (greaterThan != 0) { + sp<Rule> greaterThanRule = rule->subrules[index++]; + EXPECT_EQ(Rule::GREATER_THAN, greaterThanRule->op) + << "for " << density << "dpi GREATER_THAN rule"; + EXPECT_EQ(Rule::SCREEN_DENSITY, greaterThanRule->key) + << "for " << density << "dpi GREATER_THAN rule"; + if (greaterThanRule->longArgs.size() == 1) { + EXPECT_EQ(greaterThan, greaterThanRule->longArgs[0]) + << "for " << density << "dpi GREATER_THAN rule"; + } else { + EXPECT_EQ(1u, greaterThanRule->longArgs.size()) + << "for " << density << "dpi GREATER_THAN rule"; + } + } + + if (lessThan != 0) { + sp<Rule> lessThanRule = rule->subrules[index++]; + EXPECT_EQ(Rule::LESS_THAN, lessThanRule->op) + << "for " << density << "dpi LESS_THAN rule"; + EXPECT_EQ(Rule::SCREEN_DENSITY, lessThanRule->key) + << "for " << density << "dpi LESS_THAN rule"; + if (lessThanRule->longArgs.size() == 1) { + EXPECT_EQ(lessThan, lessThanRule->longArgs[0]) + << "for " << density << "dpi LESS_THAN rule"; + } else { + EXPECT_EQ(1u, lessThanRule->longArgs.size()) + << "for " << density << "dpi LESS_THAN rule"; + } + } +} + +static void expectAbiRule(const Vector<abi::Variant>& abis, abi::Variant variant, + std::initializer_list<const char*> matches) { + const abi::Variant* iter = std::find(abis.begin(), abis.end(), variant); + if (abis.end() == iter) { + ADD_FAILURE() << abi::toString(variant) << " was not in the abi list."; + return; + } + + sp<Rule> rule = RuleGenerator::generateAbi(abis, iter - abis.begin()); + + EXPECT_EQ(Rule::CONTAINS_ANY, rule->op) + << "for " << abi::toString(variant) << " rule"; + EXPECT_EQ(Rule::NATIVE_PLATFORM, rule->key) + << " for " << abi::toString(variant) << " rule"; + EXPECT_EQ(matches.size(), rule->stringArgs.size()) + << " for " << abi::toString(variant) << " rule"; + + for (const char* match : matches) { + if (rule->stringArgs.end() == + std::find(rule->stringArgs.begin(), rule->stringArgs.end(), String8(match))) { + ADD_FAILURE() << "Rule for abi " << abi::toString(variant) + << " does not contain match for expected abi " << match; + } + } +} + +} // namespace split diff --git a/tools/split-select/Rule_test.cpp b/tools/split-select/Rule_test.cpp new file mode 100644 index 0000000..aca7433 --- /dev/null +++ b/tools/split-select/Rule_test.cpp @@ -0,0 +1,147 @@ +/* + * 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. + */ + +#include "Rule.h" + +#include "SplitDescription.h" + +#include <algorithm> +#include <string> +#include <gtest/gtest.h> +#include <utils/String8.h> + +using namespace android; + +namespace split { + +TEST(RuleTest, generatesValidJson) { + sp<Rule> rule = new Rule(); + rule->op = Rule::AND_SUBRULES; + + sp<Rule> subrule = new Rule(); + subrule->op = Rule::EQUALS; + subrule->key = Rule::SDK_VERSION; + subrule->longArgs.add(7); + rule->subrules.add(subrule); + + subrule = new Rule(); + subrule->op = Rule::OR_SUBRULES; + rule->subrules.add(subrule); + + sp<Rule> subsubrule = new Rule(); + subsubrule->op = Rule::GREATER_THAN; + subsubrule->key = Rule::SCREEN_DENSITY; + subsubrule->longArgs.add(10); + subrule->subrules.add(subsubrule); + + subsubrule = new Rule(); + subsubrule->op = Rule::LESS_THAN; + subsubrule->key = Rule::SCREEN_DENSITY; + subsubrule->longArgs.add(5); + subrule->subrules.add(subsubrule); + + std::string expected( + "{" + " \"op\": \"AND_SUBRULES\"," + " \"subrules\": [" + " {" + " \"op\": \"EQUALS\"," + " \"property\": \"SDK_VERSION\"," + " \"args\": [7]" + " }," + " {" + " \"op\": \"OR_SUBRULES\"," + " \"subrules\": [" + " {" + " \"op\": \"GREATER_THAN\"," + " \"property\": \"SCREEN_DENSITY\"," + " \"args\": [10]" + " }," + " {" + " \"op\": \"LESS_THAN\"," + " \"property\": \"SCREEN_DENSITY\"," + " \"args\": [5]" + " }" + " ]" + " }" + " ]" + "}"); + // Trim + expected.erase(std::remove_if(expected.begin(), expected.end(), ::isspace), expected.end()); + + std::string result(rule->toJson().string()); + + // Trim + result.erase(std::remove_if(result.begin(), result.end(), ::isspace), result.end()); + + ASSERT_EQ(expected, result); +} + +TEST(RuleTest, simplifiesSingleSubruleRules) { + sp<Rule> rule = new Rule(); + rule->op = Rule::AND_SUBRULES; + + sp<Rule> subrule = new Rule(); + subrule->op = Rule::EQUALS; + subrule->key = Rule::SDK_VERSION; + subrule->longArgs.add(7); + rule->subrules.add(subrule); + + sp<Rule> simplified = Rule::simplify(rule); + EXPECT_EQ(Rule::EQUALS, simplified->op); + EXPECT_EQ(Rule::SDK_VERSION, simplified->key); + ASSERT_EQ(1u, simplified->longArgs.size()); + EXPECT_EQ(7, simplified->longArgs[0]); +} + +TEST(RuleTest, simplifiesNestedSameOpSubrules) { + sp<Rule> rule = new Rule(); + rule->op = Rule::AND_SUBRULES; + + sp<Rule> subrule = new Rule(); + subrule->op = Rule::AND_SUBRULES; + rule->subrules.add(subrule); + + sp<Rule> subsubrule = new Rule(); + subsubrule->op = Rule::EQUALS; + subsubrule->key = Rule::SDK_VERSION; + subsubrule->longArgs.add(7); + subrule->subrules.add(subsubrule); + + subrule = new Rule(); + subrule->op = Rule::EQUALS; + subrule->key = Rule::SDK_VERSION; + subrule->longArgs.add(8); + rule->subrules.add(subrule); + + sp<Rule> simplified = Rule::simplify(rule); + EXPECT_EQ(Rule::AND_SUBRULES, simplified->op); + ASSERT_EQ(2u, simplified->subrules.size()); + + sp<Rule> simplifiedSubrule = simplified->subrules[0]; + EXPECT_EQ(Rule::EQUALS, simplifiedSubrule->op); + EXPECT_EQ(Rule::SDK_VERSION, simplifiedSubrule->key); + ASSERT_EQ(1u, simplifiedSubrule->longArgs.size()); + EXPECT_EQ(7, simplifiedSubrule->longArgs[0]); + + simplifiedSubrule = simplified->subrules[1]; + EXPECT_EQ(Rule::EQUALS, simplifiedSubrule->op); + EXPECT_EQ(Rule::SDK_VERSION, simplifiedSubrule->key); + ASSERT_EQ(1u, simplifiedSubrule->longArgs.size()); + EXPECT_EQ(8, simplifiedSubrule->longArgs[0]); +} + +} // namespace split diff --git a/tools/split-select/SplitDescription.cpp b/tools/split-select/SplitDescription.cpp new file mode 100644 index 0000000..8037ef0 --- /dev/null +++ b/tools/split-select/SplitDescription.cpp @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "SplitDescription.h" + +#include "aapt/AaptConfig.h" +#include "aapt/AaptUtil.h" + +#include <utils/String8.h> +#include <utils/Vector.h> + +using namespace android; + +namespace split { + +SplitDescription::SplitDescription() +: abi(abi::Variant::none) { +} + +int SplitDescription::compare(const SplitDescription& rhs) const { + int cmp; + cmp = (int)abi - (int)rhs.abi; + if (cmp != 0) return cmp; + return config.compareLogical(rhs.config); +} + +bool SplitDescription::isBetterThan(const SplitDescription& o, const SplitDescription& target) const { + if (abi != abi::Variant::none || o.abi != abi::Variant::none) { + abi::Family family = abi::getFamily(abi); + abi::Family oFamily = abi::getFamily(o.abi); + if (family != oFamily) { + return family != abi::Family::none; + } + + if (int(target.abi) - int(abi) < int(target.abi) - int(o.abi)) { + return true; + } + } + return config.isBetterThan(o.config, &target.config); +} + +bool SplitDescription::match(const SplitDescription& o) const { + if (abi != abi::Variant::none) { + abi::Family family = abi::getFamily(abi); + abi::Family oFamily = abi::getFamily(o.abi); + if (family != oFamily) { + return false; + } + + if (int(abi) > int(o.abi)) { + return false; + } + } + return config.match(o.config); +} + +String8 SplitDescription::toString() const { + String8 extension; + if (abi != abi::Variant::none) { + if (extension.isEmpty()) { + extension.append(":"); + } else { + extension.append("-"); + } + extension.append(abi::toString(abi)); + } + String8 str(config.toString()); + str.append(extension); + return str; +} + +ssize_t parseAbi(const Vector<String8>& parts, const ssize_t index, + SplitDescription* outSplit) { + const ssize_t N = parts.size(); + abi::Variant abi = abi::Variant::none; + ssize_t endIndex = index; + if (parts[endIndex] == "arm64") { + endIndex++; + if (endIndex < N) { + if (parts[endIndex] == "v8a") { + endIndex++; + abi = abi::Variant::arm64_v8a; + } + } + } else if (parts[endIndex] == "armeabi") { + endIndex++; + abi = abi::Variant::armeabi; + if (endIndex < N) { + if (parts[endIndex] == "v7a") { + endIndex++; + abi = abi::Variant::armeabi_v7a; + } + } + } else if (parts[endIndex] == "x86") { + endIndex++; + abi = abi::Variant::x86; + } else if (parts[endIndex] == "x86_64") { + endIndex++; + abi = abi::Variant::x86_64; + } else if (parts[endIndex] == "mips") { + endIndex++; + abi = abi::Variant::mips; + } else if (parts[endIndex] == "mips64") { + endIndex++; + abi = abi::Variant::mips64; + } + + if (abi == abi::Variant::none && endIndex != index) { + return -1; + } + + if (outSplit != NULL) { + outSplit->abi = abi; + } + return endIndex; +} + +bool SplitDescription::parse(const String8& str, SplitDescription* outSplit) { + ssize_t index = str.find(":"); + + String8 configStr; + String8 extensionStr; + if (index >= 0) { + configStr.setTo(str.string(), index); + extensionStr.setTo(str.string() + index + 1); + } else { + configStr.setTo(str); + } + + SplitDescription split; + if (!AaptConfig::parse(configStr, &split.config)) { + return false; + } + + Vector<String8> parts = AaptUtil::splitAndLowerCase(extensionStr, '-'); + const ssize_t N = parts.size(); + index = 0; + + if (extensionStr.length() == 0) { + goto success; + } + + index = parseAbi(parts, index, &split); + if (index < 0) { + return false; + } else { + if (index == N) { + goto success; + } + } + + // Unrecognized + return false; + +success: + if (outSplit != NULL) { + *outSplit = split; + } + return true; +} + +} // namespace split diff --git a/tools/split-select/SplitDescription.h b/tools/split-select/SplitDescription.h new file mode 100644 index 0000000..5fcafc8 --- /dev/null +++ b/tools/split-select/SplitDescription.h @@ -0,0 +1,65 @@ +/* + * 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. + */ + +#ifndef H_ANDROID_SPLIT_SPLIT_DESCRIPTION +#define H_ANDROID_SPLIT_SPLIT_DESCRIPTION + +#include "aapt/ConfigDescription.h" +#include "Abi.h" + +#include <utils/String8.h> +#include <utils/Vector.h> + +namespace split { + +struct SplitDescription { + SplitDescription(); + SplitDescription(const SplitDescription&) = default; + + ConfigDescription config; + abi::Variant abi; + + int compare(const SplitDescription& rhs) const; + inline bool operator<(const SplitDescription& rhs) const; + inline bool operator==(const SplitDescription& rhs) const; + inline bool operator!=(const SplitDescription& rhs) const; + + bool match(const SplitDescription& o) const; + bool isBetterThan(const SplitDescription& o, const SplitDescription& target) const; + + android::String8 toString() const; + + static bool parse(const android::String8& str, SplitDescription* outSplit); +}; + +ssize_t parseAbi(const android::Vector<android::String8>& parts, const ssize_t index, + SplitDescription* outSplit); + +bool SplitDescription::operator<(const SplitDescription& rhs) const { + return compare(rhs) < 0; +} + +bool SplitDescription::operator==(const SplitDescription& rhs) const { + return compare(rhs) == 0; +} + +bool SplitDescription::operator!=(const SplitDescription& rhs) const { + return compare(rhs) != 0; +} + +} // namespace split + +#endif // H_ANDROID_SPLIT_SPLIT_DESCRIPTION diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 02e610c..0db7658 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -977,7 +977,8 @@ public class WifiConfiguration implements Parcelable { if (this.didSelfAdd) sbuf.append(" didSelfAdd"); if (this.selfAdded) sbuf.append(" selfAdded"); if (this.noInternetAccess) sbuf.append(" noInternetAccess"); - if (this.didSelfAdd || this.selfAdded || this.noInternetAccess) { + if (this.ephemeral) sbuf.append(" ephemeral"); + if (this.didSelfAdd || this.selfAdded || this.noInternetAccess || this.ephemeral) { sbuf.append("\n"); } sbuf.append(" KeyMgmt:"); @@ -1434,6 +1435,7 @@ public class WifiConfiguration implements Parcelable { autoJoinStatus = source.autoJoinStatus; selfAdded = source.selfAdded; noInternetAccess = source.noInternetAccess; + ephemeral = source.ephemeral; if (source.visibility != null) { visibility = new Visibility(source.visibility); } @@ -1510,6 +1512,7 @@ public class WifiConfiguration implements Parcelable { dest.writeInt(selfAdded ? 1 : 0); dest.writeInt(didSelfAdd ? 1 : 0); dest.writeInt(noInternetAccess ? 1 : 0); + dest.writeInt(ephemeral ? 1 : 0); dest.writeInt(creatorUid); dest.writeInt(lastConnectUid); dest.writeInt(lastUpdateUid); @@ -1570,6 +1573,7 @@ public class WifiConfiguration implements Parcelable { config.selfAdded = in.readInt() != 0; config.didSelfAdd = in.readInt() != 0; config.noInternetAccess = in.readInt() != 0; + config.ephemeral = in.readInt() != 0; config.creatorUid = in.readInt(); config.lastConnectUid = in.readInt(); config.lastUpdateUid = in.readInt(); |
