diff options
153 files changed, 3131 insertions, 1052 deletions
diff --git a/api/current.txt b/api/current.txt index 2094c7c..90e44e7 100644 --- a/api/current.txt +++ b/api/current.txt @@ -215,6 +215,8 @@ package android { public static final class R.attr { ctor public R.attr(); + field public static final int __removeBeforeMRelease_leftIndents = 16844016; // 0x10104f0 + field public static final int __removeBeforeMRelease_rightIndents = 16844017; // 0x10104f1 field public static final int __reserved0 = 16844020; // 0x10104f4 field public static final int __reserved1 = 16844019; // 0x10104f3 field public static final int __reserved2 = 16843999; // 0x10104df @@ -801,7 +803,6 @@ package android { field public static final int layout_x = 16843135; // 0x101017f field public static final int layout_y = 16843136; // 0x1010180 field public static final int left = 16843181; // 0x10101ad - field public static final int leftIndents = 16844016; // 0x10104f0 field public static final int letterSpacing = 16843958; // 0x10104b6 field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 @@ -826,6 +827,7 @@ package android { field public static final int listViewWhiteStyle = 16842869; // 0x1010075 field public static final int lockTaskMode = 16844015; // 0x10104ef field public static final int logo = 16843454; // 0x10102be + field public static final int logoDescription = 16844026; // 0x10104fa field public static final int longClickable = 16842982; // 0x10100e6 field public static final int loopViews = 16843527; // 0x1010307 field public static final int manageSpaceActivity = 16842756; // 0x1010004 @@ -1026,7 +1028,6 @@ package android { field public static final int reversible = 16843851; // 0x101044b field public static final int revisionCode = 16843989; // 0x10104d5 field public static final int right = 16843183; // 0x10101af - field public static final int rightIndents = 16844017; // 0x10104f1 field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093 field public static final int ringtoneType = 16843257; // 0x10101f9 field public static final int rotation = 16843558; // 0x1010326 @@ -1178,6 +1179,7 @@ package android { field public static final int submitBackground = 16843912; // 0x1010488 field public static final int subtitle = 16843473; // 0x10102d1 field public static final int subtitleTextAppearance = 16843823; // 0x101042f + field public static final int subtitleTextColor = 16844028; // 0x10104fc field public static final int subtitleTextStyle = 16843513; // 0x10102f9 field public static final int subtypeExtraValue = 16843674; // 0x101039a field public static final int subtypeId = 16843713; // 0x10103c1 @@ -1308,6 +1310,7 @@ package android { field public static final int title = 16843233; // 0x10101e1 field public static final int titleCondensed = 16843234; // 0x10101e2 field public static final int titleTextAppearance = 16843822; // 0x101042e + field public static final int titleTextColor = 16844027; // 0x10104fb field public static final int titleTextStyle = 16843512; // 0x10102f8 field public static final int toAlpha = 16843211; // 0x10101cb field public static final int toDegrees = 16843188; // 0x10101b4 @@ -3758,7 +3761,7 @@ package android.app { method public void requestUsageTimeReport(android.app.PendingIntent); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); - field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.usage_time"; + field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; field public static final java.lang.String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages"; } @@ -5194,6 +5197,7 @@ package android.app { method public void send(int, android.app.PendingIntent.OnFinished, android.os.Handler) throws android.app.PendingIntent.CanceledException; method public void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler) throws android.app.PendingIntent.CanceledException; 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 void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, java.lang.String, android.os.Bundle) 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<android.app.PendingIntent> CREATOR; @@ -5848,7 +5852,6 @@ package android.app.admin { field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED"; field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE"; field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME"; - field public static final java.lang.String EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS = "android.app.extra.PROVISIONING_RESET_PROTECTION_PARAMETERS"; field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION"; field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE"; field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN"; @@ -12302,7 +12305,6 @@ package android.graphics.drawable { method public android.graphics.drawable.Drawable.ConstantState getConstantState(); method public android.graphics.drawable.Drawable getCurrent(); method public android.graphics.Rect getDirtyBounds(); - method public boolean getDither(); method public void getHotspotBounds(android.graphics.Rect); method public int getIntrinsicHeight(); method public int getIntrinsicWidth(); @@ -12319,6 +12321,7 @@ package android.graphics.drawable { method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public void invalidateSelf(); method public boolean isAutoMirrored(); + method public boolean isDither(); method public boolean isFilterBitmap(); method public boolean isStateful(); method public final boolean isVisible(); @@ -26057,6 +26060,7 @@ package android.provider { field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF"; field public static final java.lang.String EXTRA_INFO = "info"; field public static final java.lang.String EXTRA_LOADING = "loading"; + field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT"; field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER"; } @@ -28909,6 +28913,7 @@ package android.service.voice { method public void onDestroy(); method public boolean[] onGetSupportedCommands(java.lang.String[]); method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent); + method public void onHandleScreenshot(android.graphics.Bitmap); method public void onHide(); method public boolean onKeyDown(int, android.view.KeyEvent); method public boolean onKeyLongPress(int, android.view.KeyEvent); @@ -28931,6 +28936,7 @@ package android.service.voice { method public void startVoiceActivity(android.content.Intent); field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4 field public static final int SHOW_WITH_ASSIST = 1; // 0x1 + field public static final int SHOW_WITH_SCREENSHOT = 2; // 0x2 } public static final class VoiceInteractionSession.AbortVoiceRequest extends android.service.voice.VoiceInteractionSession.Request { @@ -30619,12 +30625,17 @@ package android.telephony { field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool"; field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool"; + field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; + field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string"; field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool"; field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_vibration_bool"; + field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array"; + field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array"; field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool"; field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool"; + field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool"; field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool"; field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled"; field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars"; @@ -36806,6 +36817,8 @@ package android.view { method public boolean onRequestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public boolean onStartNestedScroll(android.view.View, android.view.View, int); method public void onStopNestedScroll(android.view.View); + method public void onViewAdded(android.view.View); + method public void onViewRemoved(android.view.View); method public void recomputeViewAttributes(android.view.View); method public void removeAllViews(); method public void removeAllViewsInLayout(); @@ -41558,7 +41571,6 @@ package android.widget { method public int getInputType(); method public final android.text.method.KeyListener getKeyListener(); method public final android.text.Layout getLayout(); - method public int[] getLeftIndents(); method public float getLetterSpacing(); method public int getLineBounds(int, android.graphics.Rect); method public int getLineCount(); @@ -41581,7 +41593,6 @@ package android.widget { method public android.text.TextPaint getPaint(); method public int getPaintFlags(); method public java.lang.String getPrivateImeOptions(); - method public int[] getRightIndents(); method public int getSelectionEnd(); method public int getSelectionStart(); method public int getShadowColor(); @@ -41661,7 +41672,6 @@ package android.widget { method public void setImeActionLabel(java.lang.CharSequence, int); method public void setImeOptions(int); method public void setIncludeFontPadding(boolean); - method public void setIndents(int[], int[]); method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public void setInputType(int); method public void setKeyListener(android.text.method.KeyListener); diff --git a/api/system-current.txt b/api/system-current.txt index 9386c50..8a99eaf 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -290,6 +290,8 @@ package android { public static final class R.attr { ctor public R.attr(); + field public static final int __removeBeforeMRelease_leftIndents = 16844016; // 0x10104f0 + field public static final int __removeBeforeMRelease_rightIndents = 16844017; // 0x10104f1 field public static final int __reserved0 = 16844020; // 0x10104f4 field public static final int __reserved1 = 16844019; // 0x10104f3 field public static final int __reserved2 = 16843999; // 0x10104df @@ -876,7 +878,6 @@ package android { field public static final int layout_x = 16843135; // 0x101017f field public static final int layout_y = 16843136; // 0x1010180 field public static final int left = 16843181; // 0x10101ad - field public static final int leftIndents = 16844016; // 0x10104f0 field public static final int letterSpacing = 16843958; // 0x10104b6 field public static final int lineSpacingExtra = 16843287; // 0x1010217 field public static final int lineSpacingMultiplier = 16843288; // 0x1010218 @@ -901,6 +902,7 @@ package android { field public static final int listViewWhiteStyle = 16842869; // 0x1010075 field public static final int lockTaskMode = 16844015; // 0x10104ef field public static final int logo = 16843454; // 0x10102be + field public static final int logoDescription = 16844026; // 0x10104fa field public static final int longClickable = 16842982; // 0x10100e6 field public static final int loopViews = 16843527; // 0x1010307 field public static final int manageSpaceActivity = 16842756; // 0x1010004 @@ -1101,7 +1103,6 @@ package android { field public static final int reversible = 16843851; // 0x101044b field public static final int revisionCode = 16843989; // 0x10104d5 field public static final int right = 16843183; // 0x10101af - field public static final int rightIndents = 16844017; // 0x10104f1 field public static final int ringtonePreferenceStyle = 16842899; // 0x1010093 field public static final int ringtoneType = 16843257; // 0x10101f9 field public static final int rotation = 16843558; // 0x1010326 @@ -1257,6 +1258,7 @@ package android { field public static final int submitBackground = 16843912; // 0x1010488 field public static final int subtitle = 16843473; // 0x10102d1 field public static final int subtitleTextAppearance = 16843823; // 0x101042f + field public static final int subtitleTextColor = 16844028; // 0x10104fc field public static final int subtitleTextStyle = 16843513; // 0x10102f9 field public static final int subtypeExtraValue = 16843674; // 0x101039a field public static final int subtypeId = 16843713; // 0x10103c1 @@ -1387,6 +1389,7 @@ package android { field public static final int title = 16843233; // 0x10101e1 field public static final int titleCondensed = 16843234; // 0x10101e2 field public static final int titleTextAppearance = 16843822; // 0x101042e + field public static final int titleTextColor = 16844027; // 0x10104fb field public static final int titleTextStyle = 16843512; // 0x10102f8 field public static final int toAlpha = 16843211; // 0x10101cb field public static final int toDegrees = 16843188; // 0x10101b4 @@ -3851,7 +3854,7 @@ package android.app { method public void requestUsageTimeReport(android.app.PendingIntent); method public android.os.Bundle toBundle(); method public void update(android.app.ActivityOptions); - field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.usage_time"; + field public static final java.lang.String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; field public static final java.lang.String EXTRA_USAGE_TIME_REPORT_PACKAGES = "android.usage_time_packages"; } @@ -4183,6 +4186,12 @@ package android.app { method public int getWidth(); } + public class BroadcastOptions { + method public static android.app.BroadcastOptions makeBasic(); + method public void setTemporaryAppWhitelistDuration(long); + method public android.os.Bundle toBundle(); + } + public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener { ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int); ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int); @@ -5289,6 +5298,7 @@ package android.app { method public void send(int, android.app.PendingIntent.OnFinished, android.os.Handler) throws android.app.PendingIntent.CanceledException; method public void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler) throws android.app.PendingIntent.CanceledException; 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 void send(android.content.Context, int, android.content.Intent, android.app.PendingIntent.OnFinished, android.os.Handler, java.lang.String, android.os.Bundle) 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<android.app.PendingIntent> CREATOR; @@ -5959,7 +5969,6 @@ package android.app.admin { field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED"; field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE"; field public static final java.lang.String EXTRA_PROVISIONING_LOCAL_TIME = "android.app.extra.PROVISIONING_LOCAL_TIME"; - field public static final java.lang.String EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS = "android.app.extra.PROVISIONING_RESET_PROTECTION_PARAMETERS"; field public static final java.lang.String EXTRA_PROVISIONING_SKIP_ENCRYPTION = "android.app.extra.PROVISIONING_SKIP_ENCRYPTION"; field public static final java.lang.String EXTRA_PROVISIONING_TIME_ZONE = "android.app.extra.PROVISIONING_TIME_ZONE"; field public static final java.lang.String EXTRA_PROVISIONING_WIFI_HIDDEN = "android.app.extra.PROVISIONING_WIFI_HIDDEN"; @@ -7963,10 +7972,12 @@ package android.content { method public abstract void revokeUriPermission(android.net.Uri, int); method public abstract void sendBroadcast(android.content.Intent); method public abstract void sendBroadcast(android.content.Intent, java.lang.String); + method public abstract void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle); method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle); method public abstract void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String); method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String); method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); + method public abstract void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); method public abstract void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); method public abstract deprecated void sendStickyBroadcast(android.content.Intent); method public abstract deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle); @@ -8140,10 +8151,12 @@ package android.content { method public void revokeUriPermission(android.net.Uri, int); method public void sendBroadcast(android.content.Intent); method public void sendBroadcast(android.content.Intent, java.lang.String); + method public void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle); method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle); method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String); method public void sendOrderedBroadcast(android.content.Intent, java.lang.String); method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); + method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); method public deprecated void sendStickyBroadcast(android.content.Intent); method public deprecated void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle); @@ -12617,7 +12630,6 @@ package android.graphics.drawable { method public android.graphics.drawable.Drawable.ConstantState getConstantState(); method public android.graphics.drawable.Drawable getCurrent(); method public android.graphics.Rect getDirtyBounds(); - method public boolean getDither(); method public void getHotspotBounds(android.graphics.Rect); method public int getIntrinsicHeight(); method public int getIntrinsicWidth(); @@ -12634,6 +12646,7 @@ package android.graphics.drawable { method public void inflate(android.content.res.Resources, org.xmlpull.v1.XmlPullParser, android.util.AttributeSet, android.content.res.Resources.Theme) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public void invalidateSelf(); method public boolean isAutoMirrored(); + method public boolean isDither(); method public boolean isFilterBitmap(); method public boolean isStateful(); method public final boolean isVisible(); @@ -27991,6 +28004,7 @@ package android.provider { field public static final java.lang.String EXTRA_EXCLUDE_SELF = "android.provider.extra.EXCLUDE_SELF"; field public static final java.lang.String EXTRA_INFO = "info"; field public static final java.lang.String EXTRA_LOADING = "loading"; + field public static final java.lang.String EXTRA_PROMPT = "android.provider.extra.PROMPT"; field public static final java.lang.String PROVIDER_INTERFACE = "android.content.action.DOCUMENTS_PROVIDER"; } @@ -30903,7 +30917,6 @@ package android.service.persistentdata { method public abstract byte[] read() throws android.os.RemoteException; method public abstract void setOemUnlockEnabled(boolean) throws android.os.RemoteException; method public abstract void wipe() throws android.os.RemoteException; - method public abstract void wipeIfAllowed(android.os.Bundle, android.app.PendingIntent) throws android.os.RemoteException; method public abstract int write(byte[]) throws android.os.RemoteException; } @@ -30915,14 +30928,7 @@ package android.service.persistentdata { method public byte[] read(); method public void setOemUnlockEnabled(boolean); method public void wipe(); - method public void wipeIfAllowed(android.os.Bundle, android.app.PendingIntent); method public int write(byte[]); - field public static final java.lang.String ACTION_WIPE_IF_ALLOWED = "android.service.persistentdata.action.WIPE_IF_ALLOWED"; - field public static final java.lang.String EXTRA_WIPE_IF_ALLOWED_CALLBACK = "android.service.persistentdata.extra.WIPE_IF_ALLOWED_CALLBACK"; - field public static final int STATUS_ERROR_NETWORK_ERROR = 2; // 0x2 - field public static final int STATUS_ERROR_NOT_COMPLIANT = 3; // 0x3 - field public static final int STATUS_ERROR_REMOTE_EXCEPTION = 1; // 0x1 - field public static final int STATUS_SUCCESS = 0; // 0x0 } } @@ -31046,6 +31052,7 @@ package android.service.voice { method public void onDestroy(); method public boolean[] onGetSupportedCommands(java.lang.String[]); method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent); + method public void onHandleScreenshot(android.graphics.Bitmap); method public void onHide(); method public boolean onKeyDown(int, android.view.KeyEvent); method public boolean onKeyLongPress(int, android.view.KeyEvent); @@ -31068,6 +31075,7 @@ package android.service.voice { method public void startVoiceActivity(android.content.Intent); field public static final int SHOW_SOURCE_ASSIST_GESTURE = 4; // 0x4 field public static final int SHOW_WITH_ASSIST = 1; // 0x1 + field public static final int SHOW_WITH_SCREENSHOT = 2; // 0x2 } public static final class VoiceInteractionSession.AbortVoiceRequest extends android.service.voice.VoiceInteractionSession.Request { @@ -32839,12 +32847,17 @@ package android.telephony { field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONED_BOOL = "carrier_volte_provisioned_bool"; field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool"; field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool"; + field public static final java.lang.String KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; + field public static final java.lang.String KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; field public static final java.lang.String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string"; field public static final java.lang.String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; field public static final java.lang.String KEY_DTMF_TYPE_ENABLED_BOOL = "dtmf_type_enabled_bool"; field public static final java.lang.String KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL = "enable_dialer_vibration_bool"; + field public static final java.lang.String KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array"; + field public static final java.lang.String KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array"; field public static final java.lang.String KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL = "has_in_call_noise_suppression_bool"; field public static final java.lang.String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool"; + field public static final java.lang.String KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool"; field public static final java.lang.String KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL = "ignore_sim_network_locked_events_bool"; field public static final java.lang.String KEY_MMS_ALIAS_ENABLED_BOOL = "aliasEnabled"; field public static final java.lang.String KEY_MMS_ALIAS_MAX_CHARS_INT = "aliasMaxChars"; @@ -34016,10 +34029,12 @@ package android.test.mock { method public void revokeUriPermission(android.net.Uri, int); method public void sendBroadcast(android.content.Intent); method public void sendBroadcast(android.content.Intent, java.lang.String); + method public void sendBroadcast(android.content.Intent, java.lang.String, android.os.Bundle); method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle); method public void sendBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String); method public void sendOrderedBroadcast(android.content.Intent, java.lang.String); method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); + method public void sendOrderedBroadcast(android.content.Intent, java.lang.String, android.os.Bundle, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); method public void sendOrderedBroadcastAsUser(android.content.Intent, android.os.UserHandle, java.lang.String, android.content.BroadcastReceiver, android.os.Handler, int, java.lang.String, android.os.Bundle); method public void sendStickyBroadcast(android.content.Intent); method public void sendStickyBroadcastAsUser(android.content.Intent, android.os.UserHandle); @@ -39082,6 +39097,8 @@ package android.view { method public boolean onRequestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent); method public boolean onStartNestedScroll(android.view.View, android.view.View, int); method public void onStopNestedScroll(android.view.View); + method public void onViewAdded(android.view.View); + method public void onViewRemoved(android.view.View); method public void recomputeViewAttributes(android.view.View); method public void removeAllViews(); method public void removeAllViewsInLayout(); @@ -44148,7 +44165,6 @@ package android.widget { method public int getInputType(); method public final android.text.method.KeyListener getKeyListener(); method public final android.text.Layout getLayout(); - method public int[] getLeftIndents(); method public float getLetterSpacing(); method public int getLineBounds(int, android.graphics.Rect); method public int getLineCount(); @@ -44171,7 +44187,6 @@ package android.widget { method public android.text.TextPaint getPaint(); method public int getPaintFlags(); method public java.lang.String getPrivateImeOptions(); - method public int[] getRightIndents(); method public int getSelectionEnd(); method public int getSelectionStart(); method public int getShadowColor(); @@ -44251,7 +44266,6 @@ package android.widget { method public void setImeActionLabel(java.lang.CharSequence, int); method public void setImeOptions(int); method public void setIncludeFontPadding(boolean); - method public void setIndents(int[], int[]); method public void setInputExtras(int) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException; method public void setInputType(int); method public void setKeyListener(android.text.method.KeyListener); diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java index bf3b455..69ba27c 100644 --- a/cmds/am/src/com/android/commands/am/Am.java +++ b/cmds/am/src/com/android/commands/am/Am.java @@ -1002,7 +1002,7 @@ public class Am extends BaseCommand { IntentReceiver receiver = new IntentReceiver(); System.out.println("Broadcasting: " + intent); mAm.broadcastIntent(null, intent, null, receiver, 0, null, null, mReceiverPermission, - android.app.AppOpsManager.OP_NONE, true, false, mUserId); + android.app.AppOpsManager.OP_NONE, null, true, false, mUserId); receiver.waitForFinish(); } @@ -1658,7 +1658,7 @@ public class Am extends BaseCommand { Intent intent = new Intent( "com.android.server.task.controllers.IdleController.ACTION_TRIGGER_IDLE"); mAm.broadcastIntent(null, intent, null, null, 0, null, null, null, - android.app.AppOpsManager.OP_NONE, true, false, UserHandle.USER_ALL); + android.app.AppOpsManager.OP_NONE, null, true, false, UserHandle.USER_ALL); } private void runScreenCompat() throws Exception { diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 1faf41b..2be44bc 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -1812,7 +1812,7 @@ public final class Pm { private IIntentSender.Stub mLocalSender = new IIntentSender.Stub() { @Override public int send(int code, Intent intent, String resolvedType, - IIntentReceiver finishedReceiver, String requiredPermission) { + IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) { try { mResult.offer(intent, 5, TimeUnit.SECONDS); } catch (InterruptedException e) { diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java index 6ae21eb..680feae 100644 --- a/core/java/android/app/ActivityManagerNative.java +++ b/core/java/android/app/ActivityManagerNative.java @@ -108,7 +108,7 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM try { getDefault().broadcastIntent( null, intent, null, null, Activity.RESULT_OK, null, null, - null /*permission*/, appOp, false, true, userId); + null /*permission*/, appOp, null, false, true, userId); } catch (RemoteException ex) { } } @@ -458,12 +458,13 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM Bundle resultExtras = data.readBundle(); String perm = data.readString(); int appOp = data.readInt(); + Bundle options = data.readBundle(); boolean serialized = data.readInt() != 0; boolean sticky = data.readInt() != 0; int userId = data.readInt(); int res = broadcastIntent(app, intent, resolvedType, resultTo, resultCode, resultData, resultExtras, perm, appOp, - serialized, sticky, userId); + options, serialized, sticky, userId); reply.writeNoException(); reply.writeInt(res); return true; @@ -2991,9 +2992,9 @@ class ActivityManagerProxy implements IActivityManager reply.recycle(); } public int broadcastIntent(IApplicationThread caller, - Intent intent, String resolvedType, IIntentReceiver resultTo, + Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, - String requiredPermission, int appOp, boolean serialized, + String requiredPermission, int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException { Parcel data = Parcel.obtain(); @@ -3008,6 +3009,7 @@ class ActivityManagerProxy implements IActivityManager data.writeBundle(map); data.writeString(requiredPermission); data.writeInt(appOp); + data.writeBundle(options); data.writeInt(serialized ? 1 : 0); data.writeInt(sticky ? 1 : 0); data.writeInt(userId); diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java index 6fb997e..2406985 100644 --- a/core/java/android/app/ActivityOptions.java +++ b/core/java/android/app/ActivityOptions.java @@ -43,7 +43,7 @@ public class ActivityOptions { * A long in the extras delivered by {@link #requestUsageTimeReport} that contains * the total time (in ms) the user spent in the app flow. */ - public static final String EXTRA_USAGE_TIME_REPORT = "android.usage_time"; + public static final String EXTRA_USAGE_TIME_REPORT = "android.activity.usage_time"; /** * A Bundle in the extras delivered by {@link #requestUsageTimeReport} that contains @@ -56,67 +56,67 @@ public class ActivityOptions { * The package name that created the options. * @hide */ - public static final String KEY_PACKAGE_NAME = "android:packageName"; + public static final String KEY_PACKAGE_NAME = "android:activity.packageName"; /** * Type of animation that arguments specify. * @hide */ - public static final String KEY_ANIM_TYPE = "android:animType"; + public static final String KEY_ANIM_TYPE = "android:activity.animType"; /** * Custom enter animation resource ID. * @hide */ - public static final String KEY_ANIM_ENTER_RES_ID = "android:animEnterRes"; + public static final String KEY_ANIM_ENTER_RES_ID = "android:activity.animEnterRes"; /** * Custom exit animation resource ID. * @hide */ - public static final String KEY_ANIM_EXIT_RES_ID = "android:animExitRes"; + public static final String KEY_ANIM_EXIT_RES_ID = "android:activity.animExitRes"; /** * Custom in-place animation resource ID. * @hide */ - public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:animInPlaceRes"; + public static final String KEY_ANIM_IN_PLACE_RES_ID = "android:activity.animInPlaceRes"; /** * Bitmap for thumbnail animation. * @hide */ - public static final String KEY_ANIM_THUMBNAIL = "android:animThumbnail"; + public static final String KEY_ANIM_THUMBNAIL = "android:activity.animThumbnail"; /** * Start X position of thumbnail animation. * @hide */ - public static final String KEY_ANIM_START_X = "android:animStartX"; + public static final String KEY_ANIM_START_X = "android:activity.animStartX"; /** * Start Y position of thumbnail animation. * @hide */ - public static final String KEY_ANIM_START_Y = "android:animStartY"; + public static final String KEY_ANIM_START_Y = "android:activity.animStartY"; /** * Initial width of the animation. * @hide */ - public static final String KEY_ANIM_WIDTH = "android:animWidth"; + public static final String KEY_ANIM_WIDTH = "android:activity.animWidth"; /** * Initial height of the animation. * @hide */ - public static final String KEY_ANIM_HEIGHT = "android:animHeight"; + public static final String KEY_ANIM_HEIGHT = "android:activity.animHeight"; /** * Callback for when animation is started. * @hide */ - public static final String KEY_ANIM_START_LISTENER = "android:animStartListener"; + public static final String KEY_ANIM_START_LISTENER = "android:activity.animStartListener"; /** * For Activity transitions, the calling Activity's TransitionListener used to @@ -124,15 +124,18 @@ public class ActivityOptions { * complete. */ private static final String KEY_TRANSITION_COMPLETE_LISTENER - = "android:transitionCompleteListener"; - - private static final String KEY_TRANSITION_IS_RETURNING = "android:transitionIsReturning"; - private static final String KEY_TRANSITION_SHARED_ELEMENTS = "android:sharedElementNames"; - private static final String KEY_RESULT_DATA = "android:resultData"; - private static final String KEY_RESULT_CODE = "android:resultCode"; - private static final String KEY_EXIT_COORDINATOR_INDEX = "android:exitCoordinatorIndex"; - - private static final String KEY_USAGE_TIME_REPORT = "android:usageTimeReport"; + = "android:activity.transitionCompleteListener"; + + private static final String KEY_TRANSITION_IS_RETURNING + = "android:activity.transitionIsReturning"; + private static final String KEY_TRANSITION_SHARED_ELEMENTS + = "android:activity.sharedElementNames"; + private static final String KEY_RESULT_DATA = "android:activity.resultData"; + private static final String KEY_RESULT_CODE = "android:activity.resultCode"; + private static final String KEY_EXIT_COORDINATOR_INDEX + = "android:activity.exitCoordinatorIndex"; + + private static final String KEY_USAGE_TIME_REPORT = "android:activity.usageTimeReport"; /** @hide */ public static final int ANIM_NONE = 0; diff --git a/core/java/android/app/BroadcastOptions.java b/core/java/android/app/BroadcastOptions.java new file mode 100644 index 0000000..1f378da --- /dev/null +++ b/core/java/android/app/BroadcastOptions.java @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.app; + +import android.annotation.SystemApi; +import android.os.Bundle; + +/** + * Helper class for building an options Bundle that can be used with + * {@link android.content.Context#sendBroadcast(android.content.Intent) + * Context.sendBroadcast(Intent)} and related methods. + * {@hide} + */ +@SystemApi +public class BroadcastOptions { + private long mTemporaryAppWhitelistDuration; + + /** + * How long to temporarily put an app on the power whitelist when executing this broadcast + * to it. + * @hide + */ + public static final String KEY_TEMPORARY_APP_WHITELIST_DURATION + = "android:broadcast.temporaryAppWhitelistDuration"; + + public static BroadcastOptions makeBasic() { + BroadcastOptions opts = new BroadcastOptions(); + return opts; + } + + private BroadcastOptions() { + } + + /** @hide */ + public BroadcastOptions(Bundle opts) { + mTemporaryAppWhitelistDuration = opts.getLong(KEY_TEMPORARY_APP_WHITELIST_DURATION); + } + + /** + * Set a duration for which the system should temporary place an application on the + * power whitelist when this broadcast is being delivered to it. + * @param duration The duration in milliseconds; 0 means to not place on whitelist. + */ + public void setTemporaryAppWhitelistDuration(long duration) { + mTemporaryAppWhitelistDuration = duration; + } + + /** + * Return {@link #setTemporaryAppWhitelistDuration}. + * @hide + */ + public long getTemporaryAppWhitelistDuration() { + return mTemporaryAppWhitelistDuration; + } + + /** + * Returns the created options as a Bundle, which can be passed to + * {@link android.content.Context#sendBroadcast(android.content.Intent) + * Context.sendBroadcast(Intent)} and related methods. + * Note that the returned Bundle is still owned by the ActivityOptions + * object; you must not modify it, but can supply it to the sendBroadcast + * methods that take an options Bundle. + */ + public Bundle toBundle() { + Bundle b = new Bundle(); + if (mTemporaryAppWhitelistDuration > 0) { + b.putLong(KEY_TEMPORARY_APP_WHITELIST_DURATION, mTemporaryAppWhitelistDuration); + } + return b.isEmpty() ? null : b; + } +} diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index be36af7..0420fb6 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -46,7 +46,6 @@ import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; -import android.hardware.display.DisplayManager; import android.net.Uri; import android.os.Binder; import android.os.Build; @@ -676,8 +675,8 @@ class ContextImpl extends Context { + " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivity( - getOuterContext(), mMainThread.getApplicationThread(), null, - (Activity)null, intent, -1, options); + getOuterContext(), mMainThread.getApplicationThread(), null, + (Activity) null, intent, -1, options); } /** @hide */ @@ -710,8 +709,8 @@ class ContextImpl extends Context { + " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivitiesAsUser( - getOuterContext(), mMainThread.getApplicationThread(), null, - (Activity)null, intents, options, userHandle.getIdentifier()); + getOuterContext(), mMainThread.getApplicationThread(), null, + (Activity) null, intents, options, userHandle.getIdentifier()); } @Override @@ -724,8 +723,8 @@ class ContextImpl extends Context { + " Is this really what you want?"); } mMainThread.getInstrumentation().execStartActivities( - getOuterContext(), mMainThread.getApplicationThread(), null, - (Activity)null, intents, options); + getOuterContext(), mMainThread.getApplicationThread(), null, + (Activity) null, intents, options); } @Override @@ -766,9 +765,9 @@ class ContextImpl extends Context { try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( - mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, false, - getUserId()); + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false, + getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -781,9 +780,24 @@ class ContextImpl extends Context { try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( - mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, - false, false, getUserId()); + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + null, false, false, getUserId()); + } catch (RemoteException e) { + throw new RuntimeException("Failure from system", e); + } + } + + @Override + public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { + warnIfCallingFromSystemProcess(); + String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); + try { + intent.prepareToLeaveProcess(); + ActivityManagerNative.getDefault().broadcastIntent( + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + options, false, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -796,25 +810,24 @@ class ContextImpl extends Context { try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( - mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false, - getUserId()); + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermission, appOp, null, false, false, + getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } } @Override - public void sendOrderedBroadcast(Intent intent, - String receiverPermission) { + public void sendOrderedBroadcast(Intent intent, String receiverPermission) { warnIfCallingFromSystemProcess(); String resolvedType = intent.resolveTypeIfNeeded(getContentResolver()); try { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( - mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, true, false, - getUserId()); + mMainThread.getApplicationThread(), intent, resolvedType, null, + Activity.RESULT_OK, null, null, receiverPermission, AppOpsManager.OP_NONE, + null, true, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -826,7 +839,16 @@ class ContextImpl extends Context { Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE, - resultReceiver, scheduler, initialCode, initialData, initialExtras); + resultReceiver, scheduler, initialCode, initialData, initialExtras, null); + } + + @Override + public void sendOrderedBroadcast(Intent intent, + String receiverPermission, Bundle options, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, + Bundle initialExtras) { + sendOrderedBroadcast(intent, receiverPermission, AppOpsManager.OP_NONE, + resultReceiver, scheduler, initialCode, initialData, initialExtras, options); } @Override @@ -834,6 +856,14 @@ class ContextImpl extends Context { String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { + sendOrderedBroadcast(intent, receiverPermission, appOp, + resultReceiver, scheduler, initialCode, initialData, initialExtras, null); + } + + void sendOrderedBroadcast(Intent intent, + String receiverPermission, int appOp, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, + Bundle initialExtras, Bundle options) { warnIfCallingFromSystemProcess(); IIntentReceiver rd = null; if (resultReceiver != null) { @@ -858,7 +888,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, receiverPermission, appOp, - true, false, getUserId()); + options, true, false, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -871,7 +901,7 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(), intent, resolvedType, null, Activity.RESULT_OK, null, null, null, - AppOpsManager.OP_NONE, false, false, user.getIdentifier()); + AppOpsManager.OP_NONE, null, false, false, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -891,7 +921,7 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, receiverPermission, appOp, false, false, + Activity.RESULT_OK, null, null, receiverPermission, appOp, null, false, false, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -934,7 +964,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, receiverPermission, - appOp, true, false, user.getIdentifier()); + appOp, null, true, false, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -949,7 +979,7 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, + Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); @@ -986,7 +1016,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, null, - AppOpsManager.OP_NONE, true, true, getUserId()); + AppOpsManager.OP_NONE, null, true, true, getUserId()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -1017,7 +1047,7 @@ class ContextImpl extends Context { intent.prepareToLeaveProcess(); ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, null, - Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, false, true, user.getIdentifier()); + Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } @@ -1052,7 +1082,7 @@ class ContextImpl extends Context { ActivityManagerNative.getDefault().broadcastIntent( mMainThread.getApplicationThread(), intent, resolvedType, rd, initialCode, initialData, initialExtras, null, - AppOpsManager.OP_NONE, true, true, user.getIdentifier()); + AppOpsManager.OP_NONE, null, true, true, user.getIdentifier()); } catch (RemoteException e) { throw new RuntimeException("Failure from system", e); } diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java index 9311e5e..e7f7e13 100644 --- a/core/java/android/app/IActivityManager.java +++ b/core/java/android/app/IActivityManager.java @@ -107,7 +107,7 @@ public interface IActivityManager extends IInterface { public int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, Bundle map, String requiredPermission, - int appOp, boolean serialized, boolean sticky, int userId) throws RemoteException; + int appOp, Bundle options, boolean serialized, boolean sticky, int userId) throws RemoteException; public void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException; public void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast, int flags) throws RemoteException; diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 33a47b2..5a0d246 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -1371,6 +1371,9 @@ public class Notification implements Parcelable when = parcel.readLong(); if (parcel.readInt() != 0) { mSmallIcon = Icon.CREATOR.createFromParcel(parcel); + if (mSmallIcon.getType() == Icon.TYPE_RESOURCE) { + icon = mSmallIcon.getResId(); + } } number = parcel.readInt(); if (parcel.readInt() != 0) { @@ -1588,13 +1591,17 @@ public class Notification implements Parcelable } /** - * Flatten this notification from a parcel. + * Flatten this notification into a parcel. */ public void writeToParcel(Parcel parcel, int flags) { parcel.writeInt(1); parcel.writeLong(when); + if (mSmallIcon == null && icon != 0) { + // you snuck an icon in here without using the builder; let's try to keep it + mSmallIcon = Icon.createWithResource("", icon); + } if (mSmallIcon != null) { parcel.writeInt(1); mSmallIcon.writeToParcel(parcel, 0); @@ -2791,7 +2798,10 @@ public class Notification implements Parcelable return this; } - private void setFlag(int mask, boolean value) { + /** + * @hide + */ + public void setFlag(int mask, boolean value) { if (value) { mFlags |= mask; } else { diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java index 0904e21..605c006 100644 --- a/core/java/android/app/NotificationManager.java +++ b/core/java/android/app/NotificationManager.java @@ -25,6 +25,7 @@ import android.content.Context; import android.content.pm.ParceledListSlice; import android.graphics.drawable.Icon; import android.net.Uri; +import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; @@ -216,6 +217,12 @@ public class NotificationManager } } fixLegacySmallIcon(notification, pkg); + if (mContext.getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1) { + if (notification.getSmallIcon() == null) { + throw new IllegalArgumentException("Invalid notification (no valid small icon): " + + notification); + } + } if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")"); Notification stripped = notification.clone(); Builder.stripForDelivery(stripped); diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java index 031854a..c42ba65 100644 --- a/core/java/android/app/PendingIntent.java +++ b/core/java/android/app/PendingIntent.java @@ -613,7 +613,7 @@ public final class PendingIntent implements Parcelable { * is no longer allowing more intents to be sent through it. */ public void send() throws CanceledException { - send(null, 0, null, null, null, null); + send(null, 0, null, null, null, null, null); } /** @@ -627,7 +627,7 @@ public final class PendingIntent implements Parcelable { * is no longer allowing more intents to be sent through it. */ public void send(int code) throws CanceledException { - send(null, code, null, null, null, null); + send(null, code, null, null, null, null, null); } /** @@ -646,9 +646,9 @@ public final class PendingIntent implements Parcelable { * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ - public void send(Context context, int code, Intent intent) + public void send(Context context, int code, @Nullable Intent intent) throws CanceledException { - send(context, code, intent, null, null, null); + send(context, code, intent, null, null, null, null); } /** @@ -667,9 +667,9 @@ public final class PendingIntent implements Parcelable { * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ - public void send(int code, OnFinished onFinished, Handler handler) + public void send(int code, @Nullable OnFinished onFinished, @Nullable Handler handler) throws CanceledException { - send(null, code, null, onFinished, handler, null); + send(null, code, null, onFinished, handler, null, null); } /** @@ -705,9 +705,9 @@ public final class PendingIntent implements Parcelable { * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ - public void send(Context context, int code, Intent intent, - OnFinished onFinished, Handler handler) throws CanceledException { - send(context, code, intent, onFinished, handler, null); + public void send(Context context, int code, @Nullable Intent intent, + @Nullable OnFinished onFinished, @Nullable Handler handler) throws CanceledException { + send(context, code, intent, onFinished, handler, null, null); } /** @@ -748,8 +748,56 @@ public final class PendingIntent implements Parcelable { * @throws CanceledException Throws CanceledException if the PendingIntent * is no longer allowing more intents to be sent through it. */ - public void send(Context context, int code, Intent intent, - OnFinished onFinished, Handler handler, String requiredPermission) + public void send(Context context, int code, @Nullable Intent intent, + @Nullable OnFinished onFinished, @Nullable Handler handler, + @Nullable String requiredPermission) + throws CanceledException { + send(context, code, intent, onFinished, handler, requiredPermission, null); + } + + /** + * Perform the operation associated with this PendingIntent, allowing the + * caller to specify information about the Intent to use and be notified + * when the send has completed. + * + * <p>For the intent parameter, a PendingIntent + * often has restrictions on which fields can be supplied here, based on + * how the PendingIntent was retrieved in {@link #getActivity}, + * {@link #getBroadcast}, or {@link #getService}. + * + * @param context The Context of the caller. This may be null if + * <var>intent</var> is also null. + * @param code Result code to supply back to the PendingIntent's target. + * @param intent Additional Intent data. See {@link Intent#fillIn + * Intent.fillIn()} for information on how this is applied to the + * original Intent. Use null to not modify the original Intent. + * If flag {@link #FLAG_IMMUTABLE} was set when this pending intent was + * created, this argument will be ignored. + * @param onFinished The object to call back on when the send has + * completed, or null for no callback. + * @param handler Handler identifying the thread on which the callback + * should happen. If null, the callback will happen from the thread + * pool of the process. + * @param requiredPermission Name of permission that a recipient of the PendingIntent + * is required to hold. This is only valid for broadcast intents, and + * corresponds to the permission argument in + * {@link Context#sendBroadcast(Intent, String) Context.sendOrderedBroadcast(Intent, String)}. + * If null, no permission is required. + * @param options Additional options the caller would like to provide to modify the sending + * behavior. May be built from an {@link ActivityOptions} to apply to an activity start. + * + * @see #send() + * @see #send(int) + * @see #send(Context, int, Intent) + * @see #send(int, android.app.PendingIntent.OnFinished, Handler) + * @see #send(Context, int, Intent, OnFinished, Handler) + * + * @throws CanceledException Throws CanceledException if the PendingIntent + * is no longer allowing more intents to be sent through it. + */ + public void send(Context context, int code, @Nullable Intent intent, + @Nullable OnFinished onFinished, @Nullable Handler handler, + @Nullable String requiredPermission, @Nullable Bundle options) throws CanceledException { try { String resolvedType = intent != null ? @@ -759,7 +807,7 @@ public final class PendingIntent implements Parcelable { onFinished != null ? new FinishedDispatcher(this, onFinished, handler) : null, - requiredPermission); + requiredPermission, options); if (res < 0) { throw new CanceledException(); } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index ed20086..b9862ca 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -552,19 +552,6 @@ public class DevicePolicyManager { = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_SIGNATURE_CHECKSUM"; /** - * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that - * holds data needed by the system to wipe factory reset protection. The data needed to wipe - * the device depend on the installed factory reset protection implementation. For example, - * if an account is needed to unlock a device, this extra may contain data used to - * authenticate that account. - * - * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner - * provisioning via an NFC bump. - */ - public static final String EXTRA_PROVISIONING_RESET_PROTECTION_PARAMETERS - = "android.app.extra.PROVISIONING_RESET_PROTECTION_PARAMETERS"; - - /** * This MIME type is used for starting the Device Owner provisioning that does not require * provisioning features introduced in Android API level * {@link android.os.Build.VERSION_CODES#MNC} or later levels. diff --git a/core/java/android/appwidget/AppWidgetManager.java b/core/java/android/appwidget/AppWidgetManager.java index 1205708..278c9d6 100644 --- a/core/java/android/appwidget/AppWidgetManager.java +++ b/core/java/android/appwidget/AppWidgetManager.java @@ -20,6 +20,7 @@ import android.annotation.Nullable; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.pm.ParceledListSlice; import android.os.Bundle; import android.os.IBinder; import android.os.Process; @@ -753,16 +754,16 @@ public class AppWidgetManager { } try { - List<AppWidgetProviderInfo> providers = mService.getInstalledProvidersForProfile( + ParceledListSlice<AppWidgetProviderInfo> providers = mService.getInstalledProvidersForProfile( categoryFilter, profile.getIdentifier()); if (providers == null) { return Collections.emptyList(); } - for (AppWidgetProviderInfo info : providers) { + for (AppWidgetProviderInfo info : providers.getList()) { // Converting complex to dp. convertSizesToPixels(info); } - return providers; + return providers.getList(); } catch (RemoteException e) { throw new RuntimeException("system server dead?", e); diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 83ce087..675515b 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1517,6 +1517,38 @@ public abstract class Context { @Nullable String receiverPermission); /** + * Broadcast the given intent to all interested BroadcastReceivers, allowing + * an optional required permission to be enforced. This + * call is asynchronous; it returns immediately, and you will continue + * executing while the receivers are run. No results are propagated from + * receivers and receivers can not abort the broadcast. If you want + * to allow receivers to propagate results or abort the broadcast, you must + * send an ordered broadcast using + * {@link #sendOrderedBroadcast(Intent, String)}. + * + * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts. + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast. + * @param receiverPermission (optional) String naming a permission that + * a receiver must hold in order to receive your broadcast. + * If null, no permission is required. + * @param options (optional) Additional sending options, generated from a + * {@link android.app.BroadcastOptions}. + * + * @see android.content.BroadcastReceiver + * @see #registerReceiver + * @see #sendBroadcast(Intent) + * @see #sendOrderedBroadcast(Intent, String) + * @see #sendOrderedBroadcast(Intent, String, BroadcastReceiver, Handler, int, String, Bundle) + * @hide + */ + @SystemApi + public abstract void sendBroadcast(Intent intent, + @Nullable String receiverPermission, + @Nullable Bundle options); + + /** * Like {@link #sendBroadcast(Intent, String)}, but also allows specification * of an associated app op as per {@link android.app.AppOpsManager}. * @hide @@ -1588,11 +1620,60 @@ public abstract class Context { * @see android.app.Activity#RESULT_OK */ public abstract void sendOrderedBroadcast(@NonNull Intent intent, - @Nullable String receiverPermission, BroadcastReceiver resultReceiver, + @Nullable String receiverPermission, @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras); /** + * Version of {@link #sendBroadcast(Intent)} that allows you to + * receive data back from the broadcast. This is accomplished by + * supplying your own BroadcastReceiver when calling, which will be + * treated as a final receiver at the end of the broadcast -- its + * {@link BroadcastReceiver#onReceive} method will be called with + * the result values collected from the other receivers. The broadcast will + * be serialized in the same way as calling + * {@link #sendOrderedBroadcast(Intent, String)}. + * + * <p>Like {@link #sendBroadcast(Intent)}, this method is + * asynchronous; it will return before + * resultReceiver.onReceive() is called. + * + * <p>See {@link BroadcastReceiver} for more information on Intent broadcasts. + * + * + * @param intent The Intent to broadcast; all receivers matching this + * Intent will receive the broadcast. + * @param receiverPermission String naming a permissions that + * a receiver must hold in order to receive your broadcast. + * If null, no permission is required. + * @param options (optional) Additional sending options, generated from a + * {@link android.app.BroadcastOptions}. + * @param resultReceiver Your own BroadcastReceiver to treat as the final + * receiver of the broadcast. + * @param scheduler A custom Handler with which to schedule the + * resultReceiver callback; if null it will be + * scheduled in the Context's main thread. + * @param initialCode An initial value for the result code. Often + * Activity.RESULT_OK. + * @param initialData An initial value for the result data. Often + * null. + * @param initialExtras An initial value for the result extras. Often + * null. + * @see #sendBroadcast(Intent) + * @see #sendBroadcast(Intent, String) + * @see #sendOrderedBroadcast(Intent, String) + * @see android.content.BroadcastReceiver + * @see #registerReceiver + * @see android.app.Activity#RESULT_OK + * @hide + */ + @SystemApi + public abstract void sendOrderedBroadcast(@NonNull Intent intent, + @Nullable String receiverPermission, @Nullable Bundle options, + @Nullable BroadcastReceiver resultReceiver, @Nullable Handler scheduler, + int initialCode, @Nullable String initialData, @Nullable Bundle initialExtras); + + /** * Like {@link #sendOrderedBroadcast(Intent, String, BroadcastReceiver, android.os.Handler, * int, String, android.os.Bundle)}, but also allows specification * of an associated app op as per {@link android.app.AppOpsManager}. diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java index fb9e194..4e7c832 100644 --- a/core/java/android/content/ContextWrapper.java +++ b/core/java/android/content/ContextWrapper.java @@ -16,6 +16,7 @@ package android.content; +import android.annotation.SystemApi; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.res.AssetManager; @@ -401,6 +402,13 @@ public class ContextWrapper extends Context { } /** @hide */ + @SystemApi + @Override + public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { + mBase.sendBroadcast(intent, receiverPermission, options); + } + + /** @hide */ @Override public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { mBase.sendBroadcast(intent, receiverPermission, appOp); @@ -423,6 +431,18 @@ public class ContextWrapper extends Context { } /** @hide */ + @SystemApi + @Override + public void sendOrderedBroadcast( + Intent intent, String receiverPermission, Bundle options, BroadcastReceiver resultReceiver, + Handler scheduler, int initialCode, String initialData, + Bundle initialExtras) { + mBase.sendOrderedBroadcast(intent, receiverPermission, + options, resultReceiver, scheduler, initialCode, + initialData, initialExtras); + } + + /** @hide */ @Override public void sendOrderedBroadcast( Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, diff --git a/core/java/android/content/IIntentSender.aidl b/core/java/android/content/IIntentSender.aidl index 7dbd6f2..f3affa7 100644 --- a/core/java/android/content/IIntentSender.aidl +++ b/core/java/android/content/IIntentSender.aidl @@ -18,9 +18,10 @@ package android.content; import android.content.IIntentReceiver; import android.content.Intent; +import android.os.Bundle; /** @hide */ interface IIntentSender { int send(int code, in Intent intent, String resolvedType, - IIntentReceiver finishedReceiver, String requiredPermission); + IIntentReceiver finishedReceiver, String requiredPermission, in Bundle options); } diff --git a/core/java/android/content/IntentSender.java b/core/java/android/content/IntentSender.java index 166495b..13a767e 100644 --- a/core/java/android/content/IntentSender.java +++ b/core/java/android/content/IntentSender.java @@ -195,7 +195,7 @@ public class IntentSender implements Parcelable { onFinished != null ? new FinishedDispatcher(this, onFinished, handler) : null, - requiredPermission); + requiredPermission, null); if (res < 0) { throw new SendIntentException(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index bd50ca0..dd1c5c2 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2900,7 +2900,7 @@ public abstract class PackageManager { * * @return A List<ResolveInfo> containing one entry for each matching * Receiver. These are ordered from first to last in priority. If - * there are no matching receivers, an empty list is returned. + * there are no matching receivers, an empty list or {@code null} is returned. * * @see #MATCH_DEFAULT_ONLY * @see #GET_INTENT_FILTERS @@ -2936,7 +2936,7 @@ public abstract class PackageManager { * ServiceInfo. These are ordered from best to worst match -- that * is, the first item in the list is what is returned by * resolveService(). If there are no matching services, an empty - * list is returned. + * list or {@code null} is returned. * * @see #GET_INTENT_FILTERS * @see #GET_RESOLVED_FILTER @@ -2955,7 +2955,7 @@ public abstract class PackageManager { * ServiceInfo. These are ordered from best to worst match -- that * is, the first item in the list is what is returned by * resolveService(). If there are no matching services, an empty - * list is returned. + * list or {@code null} is returned. * * @see #GET_INTENT_FILTERS * @see #GET_RESOLVED_FILTER @@ -2977,7 +2977,7 @@ public abstract class PackageManager { * @param flags Additional option flags. * @return A List<ResolveInfo> containing one entry for each matching * ProviderInfo. These are ordered from best to worst match. If - * there are no matching providers, an empty list is returned. + * there are no matching providers, an empty list or {@code null} is returned. * @see #GET_INTENT_FILTERS * @see #GET_RESOLVED_FILTER */ diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index a1ebe6a..83128c3 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -537,12 +537,16 @@ public class CameraDeviceImpl extends CameraDevice { CameraAccessException pendingException = null; Surface input = null; try { - // configure streams and then block until IDLE + // configure streams and then block until IDLE configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations, isConstrainedHighSpeed); - if (inputConfig != null) { + if (configureSuccess == true && inputConfig != null) { input = new Surface(); - mRemoteDevice.getInputSurface(/*out*/input); + try { + mRemoteDevice.getInputSurface(/*out*/input); + } catch (CameraRuntimeException e) { + e.asChecked(); + } } } catch (CameraAccessException e) { configureSuccess = false; @@ -2049,6 +2053,8 @@ public class CameraDeviceImpl extends CameraDevice { // Prepare the Request builders: need carry over the request controls. // First, create a request builder that will only include preview or recording target. CameraMetadataNative requestMetadata = new CameraMetadataNative(request.getNativeCopy()); + // Note that after this step, the requestMetadata is mutated (swapped) and can not be used + // for next request builder creation. CaptureRequest.Builder singleTargetRequestBuilder = new CaptureRequest.Builder( requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); @@ -2069,6 +2075,9 @@ public class CameraDeviceImpl extends CameraDevice { // Second, Create a request builder that will include both preview and recording targets. CaptureRequest.Builder doubleTargetRequestBuilder = null; if (outputSurfaces.size() == 2) { + // Have to create a new copy, the original one was mutated after a new + // CaptureRequest.Builder creation. + requestMetadata = new CameraMetadataNative(request.getNativeCopy()); doubleTargetRequestBuilder = new CaptureRequest.Builder( requestMetadata, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE); doubleTargetRequestBuilder.set(CaptureRequest.CONTROL_CAPTURE_INTENT, diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java index d461bca..1aee794 100644 --- a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java +++ b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java @@ -138,8 +138,8 @@ public class CameraBinderDecorator { * errors, then add them to the top switch statement */ if (errorFlag < 0) { - throw new UnsupportedOperationException(String.format("Unknown error %d", - errorFlag)); + throw new CameraRuntimeException(CAMERA_ERROR, + String.format("Unknown camera device error %d", errorFlag)); } } diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java index ecc3fb4..3f40484 100644 --- a/core/java/android/net/NetworkPolicyManager.java +++ b/core/java/android/net/NetworkPolicyManager.java @@ -61,6 +61,17 @@ public class NetworkPolicyManager { public static final int FIREWALL_RULE_ALLOW = 1; public static final int FIREWALL_RULE_DENY = 2; + public static final int FIREWALL_TYPE_WHITELIST = 0; + public static final int FIREWALL_TYPE_BLACKLIST = 1; + + public static final int FIREWALL_CHAIN_NONE = 0; + public static final int FIREWALL_CHAIN_DOZABLE = 1; + public static final int FIREWALL_CHAIN_STANDBY = 2; + + public static final String FIREWALL_CHAIN_NAME_NONE = "none"; + public static final String FIREWALL_CHAIN_NAME_DOZABLE = "dozable"; + public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby"; + private static final boolean ALLOW_PLATFORM_APP_POLICY = true; /** diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl index b29e8d0..8114155 100644 --- a/core/java/android/os/INetworkManagementService.aidl +++ b/core/java/android/os/INetworkManagementService.aidl @@ -342,7 +342,9 @@ interface INetworkManagementService void setFirewallInterfaceRule(String iface, boolean allow); void setFirewallEgressSourceRule(String addr, boolean allow); void setFirewallEgressDestRule(String addr, int port, boolean allow); - void setFirewallUidRule(int uid, int rule); + void setFirewallUidRule(int chain, int uid, int rule); + void setFirewallUidRules(int chain, in int[] uids, in int[] rules); + void setFirewallChainEnabled(int chain, boolean enable); /** * Set all packets from users in ranges to go through VPN specified by netId. diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java index 30535ff..c7ba607 100644 --- a/core/java/android/provider/DocumentsContract.java +++ b/core/java/android/provider/DocumentsContract.java @@ -107,6 +107,11 @@ public final class DocumentsContract { */ public static final String EXTRA_ORIENTATION = "android.content.extra.ORIENTATION"; + /** + * Overrides the default prompt text in DocumentsUI when set in an intent. + */ + public static final String EXTRA_PROMPT = "android.provider.extra.PROMPT"; + /** {@hide} */ public static final String ACTION_MANAGE_ROOT = "android.provider.action.MANAGE_ROOT"; /** {@hide} */ diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 3e9c9de..56cd1a7 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7133,6 +7133,29 @@ public final class Settings { public static final String APP_IDLE_CONSTANTS = "app_idle_constants"; /** + * Alarm manager specific settings. + * This is encoded as a key=value list, separated by commas. Ex: + * + * "min_futurity=5000,allow_while_idle_short_time=4500" + * + * The following keys are supported: + * + * <pre> + * min_futurity (long) + * min_interval (long) + * allow_while_idle_short_time (long) + * allow_while_idle_long_time (long) + * allow_while_idle_whitelist_duration (long) + * </pre> + * + * <p> + * Type: string + * @hide + * @see com.android.server.AlarmManagerService.Constants + */ + public static final String ALARM_MANAGER_CONSTANTS = "alarm_manager_constants"; + + /** * Get the key that retrieves a bluetooth headset's priority. * @hide */ diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java index 6e40c6c..3fb93c4 100644 --- a/core/java/android/security/keymaster/KeymasterDefs.java +++ b/core/java/android/security/keymaster/KeymasterDefs.java @@ -81,7 +81,6 @@ public final class KeymasterDefs { public static final int KM_TAG_ASSOCIATED_DATA = KM_BYTES | 1000; public static final int KM_TAG_NONCE = KM_BYTES | 1001; - public static final int KM_TAG_AEAD_TAG = KM_BYTES | 1002; public static final int KM_TAG_AUTH_TOKEN = KM_BYTES | 1003; public static final int KM_TAG_MAC_LENGTH = KM_INT | 1004; diff --git a/core/java/android/security/keymaster/OperationResult.java b/core/java/android/security/keymaster/OperationResult.java index 911a05a..3065966 100644 --- a/core/java/android/security/keymaster/OperationResult.java +++ b/core/java/android/security/keymaster/OperationResult.java @@ -35,15 +35,28 @@ public class OperationResult implements Parcelable { public static final Parcelable.Creator<OperationResult> CREATOR = new Parcelable.Creator<OperationResult>() { + @Override public OperationResult createFromParcel(Parcel in) { return new OperationResult(in); } + @Override public OperationResult[] newArray(int length) { return new OperationResult[length]; } }; + public OperationResult( + int resultCode, IBinder token, long operationHandle, int inputConsumed, byte[] output, + KeymasterArguments outParams) { + this.resultCode = resultCode; + this.token = token; + this.operationHandle = operationHandle; + this.inputConsumed = inputConsumed; + this.output = output; + this.outParams = outParams; + } + protected OperationResult(Parcel in) { resultCode = in.readInt(); token = in.readStrongBinder(); diff --git a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl index 0071a33..52db223 100644 --- a/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl +++ b/core/java/android/service/persistentdata/IPersistentDataBlockService.aidl @@ -16,8 +16,6 @@ package android.service.persistentdata; -import android.app.PendingIntent; -import android.os.Bundle; import android.os.ParcelFileDescriptor; /** @@ -32,7 +30,6 @@ interface IPersistentDataBlockService { int write(in byte[] data); byte[] read(); void wipe(); - void wipeIfAllowed(in Bundle bundle, in PendingIntent pi); int getDataBlockSize(); long getMaximumDataBlockSize(); diff --git a/core/java/android/service/persistentdata/PersistentDataBlockManager.java b/core/java/android/service/persistentdata/PersistentDataBlockManager.java index 31570c6..0ffdf68 100644 --- a/core/java/android/service/persistentdata/PersistentDataBlockManager.java +++ b/core/java/android/service/persistentdata/PersistentDataBlockManager.java @@ -17,8 +17,6 @@ package android.service.persistentdata; import android.annotation.SystemApi; -import android.app.PendingIntent; -import android.os.Bundle; import android.os.RemoteException; import android.util.Slog; @@ -43,56 +41,6 @@ import android.util.Slog; @SystemApi public class PersistentDataBlockManager { private static final String TAG = PersistentDataBlockManager.class.getSimpleName(); - - /** - * Broadcast action that will be called when the {@link #wipeIfAllowed(Bundle,PendingIntent)} - * method is called. A broadcast with this action will be sent to the package allowed to write - * to the persistent data block. Packages receiving this broadcasts should respond by using the - * {@link android.app.PendingIntent} sent in the {@link #EXTRA_WIPE_IF_ALLOWED_CALLBACK} extra. - */ - public static final String ACTION_WIPE_IF_ALLOWED - = "android.service.persistentdata.action.WIPE_IF_ALLOWED"; - - /** - * A {@link android.os.Parcelable} extra of type {@link android.app.PendingIntent} used to - * response to {@link #wipeIfAllowed(Bundle,PendingIntent)}. This extra will set in broadcasts - * with an action of {@link #ACTION_WIPE_IF_ALLOWED}. - */ - public static final String EXTRA_WIPE_IF_ALLOWED_CALLBACK - = "android.service.persistentdata.extra.WIPE_IF_ALLOWED_CALLBACK"; - - /** - * Result code indicating that the data block was wiped. - * - * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to - * {@link #wipeIfAllowed(Bundle,PendingIntent)} - */ - public static final int STATUS_SUCCESS = 0; - - /** - * Result code indicating that a remote exception was received while processing the request. - * - * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to - * {@link #wipeIfAllowed(Bundle,PendingIntent)} - */ - public static final int STATUS_ERROR_REMOTE_EXCEPTION = 1; - - /** - * Result code indicating that a network error occurred while processing the request. - * - * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to - * {@link #wipeIfAllowed(Bundle,PendingIntent)} - */ - public static final int STATUS_ERROR_NETWORK_ERROR = 2; - - /** - * Result code indicating that the data block could not be cleared with the provided data. - * - * <p>This value is set as result code of the {@link android.app.PendingIntent} argument to - * {@link #wipeIfAllowed(Bundle,PendingIntent)} - */ - public static final int STATUS_ERROR_NOT_COMPLIANT = 3; - private IPersistentDataBlockService sService; public PersistentDataBlockManager(IPersistentDataBlockService service) { @@ -170,28 +118,6 @@ public class PersistentDataBlockManager { } /** - * Attempt to wipe the data block by sending a broadcast to the package allowed to modify the - * datablock. The allowed package can refuse to wipe the data block based on the contents of - * the specified bundle. This bundle may contain data used by the allowed package to wipe the - * partition such as account credentials or an authorization token. - * @param bundle data used to wipe the data block. The contents of this bundle depend on the - * allowed package receiving the data. - * @param pi intent called when attempt finished. The result code of this intent will be set - * to one of {@link #STATUS_SUCCESS}, {@link #STATUS_ERROR_REMOTE_EXCEPTION}, - * {@link #STATUS_ERROR_NETWORK_ERROR}, or {@link #STATUS_ERROR_NOT_COMPLIANT}. - */ - public void wipeIfAllowed(Bundle bundle, PendingIntent pi) { - if (pi == null) { - throw new NullPointerException(); - } - try { - sService.wipeIfAllowed(bundle, pi); - } catch (RemoteException e) { - onError("wiping persistent partition"); - } - } - - /** * Writes a byte enabling or disabling the ability to "OEM unlock" the device. */ public void setOemUnlockEnabled(boolean enabled) { diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java index d5ee7e7..39dd29b 100644 --- a/core/java/android/service/voice/VoiceInteractionSession.java +++ b/core/java/android/service/voice/VoiceInteractionSession.java @@ -80,7 +80,6 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall public static final int SHOW_WITH_ASSIST = 1<<0; /** - * @hide * Flag received in {@link #onShow}: originator requested that the session be started with * a screen shot of the currently focused activity. */ @@ -1098,7 +1097,8 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall WindowManager.LayoutParams.TYPE_VOICE_INTERACTION, Gravity.BOTTOM, true); mWindow.getWindow().addFlags( WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED | - WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN); + WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | + WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR); initViews(); mWindow.getWindow().setLayout(MATCH_PARENT, MATCH_PARENT); mWindow.setToken(mToken); @@ -1143,7 +1143,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall mContentFrame.addView(view, new FrameLayout.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); - + mContentFrame.requestApplyInsets(); } /** @hide */ @@ -1162,7 +1162,6 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall onHandleAssist(data); } - /** @hide */ public void onHandleScreenshot(Bitmap screenshot) { } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 73cfd8c..2e2ba88 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -4148,24 +4148,38 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager mOnHierarchyChangeListener = listener; } - /** - * @hide - */ - protected void onViewAdded(View child) { + void dispatchViewAdded(View child) { + onViewAdded(child); if (mOnHierarchyChangeListener != null) { mOnHierarchyChangeListener.onChildViewAdded(this, child); } } /** - * @hide + * Called when a new child is added to this ViewGroup. Overrides should always + * call super.onViewAdded. + * + * @param child the added child view */ - protected void onViewRemoved(View child) { + public void onViewAdded(View child) { + } + + void dispatchViewRemoved(View child) { + onViewRemoved(child); if (mOnHierarchyChangeListener != null) { mOnHierarchyChangeListener.onChildViewRemoved(this, child); } } + /** + * Called when a child view is removed from this ViewGroup. Overrides should always + * call super.onViewRemoved. + * + * @param child the removed child view + */ + public void onViewRemoved(View child) { + } + private void clearCachedLayoutMode() { if (!hasBooleanFlag(FLAG_LAYOUT_MODE_WAS_EXPLICITLY_SET)) { mLayoutMode = LAYOUT_MODE_UNDEFINED; @@ -4292,7 +4306,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager child.resetRtlProperties(); } - onViewAdded(child); + dispatchViewAdded(child); if ((child.mViewFlags & DUPLICATE_PARENT_STATE) == DUPLICATE_PARENT_STATE) { mGroupFlags |= FLAG_NOTIFY_CHILDREN_ON_DRAWABLE_STATE_CHANGE; @@ -4554,7 +4568,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager } } - onViewRemoved(view); + dispatchViewRemoved(view); if (view.getVisibility() != View.GONE) { notifySubtreeAccessibilityStateChangedIfNeeded(); @@ -4646,7 +4660,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager needGlobalAttributesUpdate(false); - onViewRemoved(view); + dispatchViewRemoved(view); } removeFromArray(start, count); @@ -4729,7 +4743,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager childHasTransientStateChanged(view, false); } - onViewRemoved(view); + dispatchViewRemoved(view); view.mParent = null; children[i] = null; @@ -4788,7 +4802,7 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager childHasTransientStateChanged(child, false); } - onViewRemoved(child); + dispatchViewRemoved(child); } /** diff --git a/core/java/android/view/accessibility/AccessibilityInteractionClient.java b/core/java/android/view/accessibility/AccessibilityInteractionClient.java index db78ec5..b49cbc6 100644 --- a/core/java/android/view/accessibility/AccessibilityInteractionClient.java +++ b/core/java/android/view/accessibility/AccessibilityInteractionClient.java @@ -186,7 +186,9 @@ public final class AccessibilityInteractionClient if (DEBUG) { Log.i(LOG_TAG, "Window cache miss"); } + final long identityToken = Binder.clearCallingIdentity(); window = connection.getWindow(accessibilityWindowId); + Binder.restoreCallingIdentity(identityToken); if (window != null) { sAccessibilityCache.addWindow(window); return window; @@ -222,7 +224,9 @@ public final class AccessibilityInteractionClient if (DEBUG) { Log.i(LOG_TAG, "Windows cache miss"); } + final long identityToken = Binder.clearCallingIdentity(); windows = connection.getWindows(); + Binder.restoreCallingIdentity(identityToken); if (windows != null) { final int windowCount = windows.size(); for (int i = 0; i < windowCount; i++) { @@ -282,9 +286,11 @@ public final class AccessibilityInteractionClient } } final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.findAccessibilityNodeInfoByAccessibilityId( accessibilityWindowId, accessibilityNodeId, interactionId, this, prefetchFlags, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); // If the scale is zero the call has failed. if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( @@ -328,9 +334,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.findAccessibilityNodeInfosByViewId( accessibilityWindowId, accessibilityNodeId, viewId, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); @@ -374,9 +382,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.findAccessibilityNodeInfosByText( accessibilityWindowId, accessibilityNodeId, text, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { List<AccessibilityNodeInfo> infos = getFindAccessibilityNodeInfosResultAndClear( interactionId); @@ -419,9 +429,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.findFocus(accessibilityWindowId, accessibilityNodeId, focusType, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); @@ -461,9 +473,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.focusSearch(accessibilityWindowId, accessibilityNodeId, direction, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { AccessibilityNodeInfo info = getFindAccessibilityNodeInfoResultAndClear( interactionId); @@ -502,9 +516,11 @@ public final class AccessibilityInteractionClient IAccessibilityServiceConnection connection = getConnection(connectionId); if (connection != null) { final int interactionId = mInteractionIdCounter.getAndIncrement(); + final long identityToken = Binder.clearCallingIdentity(); final boolean success = connection.performAccessibilityAction( accessibilityWindowId, accessibilityNodeId, action, arguments, interactionId, this, Thread.currentThread().getId()); + Binder.restoreCallingIdentity(identityToken); if (success) { return getPerformAccessibilityActionResultAndClear(interactionId); } diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 0001860..a96bf71 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -3113,9 +3113,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } private boolean performStylusButtonPressAction(MotionEvent ev) { - if (ev.getToolType(0) == MotionEvent.TOOL_TYPE_STYLUS - && ev.isButtonPressed(MotionEvent.BUTTON_SECONDARY) - && mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) { + if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL && mChoiceActionMode == null) { final View child = getChildAt(mMotionPosition - mFirstPosition); if (child != null) { final int longPressPosition = mMotionPosition; @@ -3785,7 +3783,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } if (mTouchMode == TOUCH_MODE_DOWN && mMotionPosition != INVALID_POSITION - && (performButtonActionOnTouchDown(ev) || performStylusButtonPressAction(ev))) { + && performButtonActionOnTouchDown(ev)) { removeCallbacks(mPendingCheckForTap); } } @@ -3828,11 +3826,6 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mTouchMode = TOUCH_MODE_DONE_WAITING; updateSelectorState(); } else if (motionView != null) { - if (performStylusButtonPressAction(ev)) { - removeCallbacks(mPendingCheckForTap); - removeCallbacks(mPendingCheckForLongPress); - } - // Still within bounds, update the hotspot. final float[] point = mTmpPoint; point[0] = x; @@ -4072,7 +4065,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te public boolean onGenericMotionEvent(MotionEvent event) { if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { switch (event.getAction()) { - case MotionEvent.ACTION_SCROLL: { + case MotionEvent.ACTION_SCROLL: if (mTouchMode == TOUCH_MODE_REST) { final float vscroll = event.getAxisValue(MotionEvent.AXIS_VSCROLL); if (vscroll != 0) { @@ -4082,9 +4075,22 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } } } - } + break; + + case MotionEvent.ACTION_BUTTON_PRESS: + int actionButton = event.getActionButton(); + if ((actionButton == MotionEvent.BUTTON_STYLUS_PRIMARY + || actionButton == MotionEvent.BUTTON_SECONDARY) + && (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP)) { + if (performStylusButtonPressAction(event)) { + removeCallbacks(mPendingCheckForLongPress); + removeCallbacks(mPendingCheckForTap); + } + } + break; } } + return super.onGenericMotionEvent(event); } @@ -6575,13 +6581,14 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te * @return A view from the ScrapViews collection. These are unordered. */ View getScrapView(int position) { + final int whichScrap = mAdapter.getItemViewType(position); + if (whichScrap < 0) { + return null; + } if (mViewTypeCount == 1) { return retrieveFromScrap(mCurrentScrap, position); - } else { - final int whichScrap = mAdapter.getItemViewType(position); - if (whichScrap >= 0 && whichScrap < mScrapViews.length) { - return retrieveFromScrap(mScrapViews[whichScrap], position); - } + } else if (whichScrap < mScrapViews.length) { + return retrieveFromScrap(mScrapViews[whichScrap], position); } return null; } diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java index 2c98961..9ca59f1 100644 --- a/core/java/android/widget/Editor.java +++ b/core/java/android/widget/Editor.java @@ -3568,13 +3568,24 @@ public class Editor { } protected void updateDrawable() { + if (mIsDragging) { + // Don't update drawable during dragging. + return; + } final int offset = getCurrentCursorOffset(); final boolean isRtlCharAtOffset = mTextView.getLayout().isRtlCharAt(offset); final Drawable oldDrawable = mDrawable; mDrawable = isRtlCharAtOffset ? mDrawableRtl : mDrawableLtr; mHotspotX = getHotspotX(mDrawable, isRtlCharAtOffset); mHorizontalGravity = getHorizontalGravity(isRtlCharAtOffset); - if (oldDrawable != mDrawable) { + final Layout layout = mTextView.getLayout(); + if (layout != null && oldDrawable != mDrawable && isShowing()) { + // Update popup window position. + mPositionX = (int) (layout.getPrimaryHorizontal(offset) - 0.5f - mHotspotX - + getHorizontalOffset() + getCursorOffset()); + mPositionX += mTextView.viewportToContentHorizontalOffset(); + mPositionHasChanged = true; + updatePosition(mLastParentX, mLastParentY, false, false); postInvalidate(); } } @@ -3848,10 +3859,12 @@ public class Editor { case MotionEvent.ACTION_UP: filterOnTouchUp(); mIsDragging = false; + updateDrawable(); break; case MotionEvent.ACTION_CANCEL: mIsDragging = false; + updateDrawable(); break; } return true; @@ -4013,7 +4026,15 @@ public class Editor { @Override public void updatePosition(float x, float y) { - positionAtCursorOffset(mTextView.getOffsetForPosition(x, y), false); + Layout layout = mTextView.getLayout(); + int offset; + if (layout != null) { + int currLine = getCurrentLineAdjustedForSlop(layout, mPrevLine, y); + offset = mTextView.getOffsetAtCoordinate(currLine, x); + } else { + offset = mTextView.getOffsetForPosition(x, y); + } + positionAtCursorOffset(offset, false); if (mTextActionMode != null) { mTextActionMode.invalidate(); } @@ -4136,6 +4157,11 @@ public class Editor { offset = adjustedOffset; } positionCursor = true; + } else if (adjustedOffset < mPreviousOffset) { + // Handle has jumped to the start of the word, and the user is moving + // their finger towards the handle, the delta should be updated. + mTouchWordDelta = mTextView.convertToLocalHorizontalCoordinate(x) + - layout.getPrimaryHorizontal(mPreviousOffset); } } @@ -4270,6 +4296,11 @@ public class Editor { offset = adjustedOffset; } positionCursor = true; + } else if (adjustedOffset > mPreviousOffset) { + // Handle has jumped to the end of the word, and the user is moving + // their finger towards the handle, the delta should be updated. + mTouchWordDelta = layout.getPrimaryHorizontal(mPreviousOffset) + - mTextView.convertToLocalHorizontalCoordinate(x); } } @@ -4413,6 +4444,10 @@ public class Editor { // Indicates whether the user is selecting text and using the drag accelerator. private boolean mDragAcceleratorActive; private boolean mHaventMovedEnoughToStartDrag; + // The line that a selection happened most recently with the drag accelerator. + private int mLineSelectionIsOn = -1; + // Whether the drag accelerator has selected past the initial line. + private boolean mSwitchedLines = false; SelectionModifierCursorController() { resetTouchOffsets(); @@ -4465,6 +4500,7 @@ public class Editor { // Start location of selection. mStartOffset = mTextView.getOffsetForPosition(mLastDownPositionX, mLastDownPositionY); + mLineSelectionIsOn = mTextView.getLineAtCoordinate(mLastDownPositionY); // Don't show the handles until user has lifted finger. hide(); @@ -4548,17 +4584,35 @@ public class Editor { break; } - if (mStartOffset != -1) { + if (mStartOffset != -1 && mTextView.getLayout() != null) { if (!mHaventMovedEnoughToStartDrag) { - // Offset the finger by the same vertical offset as the handles. This - // improves visibility of the content being selected by shifting - // the finger below the content. - final float fingerOffset = (mStartHandle != null) - ? mStartHandle.getIdealVerticalOffset() - : touchSlop; - int offset = - mTextView.getOffsetForPosition(eventX, eventY - fingerOffset); + + float y = eventY; + if (mSwitchedLines) { + // Offset the finger by the same vertical offset as the handles. + // This improves visibility of the content being selected by + // shifting the finger below the content, this is applied once + // the user has switched lines. + final float fingerOffset = (mStartHandle != null) + ? mStartHandle.getIdealVerticalOffset() + : touchSlop; + y = eventY - fingerOffset; + } + + final int currLine = getCurrentLineAdjustedForSlop( + mTextView.getLayout(), + mLineSelectionIsOn, y); + if (!mSwitchedLines && currLine != mLineSelectionIsOn) { + // Break early here, we want to offset the finger position from + // the selection highlight, once the user moved their finger + // to a different line we should apply the offset and *not* switch + // lines until recomputing the position with the finger offset. + mSwitchedLines = true; + break; + } + int startOffset; + int offset = mTextView.getOffsetAtCoordinate(currLine, eventX); // Snap to word boundaries. if (mStartOffset < offset) { // Expanding with end handle. @@ -4569,6 +4623,7 @@ public class Editor { offset = getWordStart(offset); startOffset = getWordEnd(mStartOffset); } + mLineSelectionIsOn = currLine; Selection.setSelection((Spannable) mTextView.getText(), startOffset, offset); } @@ -4605,6 +4660,7 @@ public class Editor { startSelectionActionMode(); mDragAcceleratorActive = false; mStartOffset = -1; + mSwitchedLines = false; } break; } @@ -4634,6 +4690,7 @@ public class Editor { mMinTouchOffset = mMaxTouchOffset = -1; mStartOffset = -1; mDragAcceleratorActive = false; + mSwitchedLines = false; } /** diff --git a/core/java/android/widget/GridLayout.java b/core/java/android/widget/GridLayout.java index 6cc4bda..258424a 100644 --- a/core/java/android/widget/GridLayout.java +++ b/core/java/android/widget/GridLayout.java @@ -935,22 +935,14 @@ public class GridLayout extends ViewGroup { super.onDebugDraw(canvas); } - // Add/remove - - /** - * @hide - */ @Override - protected void onViewAdded(View child) { + public void onViewAdded(View child) { super.onViewAdded(child); invalidateStructure(); } - /** - * @hide - */ @Override - protected void onViewRemoved(View child) { + public void onViewRemoved(View child) { super.onViewRemoved(child); invalidateStructure(); } diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index 6b28f89..e0b2395 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -216,7 +216,7 @@ public class ImageView extends View { protected boolean verifyDrawable(Drawable dr) { return mDrawable == dr || super.verifyDrawable(dr); } - + @Override public void jumpDrawablesToCurrentState() { super.jumpDrawablesToCurrentState(); @@ -226,6 +226,15 @@ public class ImageView extends View { @Override public void invalidateDrawable(Drawable dr) { if (dr == mDrawable) { + if (dr != null) { + // update cached drawable dimensions if they've changed + final int w = dr.getIntrinsicWidth(); + final int h = dr.getIntrinsicHeight(); + if (w != mDrawableWidth || h != mDrawableHeight) { + mDrawableWidth = w; + mDrawableHeight = h; + } + } /* we invalidate the whole view in this case because it's very * hard to know where the drawable actually is. This is made * complicated because of the offsets and transformations that diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java index affc5da..339038e 100644 --- a/core/java/android/widget/RelativeLayout.java +++ b/core/java/android/widget/RelativeLayout.java @@ -522,7 +522,7 @@ public class RelativeLayout extends ViewGroup { View baselineView = null; LayoutParams baselineParams = null; for (int i = 0; i < count; i++) { - final View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE) { final LayoutParams childParams = (LayoutParams) child.getLayoutParams(); if (baselineView == null || baselineParams == null @@ -548,9 +548,9 @@ public class RelativeLayout extends ViewGroup { if (offsetHorizontalAxis) { for (int i = 0; i < count; i++) { - View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE) { - LayoutParams params = (LayoutParams) child.getLayoutParams(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); final int[] rules = params.getRules(layoutDirection); if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_HORIZONTAL] != 0) { centerHorizontal(child, params, width); @@ -578,9 +578,9 @@ public class RelativeLayout extends ViewGroup { if (offsetVerticalAxis) { for (int i = 0; i < count; i++) { - View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE) { - LayoutParams params = (LayoutParams) child.getLayoutParams(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); final int[] rules = params.getRules(layoutDirection); if (rules[CENTER_IN_PARENT] != 0 || rules[CENTER_VERTICAL] != 0) { centerVertical(child, params, height); @@ -607,9 +607,9 @@ public class RelativeLayout extends ViewGroup { final int verticalOffset = contentBounds.top - top; if (horizontalOffset != 0 || verticalOffset != 0) { for (int i = 0; i < count; i++) { - View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE && child != ignore) { - LayoutParams params = (LayoutParams) child.getLayoutParams(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); if (horizontalGravity) { params.mLeft += horizontalOffset; params.mRight += horizontalOffset; @@ -626,9 +626,9 @@ public class RelativeLayout extends ViewGroup { if (isLayoutRtl()) { final int offsetWidth = myWidth - width; for (int i = 0; i < count; i++) { - View child = getChildAt(i); + final View child = views[i]; if (child.getVisibility() != GONE) { - LayoutParams params = (LayoutParams) child.getLayoutParams(); + final LayoutParams params = (LayoutParams) child.getLayoutParams(); params.mLeft -= offsetWidth; params.mRight -= offsetWidth; } diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 78b5d5d..c538dc2 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -241,8 +241,6 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; * @attr ref android.R.styleable#TextView_fontFeatureSettings * @attr ref android.R.styleable#TextView_breakStrategy * @attr ref android.R.styleable#TextView_hyphenationFrequency - * @attr ref android.R.styleable#TextView_leftIndents - * @attr ref android.R.styleable#TextView_rightIndents */ @RemoteView public class TextView extends View implements ViewTreeObserver.OnPreDrawListener { @@ -559,8 +557,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mBreakStrategy; private int mHyphenationFrequency; - private int[] mLeftIndents; - private int[] mRightIndents; private int mMaximum = Integer.MAX_VALUE; private int mMaxMode = LINES; @@ -1165,16 +1161,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener case com.android.internal.R.styleable.TextView_hyphenationFrequency: mHyphenationFrequency = a.getInt(attr, Layout.HYPHENATION_FREQUENCY_NONE); break; - - case com.android.internal.R.styleable.TextView_leftIndents: - TypedArray margins = res.obtainTypedArray(a.getResourceId(attr, View.NO_ID)); - mLeftIndents = parseDimensionArray(margins); - break; - - case com.android.internal.R.styleable.TextView_rightIndents: - margins = res.obtainTypedArray(a.getResourceId(attr, View.NO_ID)); - mRightIndents = parseDimensionArray(margins); - break; } } a.recycle(); @@ -3095,51 +3081,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } /** - * Set indents. Arguments are arrays holding an indent amount, one per line, measured in - * pixels. For lines past the last element in the array, the last element repeats. - * - * @param leftIndents array of indent values for left margin, in pixels - * @param rightIndents array of indent values for right margin, in pixels - * - * @see #getLeftIndents() - * @see #getRightIndents() - * - * @attr ref android.R.styleable#TextView_leftIndents - * @attr ref android.R.styleable#TextView_rightIndents - */ - public void setIndents(@Nullable int[] leftIndents, @Nullable int[] rightIndents) { - mLeftIndents = leftIndents; - mRightIndents = rightIndents; - if (mLayout != null) { - nullLayouts(); - requestLayout(); - invalidate(); - } - } - - /** - * Get left indents. See {#link setMargins} for more details. - * - * @return left indents - * @see #setIndents(int[], int[]) - * @attr ref android.R.styleable#TextView_leftIndents - */ - public int[] getLeftIndents() { - return mLeftIndents; - } - - /** - * Get right indents. See {#link setMargins} for more details. - * - * @return right indents - * @see #setIndents(int[], int[]) - * @attr ref android.R.styleable#TextView_rightIndents - */ - public int[] getRightIndents() { - return mRightIndents; - } - - /** * Sets font feature settings. The format is the same as the CSS * font-feature-settings attribute: * http://dev.w3.org/csswg/css-fonts/#propdef-font-feature-settings @@ -6685,9 +6626,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) .setHyphenationFrequency(mHyphenationFrequency); - if (mLeftIndents != null || mRightIndents != null) { - builder.setIndents(mLeftIndents, mRightIndents); - } if (shouldEllipsize) { builder.setEllipsize(mEllipsize) .setEllipsizedWidth(ellipsisWidth) @@ -6776,9 +6714,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener .setIncludePad(mIncludePad) .setBreakStrategy(mBreakStrategy) .setHyphenationFrequency(mHyphenationFrequency); - if (mLeftIndents != null || mRightIndents != null) { - builder.setIndents(mLeftIndents, mRightIndents); - } if (shouldEllipsize) { builder.setEllipsize(effectiveEllipsize) .setEllipsizedWidth(ellipsisWidth) diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java index 2ea2667..471ea9b 100644 --- a/core/java/android/widget/Toolbar.java +++ b/core/java/android/widget/Toolbar.java @@ -273,6 +273,24 @@ public class Toolbar extends ViewGroup { if (!TextUtils.isEmpty(navDesc)) { setNavigationContentDescription(navDesc); } + + final Drawable logo = a.getDrawable(R.styleable.Toolbar_logo); + if (logo != null) { + setLogo(logo); + } + + final CharSequence logoDesc = a.getText(R.styleable.Toolbar_logoDescription); + if (!TextUtils.isEmpty(logoDesc)) { + setLogoDescription(logoDesc); + } + + if (a.hasValue(R.styleable.Toolbar_titleTextColor)) { + setTitleTextColor(a.getColor(R.styleable.Toolbar_titleTextColor, 0xffffffff)); + } + + if (a.hasValue(R.styleable.Toolbar_subtitleTextColor)) { + setSubtitleTextColor(a.getColor(R.styleable.Toolbar_subtitleTextColor, 0xffffffff)); + } a.recycle(); } diff --git a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl index 7d3db02..5a195cb 100644 --- a/core/java/com/android/internal/appwidget/IAppWidgetService.aidl +++ b/core/java/com/android/internal/appwidget/IAppWidgetService.aidl @@ -20,6 +20,7 @@ import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; import android.content.pm.ApplicationInfo; +import android.content.pm.ParceledListSlice; import android.appwidget.AppWidgetProviderInfo; import com.android.internal.appwidget.IAppWidgetHost; import android.os.Bundle; @@ -54,7 +55,7 @@ interface IAppWidgetService { in RemoteViews views); void updateAppWidgetProvider(in ComponentName provider, in RemoteViews views); void notifyAppWidgetViewDataChanged(String packageName, in int[] appWidgetIds, int viewId); - List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, + ParceledListSlice getInstalledProvidersForProfile(int categoryFilter, int profileId); AppWidgetProviderInfo getAppWidgetInfo(String callingPackage, int appWidgetId); boolean hasBindAppWidgetPermission(in String packageName, int userId); diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java index 230d96d..03f2e3a 100644 --- a/core/java/com/android/internal/logging/MetricsLogger.java +++ b/core/java/com/android/internal/logging/MetricsLogger.java @@ -26,6 +26,13 @@ import android.view.View; * @hide */ public class MetricsLogger implements MetricsConstants { + public static final int VOLUME_DIALOG = 207; + public static final int VOLUME_DIALOG_DETAILS = 208; + public static final int ACTION_VOLUME_SLIDER = 209; + public static final int ACTION_VOLUME_STREAM = 210; + public static final int ACTION_VOLUME_KEY = 211; + public static final int ACTION_VOLUME_ICON = 212; + public static final int ACTION_RINGER_MODE = 213; // Temporary constants go here, to await migration to MetricsConstants. public static void visible(Context context, int category) throws IllegalArgumentException { diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java index 294e4ba..66f6079 100644 --- a/core/java/com/android/internal/policy/PhoneWindow.java +++ b/core/java/com/android/internal/policy/PhoneWindow.java @@ -390,6 +390,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { mLayoutInflater.inflate(layoutResID, mContentParent); } + mContentParent.requestApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); @@ -419,6 +420,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { } else { mContentParent.addView(view, params); } + mContentParent.requestApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); @@ -435,6 +437,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { Log.v(TAG, "addContentView does not support content transitions"); } mContentParent.addView(view, params); + mContentParent.requestApplyInsets(); final Callback cb = getCallback(); if (cb != null && !isDestroyed()) { cb.onContentChanged(); diff --git a/core/java/com/android/internal/statusbar/StatusBarIcon.java b/core/java/com/android/internal/statusbar/StatusBarIcon.java index 4693d4b..1d62623 100644 --- a/core/java/com/android/internal/statusbar/StatusBarIcon.java +++ b/core/java/com/android/internal/statusbar/StatusBarIcon.java @@ -20,17 +20,27 @@ import android.graphics.drawable.Icon; import android.os.Parcel; import android.os.Parcelable; import android.os.UserHandle; +import android.text.TextUtils; public class StatusBarIcon implements Parcelable { public UserHandle user; + public String pkg; public Icon icon; public int iconLevel; public boolean visible = true; public int number; public CharSequence contentDescription; - public StatusBarIcon(UserHandle user, Icon icon, int iconLevel, int number, + public StatusBarIcon(UserHandle user, String resPackage, Icon icon, int iconLevel, int number, CharSequence contentDescription) { + if (icon.getType() == Icon.TYPE_RESOURCE + && TextUtils.isEmpty(icon.getResPackage())) { + // This is an odd situation where someone's managed to hand us an icon without a + // package inside, probably by mashing an int res into a Notification object. + // Now that we have the correct package name handy, let's fix it. + icon = Icon.createWithResource(resPackage, icon.getResId()); + } + this.pkg = resPackage; this.user = user; this.icon = icon; this.iconLevel = iconLevel; @@ -41,21 +51,23 @@ public class StatusBarIcon implements Parcelable { public StatusBarIcon(String iconPackage, UserHandle user, int iconId, int iconLevel, int number, CharSequence contentDescription) { - this(user, Icon.createWithResource(iconPackage, iconId), + this(user, iconPackage, Icon.createWithResource(iconPackage, iconId), iconLevel, number, contentDescription); } @Override public String toString() { - return "StatusBarIcon(icon=" + this.icon + return "StatusBarIcon(icon=" + icon + + ((iconLevel != 0)?(" level=" + iconLevel):"") + + (visible?" visible":"") + " user=" + user.getIdentifier() - + " level=" + this.iconLevel + " visible=" + visible - + " num=" + this.number + " )"; + + ((number != 0)?(" num=" + number):"") + + " )"; } @Override public StatusBarIcon clone() { - StatusBarIcon that = new StatusBarIcon(this.user, this.icon, + StatusBarIcon that = new StatusBarIcon(this.user, this.pkg, this.icon, this.iconLevel, this.number, this.contentDescription); that.visible = this.visible; return that; @@ -70,6 +82,7 @@ public class StatusBarIcon implements Parcelable { public void readFromParcel(Parcel in) { this.icon = (Icon) in.readParcelable(null); + this.pkg = in.readString(); this.user = (UserHandle) in.readParcelable(null); this.iconLevel = in.readInt(); this.visible = in.readInt() != 0; @@ -79,6 +92,7 @@ public class StatusBarIcon implements Parcelable { public void writeToParcel(Parcel out, int flags) { out.writeParcelable(this.icon, 0); + out.writeString(this.pkg); out.writeParcelable(this.user, 0); out.writeInt(this.iconLevel); out.writeInt(this.visible ? 1 : 0); diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java index 99c1277..784b256 100644 --- a/core/java/com/android/internal/view/FloatingActionMode.java +++ b/core/java/com/android/internal/view/FloatingActionMode.java @@ -25,6 +25,7 @@ import android.view.MenuItem; import android.view.View; import android.view.ViewConfiguration; +import com.android.internal.R; import com.android.internal.util.Preconditions; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.widget.FloatingToolbar; @@ -44,6 +45,7 @@ public class FloatingActionMode extends ActionMode { private final Rect mViewRect; private final Rect mScreenRect; private final View mOriginatingView; + private final int mBottomAllowance; private final Runnable mMovingOff = new Runnable() { public void run() { @@ -77,6 +79,10 @@ public class FloatingActionMode extends ActionMode { mScreenRect = new Rect(); mOriginatingView = Preconditions.checkNotNull(originatingView); mOriginatingView.getLocationInWindow(mViewPosition); + // Allow the content rect to overshoot a little bit beyond the + // bottom view bound if necessary. + mBottomAllowance = context.getResources() + .getDimensionPixelSize(R.dimen.content_rect_bottom_clip_allowance); } public void setFloatingToolbar(FloatingToolbar floatingToolbar) { @@ -141,7 +147,7 @@ public class FloatingActionMode extends ActionMode { Math.max(mContentRectOnWindow.left, mViewRect.left), Math.max(mContentRectOnWindow.top, mViewRect.top), Math.min(mContentRectOnWindow.right, mViewRect.right), - Math.min(mContentRectOnWindow.bottom, mViewRect.bottom)); + Math.min(mContentRectOnWindow.bottom, mViewRect.bottom + mBottomAllowance)); if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) { // Content rect is moving. diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java index 53ebc23..65f2f53f 100644 --- a/core/java/com/android/internal/widget/FloatingToolbar.java +++ b/core/java/com/android/internal/widget/FloatingToolbar.java @@ -20,7 +20,9 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.content.ComponentCallbacks; import android.content.Context; +import android.content.res.Configuration; import android.graphics.Color; import android.graphics.Point; import android.graphics.Rect; @@ -89,6 +91,19 @@ public final class FloatingToolbar { private int mSuggestedWidth; private boolean mWidthChanged = true; + private final ComponentCallbacks mOrientationChangeHandler = new ComponentCallbacks() { + @Override + public void onConfigurationChanged(Configuration newConfig) { + if (mPopup.isShowing() && mPopup.viewPortHasChanged()) { + mWidthChanged = true; + updateLayout(); + } + } + + @Override + public void onLowMemory() {} + }; + /** * Initializes a floating toolbar. */ @@ -151,6 +166,8 @@ public final class FloatingToolbar { * Shows this floating toolbar. */ public FloatingToolbar show() { + mContext.unregisterComponentCallbacks(mOrientationChangeHandler); + mContext.registerComponentCallbacks(mOrientationChangeHandler); List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu); if (!isCurrentlyShowing(menuItems) || mWidthChanged) { mPopup.dismiss(); @@ -181,6 +198,7 @@ public final class FloatingToolbar { * Dismisses this floating toolbar. */ public void dismiss() { + mContext.unregisterComponentCallbacks(mOrientationChangeHandler); mPopup.dismiss(); } @@ -329,6 +347,7 @@ public final class FloatingToolbar { private final Rect mViewPort = new Rect(); private final Point mCoords = new Point(); + private final Rect mTmpRect = new Rect(); private final Region mTouchableRegion = new Region(); private final ViewTreeObserver.OnComputeInternalInsetsListener mInsetsComputer = @@ -873,6 +892,11 @@ public final class FloatingToolbar { mParent.getWindowVisibleDisplayFrame(mViewPort); } + private boolean viewPortHasChanged() { + mParent.getWindowVisibleDisplayFrame(mTmpRect); + return !mTmpRect.equals(mViewPort); + } + private int getToolbarWidth(int suggestedWidth) { int width = suggestedWidth; refreshViewPort(); diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp index 3bab2df..e99bdfc 100644 --- a/core/jni/android/graphics/Region.cpp +++ b/core/jni/android/graphics/Region.cpp @@ -231,15 +231,24 @@ static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHandle, jobject parcel) { const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); - if (parcel == NULL) { + if (parcel == nullptr) { return JNI_FALSE; } android::Parcel* p = android::parcelForJavaObject(env, parcel); - size_t size = region->writeToMemory(NULL); + const size_t size = region->writeToMemory(nullptr); p->writeInt32(size); - region->writeToMemory(p->writeInplace(size)); + void* dst = p->writeInplace(size); + if (dst == nullptr) { + ALOGE("Region.writeToParcel could not write %zi bytes", size); + return JNI_FALSE; + } + const size_t sizeWritten = region->writeToMemory(dst); + if (sizeWritten != size) { + ALOGE("SkRegion::writeToMemory should have written %zi bytes but wrote %zi", + size, sizeWritten); + } return JNI_TRUE; } diff --git a/core/jni/android_media_AudioFormat.h b/core/jni/android_media_AudioFormat.h index 5144457..bb13c35 100644 --- a/core/jni/android_media_AudioFormat.h +++ b/core/jni/android_media_AudioFormat.h @@ -80,6 +80,13 @@ static inline int audioFormatFromNative(audio_format_t nativeFormat) return ENCODING_PCM_8BIT; case AUDIO_FORMAT_PCM_FLOAT: return ENCODING_PCM_FLOAT; + + // map these to ENCODING_PCM_FLOAT + case AUDIO_FORMAT_PCM_8_24_BIT: + case AUDIO_FORMAT_PCM_24_BIT_PACKED: + case AUDIO_FORMAT_PCM_32_BIT: + return ENCODING_PCM_FLOAT; + case AUDIO_FORMAT_AC3: return ENCODING_AC3; case AUDIO_FORMAT_E_AC3: diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp index ac00532..9f2181f 100644 --- a/core/jni/android_media_AudioSystem.cpp +++ b/core/jni/android_media_AudioSystem.cpp @@ -832,6 +832,15 @@ exit: return jStatus; } +static bool hasFormat(int* formats, size_t size, int format) { + for (size_t index = 0; index < size; index++) { + if (formats[index] == format) { + return true; // found + } + } + return false; // not found +} + static jint convertAudioPortFromNative(JNIEnv *env, jobject *jAudioPort, const struct audio_port *nAudioPort) { @@ -839,6 +848,7 @@ static jint convertAudioPortFromNative(JNIEnv *env, jintArray jSamplingRates = NULL; jintArray jChannelMasks = NULL; jintArray jChannelIndexMasks = NULL; + int* cFormats = NULL; jintArray jFormats = NULL; jobjectArray jGains = NULL; jobject jHandle = NULL; @@ -846,7 +856,7 @@ static jint convertAudioPortFromNative(JNIEnv *env, bool useInMask; size_t numPositionMasks = 0; size_t numIndexMasks = 0; - + size_t numUniqueFormats; ALOGV("convertAudioPortFromNative id %d role %d type %d name %s", nAudioPort->id, nAudioPort->role, nAudioPort->type, nAudioPort->name); @@ -897,15 +907,20 @@ static jint convertAudioPortFromNative(JNIEnv *env, } // formats - jFormats = env->NewIntArray(nAudioPort->num_formats); + cFormats = new int[nAudioPort->num_formats]; + numUniqueFormats = 0; + for (size_t index = 0; index < nAudioPort->num_formats; index++) { + int format = audioFormatFromNative(nAudioPort->formats[index]); + if (!hasFormat(cFormats, numUniqueFormats, format)) { + cFormats[numUniqueFormats++] = format; + } + } + jFormats = env->NewIntArray(numUniqueFormats); if (jFormats == NULL) { jStatus = (jint)AUDIO_JAVA_ERROR; goto exit; } - for (size_t j = 0; j < nAudioPort->num_formats; j++) { - jint jFormat = audioFormatFromNative(nAudioPort->formats[j]); - env->SetIntArrayRegion(jFormats, j, 1, &jFormat); - } + env->SetIntArrayRegion(jFormats, 0, numUniqueFormats, cFormats); // gains jGains = env->NewObjectArray(nAudioPort->num_gains, @@ -1000,6 +1015,12 @@ exit: if (jChannelMasks != NULL) { env->DeleteLocalRef(jChannelMasks); } + if (jChannelIndexMasks != NULL) { + env->DeleteLocalRef(jChannelIndexMasks); + } + if (cFormats != NULL) { + delete[] cFormats; + } if (jFormats != NULL) { env->DeleteLocalRef(jFormats); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 65c064b..f197597 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -316,8 +316,6 @@ <protected-broadcast android:name="android.intent.action.ACTION_SET_RADIO_CAPABILITY_FAILED" /> <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" /> - <protected-broadcast android:name="android.service.persistentdata.action.WIPE_IF_ALLOWED" /> - <protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" /> <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> diff --git a/core/res/res/drawable/control_background_32dp_material.xml b/core/res/res/drawable/control_background_32dp_material.xml new file mode 100644 index 0000000..1628734 --- /dev/null +++ b/core/res/res/drawable/control_background_32dp_material.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<ripple xmlns:android="http://schemas.android.com/apk/res/android" + android:color="@color/control_highlight_material" + android:radius="16dp" /> diff --git a/core/res/res/drawable/control_background_material.xml b/core/res/res/drawable/control_background_40dp_material.xml index 7b78349..0e82ace 100644 --- a/core/res/res/drawable/control_background_material.xml +++ b/core/res/res/drawable/control_background_40dp_material.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2014 The Android Open Source Project +<!-- Copyright (C) 2015 The Android Open Source Project Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/core/res/res/drawable/seekbar_track_material.xml b/core/res/res/drawable/seekbar_track_material.xml index 6e40c48..01eb243 100644 --- a/core/res/res/drawable/seekbar_track_material.xml +++ b/core/res/res/drawable/seekbar_track_material.xml @@ -20,7 +20,7 @@ <shape android:shape="rectangle" android:tint="?attr/colorControlNormal"> <size android:height="@dimen/seekbar_track_background_height_material" /> - <solid android:color="#ff000000" /> + <solid android:color="@color/white_disabled_material" /> </shape> </item> <item android:id="@id/secondaryProgress" diff --git a/core/res/res/drawable/spinner_background_material.xml b/core/res/res/drawable/spinner_background_material.xml index 892dbc5..d37f5b7 100644 --- a/core/res/res/drawable/spinner_background_material.xml +++ b/core/res/res/drawable/spinner_background_material.xml @@ -17,22 +17,18 @@ <layer-list xmlns:android="http://schemas.android.com/apk/res/android" android:paddingMode="stack" android:paddingStart="0dp" - android:paddingEnd="48dp" + android:paddingEnd="24dp" android:paddingLeft="0dp" android:paddingRight="0dp"> <item android:gravity="end|center_vertical" - android:width="48dp" - android:height="48dp"> - <ripple - android:color="?attr/colorControlHighlight" - android:radius="24dp" /> - </item> + android:width="24dp" + android:height="24dp" + android:drawable="@drawable/control_background_40dp_material" /> <item android:drawable="@drawable/ic_spinner_caret" android:gravity="end|center_vertical" android:width="24dp" - android:height="24dp" - android:end="12dp" /> + android:height="24dp" /> </layer-list> diff --git a/core/res/res/values-mcc302-mnc220/config.xml b/core/res/res/values-mcc302-mnc220/config.xml index 9147cbf..09a63aa 100644 --- a/core/res/res/values-mcc302-mnc220/config.xml +++ b/core/res/res/values-mcc302-mnc220/config.xml @@ -38,7 +38,8 @@ note that empty fields can be ommitted: "name,apn,,,,,,,,,310,260,,DUN" --> <string-array translatable="false" name="config_tether_apndata"> <item>[ApnSettingV3]TELUS ISP,isp.telus.com,,,,,,,,,302,220,,DUN,,,true,0,,,,,,,gid,54</item> - <item>[ApnSettingV3]Tethered PC Mobile,isp.mb.com,,,,,,,,,302,220,,DUN,,,true,0,,,,,,,gid,50</item> + <item>[ApnSettingV3]Tethered Mobile Internet,isp.mb.com,,,,,,,,,302,220,,DUN,,,true,0,,,,,,,gid,50</item> + <item>[ApnSettingV3]Tethered Public Mobile,isp.mb.com,,,,,,,,,302,220,,DUN,,,true,0,,,,,,,gid,4D4F</item> </string-array> </resources> diff --git a/core/res/res/values-mcc302-mnc720/config.xml b/core/res/res/values-mcc302-mnc720/config.xml index a83107a..dcfa5c5 100644 --- a/core/res/res/values-mcc302-mnc720/config.xml +++ b/core/res/res/values-mcc302-mnc720/config.xml @@ -29,6 +29,8 @@ <string-array translatable="false" name="config_tether_apndata"> <item>Rogers LTE Tethering,ltedata.apn,,,,,,,,,302,720,,DUN</item> <item>[ApnSettingV3]chatr Tethering,chatrisp.apn,,,,,,,,,302,720,,DUN,,,true,0,,,,,,,imsi,302720x94</item> + <item>[ApnSettingV3]Tbaytel Tethering,ltedata.apn,,,,,,,,,302,720,,DUN,IPV4V6,IP,true,0,,,,,,,gid,BA</item> + <item>[ApnSettingV3]Cityfone Tethering,ltedata.apn,,,,,,,,,302,720,,DUN,IPV4V6,IP,true,0,,,,,,,spn,CITYFONE</item> </string-array> <!-- Configure mobile network MTU. Carrier specific value is set here. diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index c08d511..33c9c60 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -4384,7 +4384,7 @@ i <enum name="simple" value="0" /> <!-- Line breaking uses high-quality strategy, including hyphenation. --> <enum name="high_quality" value="1" /> - <!-- Line breaking stratgegy balances line lengths. --> + <!-- Line breaking strategy balances line lengths. --> <enum name="balanced" value="2" /> </attr> <!-- Frequency of automatic hyphenation. --> @@ -4398,10 +4398,10 @@ i screens with limited space for text. --> <enum name="full" value="2" /> </attr> - <!-- Array of indents, one dimension value per line, left side. --> - <attr name="leftIndents" format="reference" /> - <!-- Array of indents, one dimension value per line, right side. --> - <attr name="rightIndents" format="reference" /> + <!-- Placeholder for a deleted attribute. This should be removed before M release. --> + <attr name="__removeBeforeMRelease_leftIndents" format="reference" /> + <!-- Placeholder for a deleted attribute. This should be removed before M release. --> + <attr name="__removeBeforeMRelease_rightIndents" format="reference" /> </declare-styleable> <declare-styleable name="TextViewAppearance"> <!-- Base text color, typeface, size, and style. --> @@ -7775,6 +7775,16 @@ i <!-- Text to set as the content description for the navigation button located at the start of the toolbar. --> <attr name="navigationContentDescription" format="string" /> + <!-- Drawable to set as the logo that appears at the starting side of + the Toolbar, just after the navigation button. --> + <attr name="logo" /> + <!-- A content description string to describe the appearance of the + associated logo image. --> + <attr name="logoDescription" format="string" /> + <!-- A color to apply to the title string. --> + <attr name="titleTextColor" format="color" /> + <!-- A color to apply to the subtitle string. --> + <attr name="subtitleTextColor" format="color" /> </declare-styleable> <declare-styleable name="Toolbar_LayoutParams"> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index e60a48d..7e74680 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -399,6 +399,7 @@ <dimen name="floating_toolbar_maximum_overflow_height">192dp</dimen> <dimen name="floating_toolbar_horizontal_margin">16dp</dimen> <dimen name="floating_toolbar_vertical_margin">8dp</dimen> + <dimen name="content_rect_bottom_clip_allowance">20dp</dimen> <dimen name="chooser_grid_padding">0dp</dimen> </resources> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index bbe27a4..65fa36b 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -2683,8 +2683,9 @@ <public type="attr" name="lockTaskMode" /> - <public type="attr" name="leftIndents" /> - <public type="attr" name="rightIndents" /> + <!-- Placeholder for a removed attribute. Remove this before M release. --> + <public type="attr" name="__removeBeforeMRelease_leftIndents" /> + <public type="attr" name="__removeBeforeMRelease_rightIndents" /> <public type="attr" name="showForAllUsers" /> @@ -2699,4 +2700,7 @@ <public type="attr" name="scrollIndicators" /> <public type="attr" name="hyphenationFrequency" /> <public type="attr" name="fingerprintAuthDrawable" /> + <public type="attr" name="logoDescription" /> + <public type="attr" name="titleTextColor" /> + <public type="attr" name="subtitleTextColor" /> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 510f6a5..ea0d349 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -537,10 +537,10 @@ <!-- Label for the Android system components when they are shown to the user. --> <string name="android_system_label">Android System</string> - <!-- Label for the user owner in the intent forwarding app. --> - <string name="user_owner_label">Personal apps</string> + <!-- Label for the user owner in the intent forwarding app. [CHAR LIMIT=15] --> + <string name="user_owner_label">Personal</string> - <!-- Label for a corporate profile in the intent forwarding app. --> + <!-- Label for a corporate profile in the intent forwarding app. [CHAR LIMIT=15] --> <string name="managed_profile_label">Work</string> <!-- Title of a category of application permissions, listed so the user can choose whether they want to allow the application to do this. --> diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml index 70f9c02..1b9c409 100644 --- a/core/res/res/values/styles_material.xml +++ b/core/res/res/values/styles_material.xml @@ -574,16 +574,16 @@ please see styles_device_defaults.xml. <style name="Widget.Material.CompoundButton" parent="Widget.CompoundButton"/> <style name="Widget.Material.CompoundButton.CheckBox" parent="Widget.CompoundButton.CheckBox"> - <item name="background">@drawable/control_background_material</item> + <item name="background">@drawable/control_background_40dp_material</item> </style> <style name="Widget.Material.CompoundButton.RadioButton" parent="Widget.CompoundButton.RadioButton"> - <item name="background">@drawable/control_background_material</item> + <item name="background">@drawable/control_background_40dp_material</item> </style> <style name="Widget.Material.CompoundButton.Star" parent="Widget.CompoundButton.Star"> <item name="button">@drawable/btn_star_material</item> - <item name="background">@drawable/control_background_material</item> + <item name="background">@drawable/control_background_40dp_material</item> </style> <style name="Widget.Material.CompoundButton.Switch"> @@ -592,7 +592,7 @@ please see styles_device_defaults.xml. <item name="switchTextAppearance">@style/TextAppearance.Material.Widget.Switch</item> <item name="textOn">@string/capital_on</item> <item name="textOff">@string/capital_off</item> - <item name="background">@drawable/control_background_material</item> + <item name="background">@drawable/control_background_40dp_material</item> <item name="showText">false</item> </style> @@ -730,7 +730,7 @@ please see styles_device_defaults.xml. <item name="paddingStart">16dip</item> <item name="paddingEnd">16dip</item> <item name="mirrorForRtl">true</item> - <item name="background">@drawable/control_background_material</item> + <item name="background">@drawable/control_background_32dp_material</item> </style> <style name="Widget.Material.RatingBar" parent="Widget.RatingBar"> @@ -812,7 +812,7 @@ please see styles_device_defaults.xml. </style> <style name="Widget.Material.Toolbar.Button.Navigation" parent="Widget.Material"> - <item name="background">@drawable/control_background_material</item> + <item name="background">@drawable/control_background_40dp_material</item> <item name="minWidth">56dp</item> <item name="scaleType">center</item> <item name="paddingStart">@dimen/action_bar_navigation_padding_start_material</item> @@ -869,7 +869,7 @@ please see styles_device_defaults.xml. </style> <style name="Widget.Material.ActionButton.CloseMode"> - <item name="background">@drawable/control_background_material</item> + <item name="background">@drawable/control_background_40dp_material</item> <!-- Should match Widget.Material.Toolbar.Button.Navigation minWidth. --> <item name="minWidth">56dp</item> </style> @@ -967,7 +967,7 @@ please see styles_device_defaults.xml. </style> <style name="Widget.Material.MediaRouteButton"> - <item name="background">@drawable/control_background_material</item> + <item name="background">@drawable/control_background_40dp_material</item> <item name="externalRouteEnabledDrawable">@drawable/ic_media_route_material</item> <item name="minWidth">56dp</item> <item name="minHeight">48dp</item> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 5ba57c4..4160e0e 100755 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2274,6 +2274,7 @@ <java-symbol type="dimen" name="floating_toolbar_maximum_overflow_height" /> <java-symbol type="dimen" name="floating_toolbar_horizontal_margin" /> <java-symbol type="dimen" name="floating_toolbar_vertical_margin" /> + <java-symbol type="dimen" name="content_rect_bottom_clip_allowance" /> <java-symbol type="string" name="date_picker_prev_month_button" /> <java-symbol type="string" name="date_picker_next_month_button" /> diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd index fca958e..52cb13e 100644 --- a/docs/html/training/articles/keystore.jd +++ b/docs/html/training/articles/keystore.jd @@ -32,7 +32,7 @@ page.title=Android Keystore System keystore, they can be used for cryptographic operations with the key material remaining non-exportable. Moreover, it offers facilities to restrict when and how keys can be used, such as requiring user authentication for key use or - restricting encryption keys to be used only in certain block modes. See + restricting keys to be used only in certain cryptographic modes. See <a href="#SecurityFeatures">Security Features</a> section for more information.</p> <p>The Keystore system is used by the {@link @@ -48,7 +48,8 @@ Android Keystore system protects key material from unauthorized use. Firstly, An mitigates unauthorized use of key material outside of the Android device by preventing extraction of the key material from application processes and from the Android device as a whole. Secondly, Android KeyStore mitigates unauthorized use of key material on the Android device by making apps -specify authorized uses of their keys and then enforcing these restrictions. +specify authorized uses of their keys and then enforcing these restrictions outside of the apps' +processes. <h3 id="ExtractionPrevention">Extraction Prevention</h3> @@ -78,14 +79,16 @@ Key material of Android Keystore keys is protected from extraction using two sec To mitigate unauthorized use of keys on the Android device, Android Keystore lets apps specify authorized uses of their keys when generating or importing the keys. Once a key is generated or imported, its authorizations can not be changed. Authorizations are then enforced by the Android -Keystore whenever the key is used. +Keystore whenever the key is used. This is an advanced security feature which is generally useful +only if your requirements are that a compromise of your application process after key +generation/import (but not before or during) cannot lead to unauthorized uses of the key. <p>Supported key use authorizations fall into the following categories: <ul> <li><em>cryptography</em>: authorized key algorithm, operations or purposes (encrypt, decrypt, sign, - verify), padding schemes, block modes, digests with which the key can be used</li> + verify), padding schemes, block modes, digests with which the key can be used;</li> <li><em>temporal validity interval</em>: interval of time during which the key is authorized for - use</li> + use;</li> <li><em>user authentication</em>: the key can only be used if the user has been authenticated recently enough. See <a href="#UserAuthentication">Requiring User Authentication For Key Use</a>. </li> @@ -181,23 +184,33 @@ and {@link java.security.KeyPairGenerator} or <h3 id="UserAuthentication">Requiring User Authentication For Key Use</h3> <p>When generating or importing a key into the {@code AndroidKeyStore} you can specify that the key -can only be used if user has been authenticated. The user is authenticated using a subset of their -secure lock screen credentials. This is a security measure which makes it possible to generate -cryptographic assertions about the user having been authenticated. +is only authorized to be used if the user has been authenticated. The user is authenticated using a +subset of their secure lock screen credentials (pattern/PIN/password, fingerprint). -<p>When a key is configured to require user authentication, it is also configured to operate in one -of the two modes: +<p>This is an advanced security feature which is generally useful only if your requirements are that +a compromise of your application process after key generation/import (but not before or during) +cannot bypass the requirement for the user to be authenticated to use the key. + +<p>When a key is authorized to be used only if the user has been authenticated, it is configured to +operate in one of the two modes: <ul> -<li>User authentication is valid for a duration of time. All keys in this mode are authorized - for use as soon as the user unlocks the secure lock screen or confirms their secure lock screen - credentials using the {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence) KeyguardManager.createConfirmDeviceCredentialIntent} - flow. Each key specifies for how long the authorization remains valid for that key. Such keys - can only be generated or imported if the secure lock screen is enabled (see {@link android.app.KeyguardManager#isDeviceSecure() KeyguardManager.isDeviceSecure()}). - These keys become permanently invalidated once the secure lock screen is disabled or forcibly - reset (e.g. by a Device Admin).</li> -<li>User authentication is required for every use of the key. In this mode, a specific operation - involving a specific key is authorized by the user. Currently, the only means of such - authorization is fingerprint authentication: {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, AuthenticationCallback, Handler) FingerprintManager.authenticate}. - Such keys can only be generated or imported if at least one fingerprint is enrolled (see {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}). - These keys become permanently invalidated once all fingerprints are unenrolled.</li> -</ul> +<li>User authentication authorizes the use of keys for a duration of time. All keys in this mode are + authorized for use as soon as the user unlocks the secure lock screen or confirms their secure + lock screen credential using the + {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence) KeyguardManager.createConfirmDeviceCredentialIntent} + flow. The duration for which the authorization remains valid is specific to each key, as specified + using {@code setUserAuthenticationValidityDurationSeconds} during key generation or import. Such + keys can only be generated or imported if the secure lock screen is enabled (see + {@link android.app.KeyguardManager#isDeviceSecure() KeyguardManager.isDeviceSecure()}). These keys + become permanently invalidated once the secure lock screen is disabled (reconfigured to None, + Swipe or other mode which does not authenticate the user) or forcibly reset (e.g. by a Device + Administrator).</li> +<li>User authentication authorizes a specific cryptographic operation associated with one key. In + this mode, each operation involving such a key must be individually authorized by the user. + Currently, the only means of such authorization is fingerprint authentication: + {@link android.hardware.fingerprint.FingerprintManager#authenticate(CryptoObject, CancellationSignal, int, AuthenticationCallback, Handler) FingerprintManager.authenticate}. + Such keys can only be generated or imported if at least one fingerprint is enrolled (see + {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}). + These keys become permanently invalidated once a new fingerprint is enrolled or all fingerprints + are unenrolled.</li> +</ul>
\ No newline at end of file diff --git a/docs/html/training/training_toc.cs b/docs/html/training/training_toc.cs index ccefe72..e1e6838 100644 --- a/docs/html/training/training_toc.cs +++ b/docs/html/training/training_toc.cs @@ -1023,8 +1023,8 @@ include the action bar on devices running Android 2.1 or higher." <li class="nav-section"> <div class="nav-section-header"> <a href="<?cs var:toroot ?>training/tv/tif/index.html" - description="How to build Live TV apps."> - Building Live TV Apps</a> + description="How to build channels for TV."> + Building TV Channels</a> </div> <ul> <li> diff --git a/docs/html/training/tv/tif/index.jd b/docs/html/training/tv/tif/index.jd index 5739294..92b6139 100644 --- a/docs/html/training/tv/tif/index.jd +++ b/docs/html/training/tv/tif/index.jd @@ -1,4 +1,4 @@ -page.title=Building Live TV Apps +page.title=Building TV Channels page.tags=tv, tif helpoutsWidget=true startpage=true @@ -25,12 +25,17 @@ startpage=true </div> <p> - Watching live television shows and other continuous, channel-based content is a big part of the - TV experience. Android supports receiving and playback of live video content through the TV Input - Framework in Android 5.0 (API level 21). - This framework provides a unified method for receiving audio and video channel content - from hardware sources, such as HDMI ports and built-in-tuners, and software sources, such as - video streamed over the internet. +Watching live TV shows and other continuous, channel-based content is a big part of the TV +experience. Users are accustomed to selecting and watching shows on TV by channel browsing. +To provide your users a similar experience, use the TV Input Framework to create channels for +publishing video or music content so that your media appears alongside traditional TV channels in +the programming guide. +</p> +<p> +Android supports receiving and playback of live video content through the TV Input Framework in +Android 5.0 (API level 21). This framework provides a unified method for receiving audio and video +channel content from hardware sources, such as HDMI ports and built-in-tuners, and software +sources, such as video streamed over the internet. </p> <p> The framework enables developers to define live TV input sources by implementing a TV input diff --git a/docs/html/tv/index.jd b/docs/html/tv/index.jd index 7a0cdcc..73b3435 100644 --- a/docs/html/tv/index.jd +++ b/docs/html/tv/index.jd @@ -145,6 +145,36 @@ page.type=about </div> <!-- end .wrap --> </div> <!-- end .landing-section --> + <div class="landing-section" style="background-color:#f5f5f5" id="tv-games-channels"> + <div class="wrap"> + <div class="landing-section-header"> + <div class="landing-h1">Develop Games and Channels</div> + </div> + + <div class="landing-body"> + <div class="cols"> + <div class="col-8"> + <div class="landing-h3">Play Games on TV</div> + <p class="landing-small" style="padding-left:0px; padding-top:15px;"> + Build apps that let users experience high-performance gaming in leanback mode. + Users can discover your apps easily through the Games row in the Android TV + Launcher.<br> + <a href="{@docRoot}training/tv/games/index.html">Learn how to build games for TV</a> + </p> + </div> + <div class="col-8"> + <div class="landing-h3">Keep Users Engaged with Channels</div> + <p class="landing-small" style="padding-left:0px; padding-top:15px;"> + Create apps that serve video and music content in a linear, channel-like + fashion to users. Users see your channels alongside traditional TV channels in the + programming guide.<br> + <a href="{@docRoot}training/tv/tif/index.html">Learn how to build channels</a> + </p> + </div> + </div> + </div> + </div> <!-- end .wrap --> + </div> <!-- end .landing-section --> <div class="landing-section landing-red-background"> <div class="wrap"> diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index a0c407f..f059727 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -363,7 +363,7 @@ public class BitmapDrawable extends Drawable { } @Override - public boolean getDither() { + public boolean isDither() { return mBitmapState.mPaint.isDither(); } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 415af0d..6090cf0 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -279,7 +279,7 @@ public abstract class Drawable { * @return whether this drawable dithers its colors * @see #setDither(boolean) */ - public boolean getDither() { + public boolean isDither() { return false; } diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index 8b801c3..1759f53 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -167,7 +167,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } @Override - public boolean getDither() { + public boolean isDither() { return mDrawableContainerState.mDither; } diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index ed47eed..626991d 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -826,7 +826,7 @@ public class GradientDrawable extends Drawable { } @Override - public boolean getDither() { + public boolean isDither() { return mGradientState.mDither; } diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java index 7b4329a..85db6a1 100644 --- a/graphics/java/android/graphics/drawable/Icon.java +++ b/graphics/java/android/graphics/drawable/Icon.java @@ -29,6 +29,7 @@ import android.os.Handler; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; +import android.text.TextUtils; import android.util.Log; import java.io.DataInputStream; @@ -258,16 +259,21 @@ public final class Icon implements Parcelable { return new BitmapDrawable(context.getResources(), getBitmap()); case TYPE_RESOURCE: if (getResources() == null) { - if (getResPackage() == null || "android".equals(getResPackage())) { + // figure out where to load resources from + String resPackage = getResPackage(); + if (TextUtils.isEmpty(resPackage)) { + // if none is specified, try the given context + resPackage = context.getPackageName(); + } + if ("android".equals(resPackage)) { mObj1 = Resources.getSystem(); } else { final PackageManager pm = context.getPackageManager(); try { - mObj1 = pm.getResourcesForApplication(getResPackage()); + mObj1 = pm.getResourcesForApplication(resPackage); } catch (PackageManager.NameNotFoundException e) { - Log.e(TAG, String.format("Unable to find pkg=%s", - getResPackage()), - e); + Log.e(TAG, String.format("Unable to find pkg=%s for icon %s", + resPackage, this), e); break; } } @@ -320,12 +326,15 @@ public final class Icon implements Parcelable { */ public Drawable loadDrawableAsUser(Context context, int userId) { if (mType == TYPE_RESOURCE) { - if (getResources() == null - && getResPackage() != null - && !(getResPackage().equals("android"))) { + String resPackage = getResPackage(); + if (TextUtils.isEmpty(resPackage)) { + resPackage = context.getPackageName(); + } + if (getResources() == null && !(getResPackage().equals("android"))) { final PackageManager pm = context.getPackageManager(); try { - mObj1 = pm.getResourcesForApplicationAsUser(getResPackage(), userId); + // assign getResources() as the correct user + mObj1 = pm.getResourcesForApplicationAsUser(resPackage, userId); } catch (PackageManager.NameNotFoundException e) { Log.e(TAG, String.format("Unable to find pkg=%s user=%d", getResPackage(), @@ -410,6 +419,9 @@ public final class Icon implements Parcelable { * @param resId ID of the drawable resource */ public static Icon createWithResource(Context context, @DrawableRes int resId) { + if (context == null) { + throw new IllegalArgumentException("Context must not be null."); + } final Icon rep = new Icon(TYPE_RESOURCE); rep.mInt1 = resId; rep.mString1 = context.getPackageName(); diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 5c00a23..90891f6 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -1248,12 +1248,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } @Override - public boolean getDither() { + public boolean isDither() { final Drawable dr = getFirstNonNullDrawable(); if (dr != null) { - return dr.getDither(); + return dr.isDither(); } else { - return super.getDither(); + return super.isDither(); } } @@ -1537,8 +1537,23 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { continue; } + // Take the resolved layout direction into account. If start / end + // padding are defined, they will be resolved (hence overriding) to + // left / right or right / left depending on the resolved layout + // direction. If start / end padding are not defined, use the + // left / right ones. + final int insetL, insetR; + final int layoutDirection = getLayoutDirection(); + if (layoutDirection == LayoutDirection.RTL) { + insetL = r.mInsetE == UNDEFINED_INSET ? r.mInsetL : r.mInsetE; + insetR = r.mInsetS == UNDEFINED_INSET ? r.mInsetR : r.mInsetS; + } else { + insetL = r.mInsetS == UNDEFINED_INSET ? r.mInsetL : r.mInsetS; + insetR = r.mInsetE == UNDEFINED_INSET ? r.mInsetR : r.mInsetE; + } + final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth; - final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR; + final int w = minWidth + insetL + insetR + padL + padR; if (w > width) { width = w; } diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 0b7869b..adf53e3 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -374,7 +374,7 @@ public class NinePatchDrawable extends Drawable { } @Override - public boolean getDither() { + public boolean isDither() { return mPaint == null ? DEFAULT_DITHER : mPaint.isDither(); } diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index 334b3bd..a669d3c 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -328,7 +328,7 @@ public class ShapeDrawable extends Drawable { } @Override - public boolean getDither() { + public boolean isDither() { return mShapeState.mPaint.isDither(); } diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java new file mode 100644 index 0000000..f412743 --- /dev/null +++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java @@ -0,0 +1,442 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.security.keystore; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.IBinder; +import android.security.KeyStore; +import android.security.KeyStoreException; +import android.security.keymaster.KeymasterArguments; +import android.security.keymaster.KeymasterDefs; +import android.security.keymaster.OperationResult; +import android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.Stream; + +import libcore.util.EmptyArray; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.ProviderException; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.util.Arrays; + +import javax.crypto.CipherSpi; +import javax.crypto.spec.GCMParameterSpec; + +/** + * Base class for Android Keystore authenticated AES {@link CipherSpi} implementations. + * + * @hide + */ +abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase { + + abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi { + private static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96; + private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128; + private static final int DEFAULT_TAG_LENGTH_BITS = 128; + private static final int IV_LENGTH_BYTES = 12; + + private int mTagLengthBits = DEFAULT_TAG_LENGTH_BITS; + + GCM(int keymasterPadding) { + super(KeymasterDefs.KM_MODE_GCM, keymasterPadding); + } + + @Override + protected final void resetAll() { + mTagLengthBits = DEFAULT_TAG_LENGTH_BITS; + super.resetAll(); + } + + @Override + protected final void resetWhilePreservingInitState() { + super.resetWhilePreservingInitState(); + } + + @Override + protected final void initAlgorithmSpecificParameters() throws InvalidKeyException { + if (!isEncrypting()) { + throw new InvalidKeyException("IV required when decrypting" + + ". Use IvParameterSpec or AlgorithmParameters to provide it."); + } + } + + @Override + protected final void initAlgorithmSpecificParameters(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException { + // IV is used + if (params == null) { + if (!isEncrypting()) { + // IV must be provided by the caller + throw new InvalidAlgorithmParameterException( + "GCMParameterSpec must be provided when decrypting"); + } + return; + } + if (!(params instanceof GCMParameterSpec)) { + throw new InvalidAlgorithmParameterException("Only GCMParameterSpec supported"); + } + GCMParameterSpec spec = (GCMParameterSpec) params; + byte[] iv = spec.getIV(); + if (iv == null) { + throw new InvalidAlgorithmParameterException("Null IV in GCMParameterSpec"); + } else if (iv.length != IV_LENGTH_BYTES) { + throw new InvalidAlgorithmParameterException("Unsupported IV length: " + + iv.length + " bytes. Only " + IV_LENGTH_BYTES + + " bytes long IV supported"); + } + int tagLengthBits = spec.getTLen(); + if ((tagLengthBits < MIN_SUPPORTED_TAG_LENGTH_BITS) + || (tagLengthBits > MAX_SUPPORTED_TAG_LENGTH_BITS) + || ((tagLengthBits % 8) != 0)) { + throw new InvalidAlgorithmParameterException( + "Unsupported tag length: " + tagLengthBits + " bits" + + ". Supported lengths: 96, 104, 112, 120, 128"); + } + setIv(iv); + mTagLengthBits = tagLengthBits; + } + + @Override + protected final void initAlgorithmSpecificParameters(AlgorithmParameters params) + throws InvalidAlgorithmParameterException { + if (params == null) { + if (!isEncrypting()) { + // IV must be provided by the caller + throw new InvalidAlgorithmParameterException("IV required when decrypting" + + ". Use GCMParameterSpec or GCM AlgorithmParameters to provide it."); + } + return; + } + + GCMParameterSpec spec; + try { + spec = params.getParameterSpec(GCMParameterSpec.class); + } catch (InvalidParameterSpecException e) { + if (!isEncrypting()) { + // IV must be provided by the caller + throw new InvalidAlgorithmParameterException("IV and tag length required when" + + " decrypting, but not found in parameters: " + params, e); + } + setIv(null); + return; + } + initAlgorithmSpecificParameters(spec); + } + + @Nullable + @Override + protected final AlgorithmParameters engineGetParameters() { + byte[] iv = getIv(); + if ((iv != null) && (iv.length > 0)) { + try { + AlgorithmParameters params = AlgorithmParameters.getInstance("GCM"); + params.init(new GCMParameterSpec(mTagLengthBits, iv)); + return params; + } catch (NoSuchAlgorithmException e) { + throw new ProviderException( + "Failed to obtain GCM AlgorithmParameters", e); + } catch (InvalidParameterSpecException e) { + throw new ProviderException( + "Failed to initialize GCM AlgorithmParameters", e); + } + } + return null; + } + + @NonNull + @Override + protected KeyStoreCryptoOperationStreamer createMainDataStreamer( + KeyStore keyStore, IBinder operationToken) { + KeyStoreCryptoOperationStreamer streamer = new KeyStoreCryptoOperationChunkedStreamer( + new KeyStoreCryptoOperationChunkedStreamer.MainDataStream( + keyStore, operationToken)); + if (isEncrypting()) { + return streamer; + } else { + // When decrypting, to avoid leaking unauthenticated plaintext, do not return any + // plaintext before ciphertext is authenticated by KeyStore.finish. + return new BufferAllOutputUntilDoFinalStreamer(streamer); + } + } + + @NonNull + @Override + protected final KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer( + KeyStore keyStore, IBinder operationToken) { + return new KeyStoreCryptoOperationChunkedStreamer( + new AdditionalAuthenticationDataStream(keyStore, operationToken)); + } + + @Override + protected final int getAdditionalEntropyAmountForBegin() { + if ((getIv() == null) && (isEncrypting())) { + // IV will need to be generated + return IV_LENGTH_BYTES; + } + + return 0; + } + + @Override + protected final int getAdditionalEntropyAmountForFinish() { + return 0; + } + + @Override + protected final void addAlgorithmSpecificParametersToBegin( + @NonNull KeymasterArguments keymasterArgs) { + super.addAlgorithmSpecificParametersToBegin(keymasterArgs); + keymasterArgs.addInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mTagLengthBits); + } + + protected final int getTagLengthBits() { + return mTagLengthBits; + } + + public static final class NoPadding extends GCM { + public NoPadding() { + super(KeymasterDefs.KM_PAD_NONE); + } + + @Override + protected final int engineGetOutputSize(int inputLen) { + int tagLengthBytes = (getTagLengthBits() + 7) / 8; + long result; + if (isEncrypting()) { + result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen + + tagLengthBytes; + } else { + result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen + - tagLengthBytes; + } + if (result < 0) { + return 0; + } else if (result > Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + return (int) result; + } + } + } + + private static final int BLOCK_SIZE_BYTES = 16; + + private final int mKeymasterBlockMode; + private final int mKeymasterPadding; + + private byte[] mIv; + + /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */ + private boolean mIvHasBeenUsed; + + AndroidKeyStoreAuthenticatedAESCipherSpi( + int keymasterBlockMode, + int keymasterPadding) { + mKeymasterBlockMode = keymasterBlockMode; + mKeymasterPadding = keymasterPadding; + } + + @Override + protected void resetAll() { + mIv = null; + mIvHasBeenUsed = false; + super.resetAll(); + } + + @Override + protected final void initKey(int opmode, Key key) throws InvalidKeyException { + if (!(key instanceof AndroidKeyStoreSecretKey)) { + throw new InvalidKeyException( + "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null")); + } + if (!KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(key.getAlgorithm())) { + throw new InvalidKeyException( + "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " + + KeyProperties.KEY_ALGORITHM_AES + " supported"); + } + setKey((AndroidKeyStoreSecretKey) key); + } + + @Override + protected void addAlgorithmSpecificParametersToBegin( + @NonNull KeymasterArguments keymasterArgs) { + if ((isEncrypting()) && (mIvHasBeenUsed)) { + // IV is being reused for encryption: this violates security best practices. + throw new IllegalStateException( + "IV has already been used. Reusing IV in encryption mode violates security best" + + " practices."); + } + + keymasterArgs.addInt(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES); + keymasterArgs.addInt(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode); + keymasterArgs.addInt(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding); + if (mIv != null) { + keymasterArgs.addBlob(KeymasterDefs.KM_TAG_NONCE, mIv); + } + } + + @Override + protected final void loadAlgorithmSpecificParametersFromBeginResult( + @NonNull KeymasterArguments keymasterArgs) { + mIvHasBeenUsed = true; + + // NOTE: Keymaster doesn't always return an IV, even if it's used. + byte[] returnedIv = keymasterArgs.getBlob(KeymasterDefs.KM_TAG_NONCE, null); + if ((returnedIv != null) && (returnedIv.length == 0)) { + returnedIv = null; + } + + if (mIv == null) { + mIv = returnedIv; + } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) { + throw new ProviderException("IV in use differs from provided IV"); + } + } + + @Override + protected final int engineGetBlockSize() { + return BLOCK_SIZE_BYTES; + } + + @Override + protected final byte[] engineGetIV() { + return ArrayUtils.cloneIfNotEmpty(mIv); + } + + protected void setIv(byte[] iv) { + mIv = iv; + } + + protected byte[] getIv() { + return mIv; + } + + /** + * {@link KeyStoreCryptoOperationStreamer} which buffers all output until {@code doFinal} from + * which it returns all output in one go, provided {@code doFinal} succeeds. + */ + private static class BufferAllOutputUntilDoFinalStreamer + implements KeyStoreCryptoOperationStreamer { + + private final KeyStoreCryptoOperationStreamer mDelegate; + private ByteArrayOutputStream mBufferedOutput = new ByteArrayOutputStream(); + private long mProducedOutputSizeBytes; + + private BufferAllOutputUntilDoFinalStreamer(KeyStoreCryptoOperationStreamer delegate) { + mDelegate = delegate; + } + + @Override + public byte[] update(byte[] input, int inputOffset, int inputLength) + throws KeyStoreException { + byte[] output = mDelegate.update(input, inputOffset, inputLength); + if (output != null) { + try { + mBufferedOutput.write(output); + } catch (IOException e) { + throw new ProviderException("Failed to buffer output", e); + } + } + return EmptyArray.BYTE; + } + + @Override + public byte[] doFinal(byte[] input, int inputOffset, int inputLength, + byte[] additionalEntropy) throws KeyStoreException { + byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, additionalEntropy); + if (output != null) { + try { + mBufferedOutput.write(output); + } catch (IOException e) { + throw new ProviderException("Failed to buffer output", e); + } + } + byte[] result = mBufferedOutput.toByteArray(); + mBufferedOutput.reset(); + mProducedOutputSizeBytes += result.length; + return result; + } + + @Override + public long getConsumedInputSizeBytes() { + return mDelegate.getConsumedInputSizeBytes(); + } + + @Override + public long getProducedOutputSizeBytes() { + return mProducedOutputSizeBytes; + } + } + + /** + * Additional Authentication Data (AAD) stream via a KeyStore streaming operation. This stream + * sends AAD into the KeyStore. + */ + private static class AdditionalAuthenticationDataStream implements Stream { + + private final KeyStore mKeyStore; + private final IBinder mOperationToken; + + private AdditionalAuthenticationDataStream(KeyStore keyStore, IBinder operationToken) { + mKeyStore = keyStore; + mOperationToken = operationToken; + } + + @Override + public OperationResult update(byte[] input) { + KeymasterArguments keymasterArgs = new KeymasterArguments(); + keymasterArgs.addBlob(KeymasterDefs.KM_TAG_ASSOCIATED_DATA, input); + + // KeyStore does not reflect AAD in inputConsumed, but users of Stream rely on this + // field. We fix this discrepancy here. KeyStore.update contract is that all of AAD + // has been consumed if the method succeeds. + OperationResult result = mKeyStore.update(mOperationToken, keymasterArgs, null); + if (result.resultCode == KeyStore.NO_ERROR) { + result = new OperationResult( + result.resultCode, + result.token, + result.operationHandle, + input.length, // inputConsumed + result.output, + result.outParams); + } + return result; + } + + @Override + public OperationResult finish(byte[] additionalEntropy) { + if ((additionalEntropy != null) && (additionalEntropy.length > 0)) { + throw new ProviderException("AAD stream does not support additional entropy"); + } + return new OperationResult( + KeyStore.NO_ERROR, + mOperationToken, + 0, // operation handle -- nobody cares about this being returned from finish + 0, // inputConsumed + EmptyArray.BYTE, // output + new KeymasterArguments() // additional params returned by finish + ); + } + } +}
\ No newline at end of file diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java index f37cf07..156f45f 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java @@ -93,6 +93,9 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { putSymmetricCipherImpl("AES/CTR/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding"); + putSymmetricCipherImpl("AES/GCM/NoPadding", + PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding"); + putAsymmetricCipherImpl("RSA/ECB/NoPadding", PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$NoPadding"); put("Alg.Alias.Cipher.RSA/None/NoPadding", "RSA/ECB/NoPadding"); @@ -129,52 +132,52 @@ class AndroidKeyStoreBCWorkaroundProvider extends Provider { putSignatureImpl("MD5withRSA", PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$MD5WithPKCS1Padding"); - put("Alg.Alias.Signature.MD5WithRSAEncryption", "MD5WithRSA"); - put("Alg.Alias.Signature.MD5/RSA", "MD5WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5WithRSA"); + put("Alg.Alias.Signature.MD5WithRSAEncryption", "MD5withRSA"); + put("Alg.Alias.Signature.MD5/RSA", "MD5withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5withRSA"); putSignatureImpl("SHA1withRSA", PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA1WithPKCS1Padding"); - put("Alg.Alias.Signature.SHA1WithRSAEncryption", "SHA1WithRSA"); - put("Alg.Alias.Signature.SHA1/RSA", "SHA1WithRSA"); - put("Alg.Alias.Signature.SHA-1/RSA", "SHA1WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1WithRSA"); - put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1WithRSA"); - put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1WithRSA"); - put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1WithRSA"); + put("Alg.Alias.Signature.SHA1WithRSAEncryption", "SHA1withRSA"); + put("Alg.Alias.Signature.SHA1/RSA", "SHA1withRSA"); + put("Alg.Alias.Signature.SHA-1/RSA", "SHA1withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA"); + put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1withRSA"); + put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1withRSA"); + put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA"); putSignatureImpl("SHA224withRSA", PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA224WithPKCS1Padding"); - put("Alg.Alias.Signature.SHA224WithRSAEncryption", "SHA224WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA224WithRSA"); + put("Alg.Alias.Signature.SHA224WithRSAEncryption", "SHA224withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA224withRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.1", - "SHA224WithRSA"); + "SHA224withRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.11", - "SHA224WithRSA"); + "SHA224withRSA"); putSignatureImpl("SHA256withRSA", PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA256WithPKCS1Padding"); - put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256WithRSA"); + put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1", - "SHA256WithRSA"); + "SHA256withRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11", - "SHA256WithRSA"); + "SHA256withRSA"); putSignatureImpl("SHA384withRSA", PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA384WithPKCS1Padding"); - put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384WithRSA"); + put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1", - "SHA384WithRSA"); + "SHA384withRSA"); putSignatureImpl("SHA512withRSA", PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA512WithPKCS1Padding"); - put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512WithRSA"); - put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512WithRSA"); + put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1", - "SHA512WithRSA"); + "SHA512withRSA"); putSignatureImpl("SHA1withRSA/PSS", PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA1WithPSSPadding"); diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java index d2d5850..fc53451 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java @@ -26,6 +26,8 @@ import android.security.keymaster.KeymasterArguments; import android.security.keymaster.KeymasterDefs; import android.security.keymaster.OperationResult; +import libcore.util.EmptyArray; + import java.nio.ByteBuffer; import java.security.AlgorithmParameters; import java.security.GeneralSecurityException; @@ -78,6 +80,8 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor private IBinder mOperationToken; private long mOperationHandle; private KeyStoreCryptoOperationStreamer mMainDataStreamer; + private KeyStoreCryptoOperationStreamer mAdditionalAuthenticationDataStreamer; + private boolean mAdditionalAuthenticationDataStreamerClosed; /** * Encountered exception which could not be immediately thrown because it was encountered inside @@ -189,6 +193,8 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor mOperationToken = null; mOperationHandle = 0; mMainDataStreamer = null; + mAdditionalAuthenticationDataStreamer = null; + mAdditionalAuthenticationDataStreamerClosed = false; mCachedException = null; } @@ -209,6 +215,8 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor mOperationToken = null; mOperationHandle = 0; mMainDataStreamer = null; + mAdditionalAuthenticationDataStreamer = null; + mAdditionalAuthenticationDataStreamerClosed = false; mCachedException = null; } @@ -273,6 +281,9 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor loadAlgorithmSpecificParametersFromBeginResult(opResult.outParams); mMainDataStreamer = createMainDataStreamer(mKeyStore, opResult.token); + mAdditionalAuthenticationDataStreamer = + createAdditionalAuthenticationDataStreamer(mKeyStore, opResult.token); + mAdditionalAuthenticationDataStreamerClosed = false; } /** @@ -289,6 +300,20 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor keyStore, operationToken)); } + /** + * Creates a streamer which sends Additional Authentication Data (AAD) into the KeyStore. + * + * <p>This implementation returns {@code null}. + * + * @returns stream or {@code null} if AAD is not supported by this cipher. + */ + @Nullable + protected KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer( + @SuppressWarnings("unused") KeyStore keyStore, + @SuppressWarnings("unused") IBinder operationToken) { + return null; + } + @Override protected final byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) { if (mCachedException != null) { @@ -307,6 +332,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor byte[] output; try { + flushAAD(); output = mMainDataStreamer.update(input, inputOffset, inputLen); } catch (KeyStoreException e) { mCachedException = e; @@ -320,6 +346,25 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor return output; } + private void flushAAD() throws KeyStoreException { + if ((mAdditionalAuthenticationDataStreamer != null) + && (!mAdditionalAuthenticationDataStreamerClosed)) { + byte[] output; + try { + output = mAdditionalAuthenticationDataStreamer.doFinal( + EmptyArray.BYTE, 0, 0, + null // no additional entropy needed flushing AAD + ); + } finally { + mAdditionalAuthenticationDataStreamerClosed = true; + } + if ((output != null) && (output.length > 0)) { + throw new ProviderException( + "AAD update unexpectedly returned data: " + output.length + " bytes"); + } + } + } + @Override protected final int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output, int outputOffset) throws ShortBufferException { @@ -344,12 +389,64 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor @Override protected final void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) { - super.engineUpdateAAD(input, inputOffset, inputLen); + if (mCachedException != null) { + return; + } + + try { + ensureKeystoreOperationInitialized(); + } catch (InvalidKeyException | InvalidAlgorithmParameterException e) { + mCachedException = e; + return; + } + + if (mAdditionalAuthenticationDataStreamerClosed) { + throw new IllegalStateException( + "AAD can only be provided before Cipher.update is invoked"); + } + + if (mAdditionalAuthenticationDataStreamer == null) { + throw new IllegalStateException("This cipher does not support AAD"); + } + + byte[] output; + try { + output = mAdditionalAuthenticationDataStreamer.update(input, inputOffset, inputLen); + } catch (KeyStoreException e) { + mCachedException = e; + return; + } + + if ((output != null) && (output.length > 0)) { + throw new ProviderException("AAD update unexpectedly produced output: " + + output.length + " bytes"); + } } @Override protected final void engineUpdateAAD(ByteBuffer src) { - super.engineUpdateAAD(src); + if (src == null) { + throw new IllegalArgumentException("src == null"); + } + if (!src.hasRemaining()) { + return; + } + + byte[] input; + int inputOffset; + int inputLen; + if (src.hasArray()) { + input = src.array(); + inputOffset = src.arrayOffset() + src.position(); + inputLen = src.remaining(); + src.position(src.limit()); + } else { + input = new byte[src.remaining()]; + inputOffset = 0; + inputLen = input.length; + src.get(input); + } + super.engineUpdateAAD(input, inputOffset, inputLen); } @Override @@ -368,6 +465,7 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor byte[] output; try { + flushAAD(); byte[] additionalEntropy = KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng( mRng, getAdditionalEntropyAmountForFinish()); @@ -615,6 +713,20 @@ abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStor return mKeyStore; } + protected final long getConsumedInputSizeBytes() { + if (mMainDataStreamer == null) { + throw new IllegalStateException("Not initialized"); + } + return mMainDataStreamer.getConsumedInputSizeBytes(); + } + + protected final long getProducedOutputSizeBytes() { + if (mMainDataStreamer == null) { + throw new IllegalStateException("Not initialized"); + } + return mMainDataStreamer.getProducedOutputSizeBytes(); + } + // The methods below need to be implemented by subclasses. /** diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java index 2de60fd..2055cdb 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java @@ -104,8 +104,6 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato /* EC */ private static final int EC_DEFAULT_KEY_SIZE = 256; - private static final int EC_MIN_KEY_SIZE = 192; - private static final int EC_MAX_KEY_SIZE = 521; /* RSA */ private static final int RSA_DEFAULT_KEY_SIZE = 2048; @@ -115,16 +113,13 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE = new HashMap<String, Integer>(); private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>(); + private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>(); static { - // Aliases for NIST P-192 - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-192", 192); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp192r1", 192); - SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime192v1", 192); - // Aliases for NIST P-224 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224); SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224); + // Aliases for NIST P-256 SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256); SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256); @@ -140,6 +135,10 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet()); Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES); + + SUPPORTED_EC_NIST_CURVE_SIZES.addAll( + new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values())); + Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES); } private final int mOriginalKeymasterAlgorithm; @@ -227,9 +226,8 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato | KeyProperties.PURPOSE_VERIFY); // Authorized to be used with any digest (including no digest). specBuilder.setDigests(KeyProperties.DIGEST_NONE); - specBuilder.setSignaturePaddings( - KeyProperties.SIGNATURE_PADDING_RSA_PKCS1); - // Authorized to be used with any padding (including no padding). + // Authorized to be used with any encryption and signature padding + // scheme (including no padding). specBuilder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_NONE); // Disable randomized encryption requirement to support encryption @@ -598,9 +596,9 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato throws InvalidAlgorithmParameterException { switch (keymasterAlgorithm) { case KeymasterDefs.KM_ALGORITHM_EC: - if (keySize < EC_MIN_KEY_SIZE || keySize > EC_MAX_KEY_SIZE) { - throw new InvalidAlgorithmParameterException("EC key size must be >= " - + EC_MIN_KEY_SIZE + " and <= " + EC_MAX_KEY_SIZE); + if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) { + throw new InvalidAlgorithmParameterException("Unsupported EC key size: " + + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES); } break; case KeymasterDefs.KM_ALGORITHM_RSA: diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java index 6abdf19..38e216d 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java @@ -129,6 +129,7 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase private final KeyStoreCryptoOperationStreamer mDelegate; private final int mModulusSizeBytes; private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream(); + private long mConsumedInputSizeBytes; private ZeroPaddingEncryptionStreamer( KeyStoreCryptoOperationStreamer delegate, @@ -142,6 +143,7 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase throws KeyStoreException { if (inputLength > 0) { mInputBuffer.write(input, inputOffset, inputLength); + mConsumedInputSizeBytes += inputLength; } return EmptyArray.BYTE; } @@ -151,6 +153,7 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase byte[] additionalEntropy) throws KeyStoreException { if (inputLength > 0) { + mConsumedInputSizeBytes += inputLength; mInputBuffer.write(input, inputOffset, inputLength); } byte[] bufferedInput = mInputBuffer.toByteArray(); @@ -173,6 +176,16 @@ abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase } return mDelegate.doFinal(paddedInput, 0, paddedInput.length, additionalEntropy); } + + @Override + public long getConsumedInputSizeBytes() { + return mConsumedInputSizeBytes; + } + + @Override + public long getProducedOutputSizeBytes() { + return mDelegate.getProducedOutputSizeBytes(); + } } } diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java index 3bd9d1d..5fb589e 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java @@ -258,9 +258,8 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi { | KeyProperties.PURPOSE_VERIFY); // Authorized to be used with any digest (including no digest). specBuilder.setDigests(KeyProperties.DIGEST_NONE); - specBuilder.setSignaturePaddings( - KeyProperties.SIGNATURE_PADDING_RSA_PKCS1); - // Authorized to be used with any padding (including no padding). + // Authorized to be used with any encryption and signature padding scheme (including no + // padding). specBuilder.setEncryptionPaddings( KeyProperties.ENCRYPTION_PADDING_NONE); // Disable randomized encryption requirement to support encryption padding NONE diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java index 76804a9..6c53c6a 100644 --- a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java +++ b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java @@ -1,3 +1,19 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + package android.security.keystore; import android.annotation.NonNull; diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java index 8d4bfcd..1732db9 100644 --- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java +++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java @@ -19,16 +19,20 @@ package android.security.keystore; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.KeyguardManager; +import android.hardware.fingerprint.FingerprintManager; import android.text.TextUtils; import java.math.BigInteger; import java.security.KeyPairGenerator; +import java.security.Signature; import java.security.cert.Certificate; import java.security.spec.AlgorithmParameterSpec; import java.util.Date; import javax.crypto.Cipher; import javax.crypto.KeyGenerator; +import javax.crypto.Mac; import javax.security.auth.x500.X500Principal; /** @@ -62,10 +66,15 @@ import javax.security.auth.x500.X500Principal; * <p>NOTE: If a private key is not authorized to sign the self-signed certificate, then the * certificate will be created with an invalid signature which will not verify. Such a certificate * is still useful because it provides access to the public key. To generate a valid - * signature for the certificate the key needs to be authorized for - * {@link KeyProperties#PURPOSE_SIGN}, a suitable digest or {@link KeyProperties#DIGEST_NONE}, and - * {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1} or - * {@link KeyProperties#ENCRYPTION_PADDING_NONE}. + * signature for the certificate the key needs to be authorized for all of the following: + * <ul> + * <li>{@link KeyProperties#PURPOSE_SIGN},</li> + * <li>operation without requiring the user to be authenticated (see + * {@link Builder#setUserAuthenticationRequired(boolean)}),</li> + * <li>suitable digest or {@link KeyProperties#DIGEST_NONE},</li> + * <li>(RSA keys only) padding scheme {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1} or + * {@link KeyProperties#ENCRYPTION_PADDING_NONE}.</li> + * </ul> * * <p>NOTE: The key material of the generated symmetric and private keys is not accessible. The key * material of the public keys is accessible. @@ -103,7 +112,7 @@ import javax.security.auth.x500.X500Principal; * * <p><h3>Example: Symmetric key</h3> * The following example illustrates how to generate an AES key in the Android KeyStore system under - * alias {@code key2} authorized to be used only for encryption/decryption in CBC mode with PKCS#7 + * alias {@code key2} authorized to be used only for encryption/decryption in GCM mode with no * padding. * <pre> {@code * KeyGenerator keyGenerator = KeyGenerator.getInstance( @@ -112,8 +121,8 @@ import javax.security.auth.x500.X500Principal; * keyGenerator.initialize( * new KeyGenParameterSpec.Builder("key2", * KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - * .setBlockModes(KeyProperties.BLOCK_MODE_CBC) - * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) + * .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) * .build()); * SecretKey key = keyGenerator.generateKey(); * @@ -368,7 +377,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used + * Gets the set of block modes (e.g., {@code GCM}, {@code CBC}) with which the key can be used * when encrypting/decrypting. Attempts to use the key with any other block modes will be * rejected. * @@ -393,28 +402,32 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Returns {@code true} if user authentication is required for this key to be used. + * Returns {@code true} if the key is authorized to be used only if the user has been + * authenticated. * - * <p>This restriction applies only to private key operations. Public key operations are not - * restricted. + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #getUserAuthenticationValidityDurationSeconds() + * @see Builder#setUserAuthenticationRequired(boolean) */ public boolean isUserAuthenticationRequired() { return mUserAuthenticationRequired; } /** - * Gets the duration of time (seconds) for which this key can be used after the user is - * successfully authenticated. This has effect only if user authentication is required. + * Gets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect only if user authentication is required + * (see {@link #isUserAuthenticationRequired()}). * - * <p>This restriction applies only to private key operations. Public key operations are not - * restricted. + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @return duration in seconds or {@code -1} if authentication is required for every use of the - * key. + * key. * * @see #isUserAuthenticationRequired() + * @see Builder#setUserAuthenticationValidityDurationSeconds(int) */ public int getUserAuthenticationValidityDurationSeconds() { return mUserAuthenticationValidityDurationSeconds; @@ -681,11 +694,11 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Sets the set of block modes (e.g., {@code CBC}, {@code CTR}, {@code ECB}) with which the - * key can be used when encrypting/decrypting. Attempts to use the key with any other block - * modes will be rejected. + * Sets the set of block modes (e.g., {@code GCM}, {@code CBC}) with which the key can be + * used when encrypting/decrypting. Attempts to use the key with any other block modes will + * be rejected. * - * <p>This must be specified for encryption/decryption keys. + * <p>This must be specified for symmetric encryption/decryption keys. * * <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants. */ @@ -711,7 +724,7 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { * <li>encryption/decryption transformation which do not offer {@code IND-CPA}, such as * {@code ECB} with a symmetric encryption algorithm, or RSA encryption/decryption without * padding, are prohibited;</li> - * <li>in block modes which use an IV, such as {@code CBC}, {@code CTR}, and {@code GCM}, + * <li>in block modes which use an IV, such as {@code GCM}, {@code CBC}, and {@code CTR}, * caller-provided IVs are rejected when encrypting, to ensure that only random IVs are * used.</li> * </ul> @@ -738,22 +751,38 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Sets whether user authentication is required to use this key. + * Sets whether this key is authorized to be used only if the user has been authenticated. * - * <p>By default, the key can be used without user authentication. + * <p>By default, the key is authorized to be used regardless of whether the user has been + * authenticated. * - * <p>When user authentication is required, the user authorizes the use of the key by - * authenticating to this Android device using a subset of their secure lock screen - * credentials. Different authentication methods are used depending on whether the every - * use of the key must be authenticated (as specified by - * {@link #setUserAuthenticationValidityDurationSeconds(int)}). + * <p>When user authentication is required: + * <ul> + * <li>The key can only be generated if secure lock screen is set up (see + * {@link KeyguardManager#isDeviceSecure()}). Additionally, if the key requires that user + * authentication takes place for every use of the key (see + * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one fingerprint + * must be enrolled (see {@link FingerprintManager#hasEnrolledFingerprints()}).</li> + * <li>The use of the key must be authorized by the user by authenticating to this Android + * device using a subset of their secure lock screen credentials such as + * password/PIN/pattern or fingerprint. * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More * information</a>. + * <li>The key will become <em>irreversibly invalidated</em> once the secure lock screen is + * disabled (reconfigured to None, Swipe or other mode which does not authenticate the user) + * or when the secure lock screen is forcibly reset (e.g., by a Device Administrator). + * Additionally, if the key requires that user authentication takes place for every use of + * the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\ + * no more fingerprints are enrolled. Attempts to initialize cryptographic operations using + * such keys will throw {@link KeyPermanentlyInvalidatedException}.</li> + * </ul> * - * <p>This restriction applies only to private key operations. Public key operations are not - * restricted. + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #setUserAuthenticationValidityDurationSeconds(int) + * @see KeyguardManager#isDeviceSecure() + * @see FingerprintManager#hasEnrolledFingerprints() */ @NonNull public Builder setUserAuthenticationRequired(boolean required) { @@ -762,15 +791,39 @@ public final class KeyGenParameterSpec implements AlgorithmParameterSpec { } /** - * Sets the duration of time (seconds) for which this key can be used after the user is - * successfully authenticated. This has effect only if user authentication is required. - * - * <p>By default, the user needs to authenticate for every use of the key. - * - * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for - * every use of the key. + * Sets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect if the key requires user + * authentication for its use (see {@link #setUserAuthenticationRequired(boolean)}). + * + * <p>By default, if user authentication is required, it must take place for every use of + * the key. + * + * <p>Cryptographic operations involving keys which require user authentication to take + * place for every operation can only use fingerprint authentication. This is achieved by + * initializing a cryptographic operation ({@link Signature}, {@link Cipher}, {@link Mac}) + * with the key, wrapping it into a {@link FingerprintManager.CryptoObject}, invoking + * {@code FingerprintManager.authenticate} with {@code CryptoObject}, and proceeding with + * the cryptographic operation only if the authentication flow succeeds. + * + * <p>Cryptographic operations involving keys which are authorized to be used for a duration + * of time after a successful user authentication event can only use secure lock screen + * authentication. These cryptographic operations will throw + * {@link UserNotAuthenticatedException} during initialization if the user needs to be + * authenticated to proceed. This situation can be resolved by the user unlocking the secure + * lock screen of the Android or by going through the confirm credential flow initiated by + * {@link KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence)}. + * Once resolved, initializing a new cryptographic operation using this key (or any other + * key which is authorized to be used for a fixed duration of time after user + * authentication) should succeed provided the user authentication flow completed + * successfully. + * + * @param seconds duration in seconds or {@code -1} if user authentication must take place + * for every use of the key. * * @see #setUserAuthenticationRequired(boolean) + * @see FingerprintManager + * @see FingerprintManager.CryptoObject + * @see KeyguardManager */ @NonNull public Builder setUserAuthenticationValidityDurationSeconds( diff --git a/keystore/java/android/security/keystore/KeyInfo.java b/keystore/java/android/security/keystore/KeyInfo.java index 03b4100..785ec15 100644 --- a/keystore/java/android/security/keystore/KeyInfo.java +++ b/keystore/java/android/security/keystore/KeyInfo.java @@ -30,7 +30,7 @@ import javax.crypto.SecretKey; * Keystore system</a>. This class describes whether the key material is available in * plaintext outside of secure hardware, whether user authentication is required for using the key * and whether this requirement is enforced by secure hardware, the key's origin, what uses the key - * is authorized for (e.g., only in {@code CBC} mode, or signing only), whether the key should be + * is authorized for (e.g., only in {@code GCM} mode, or signing only), whether the key should be * encrypted at rest, the key's and validity start and end dates. * * <p>Instances of this class are immutable. @@ -191,7 +191,7 @@ public class KeyInfo implements KeySpec { } /** - * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used + * Gets the set of block modes (e.g., {@code GCM}, {@code CBC}) with which the key can be used * when encrypting/decrypting. Attempts to use the key with any other block modes will be * rejected. * @@ -238,17 +238,27 @@ public class KeyInfo implements KeySpec { } /** - * Returns {@code true} if user authentication is required for this key to be used. + * Returns {@code true} if the key is authorized to be used only if the user has been + * authenticated. + * + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #getUserAuthenticationValidityDurationSeconds() + * @see KeyGenParameterSpec.Builder#setUserAuthenticationRequired(boolean) + * @see KeyProtection.Builder#setUserAuthenticationRequired(boolean) */ public boolean isUserAuthenticationRequired() { return mUserAuthenticationRequired; } /** - * Gets the duration of time (seconds) for which this key can be used after the user is - * successfully authenticated. This has effect only if user authentication is required. + * Gets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect only if user authentication is required + * (see {@link #isUserAuthenticationRequired()}). + * + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @return duration in seconds or {@code -1} if authentication is required for every use of the * key. diff --git a/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java b/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java index e320c9c..9e82fc0 100644 --- a/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java +++ b/keystore/java/android/security/keystore/KeyPermanentlyInvalidatedException.java @@ -21,12 +21,13 @@ import java.security.InvalidKeyException; /** * Indicates that the key can no longer be used because it has been permanently invalidated. * - * <p>This can currently occur only for keys that require user authentication. Such keys are - * permanently invalidated once the secure lock screen is disabled (i.e., reconfigured to None, - * Swipe or other mode which does not authenticate the user) or when the secure lock screen is - * forcibly reset (e.g., by Device Admin). Additionally, keys configured to require user - * authentication for every use of the key are also permanently invalidated once a new fingerprint - * is enrolled or once no more fingerprints are enrolled. + * <p>This only occurs for keys which are authorized to be used only if the user has been + * authenticated. Such keys are permanently and irreversibly invalidated once the secure lock screen + * is disabled (i.e., reconfigured to None, Swipe or other mode which does not authenticate the + * user) or when the secure lock screen is forcibly reset (e.g., by Device Admin). Additionally, + * keys configured to require user authentication to take place for every of the keys, are also + * permanently invalidated once a new fingerprint is enrolled or once no more fingerprints are + * enrolled. */ public class KeyPermanentlyInvalidatedException extends InvalidKeyException { diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java index 1e0611c..b7a2a0b 100644 --- a/keystore/java/android/security/keystore/KeyProtection.java +++ b/keystore/java/android/security/keystore/KeyProtection.java @@ -19,19 +19,23 @@ package android.security.keystore; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.app.KeyguardManager; +import android.hardware.fingerprint.FingerprintManager; import java.security.Key; +import java.security.Signature; import java.security.KeyStore.ProtectionParameter; import java.security.cert.Certificate; import java.util.Date; import javax.crypto.Cipher; +import javax.crypto.Mac; /** * Specification of how a key or key pair is secured when imported into the * <a href="{@docRoot}training/articles/keystore.html">Android KeyStore facility</a>. This class * specifies parameters such as whether user authentication is required for using the key, what uses - * the key is authorized for (e.g., only in {@code CTR} mode, or only for signing -- decryption not + * the key is authorized for (e.g., only in {@code GCM} mode, or only for signing -- decryption not * permitted), the key's and validity start and end dates. * * <p>To import a key or key pair into the Android KeyStore, create an instance of this class using @@ -51,8 +55,8 @@ import javax.crypto.Cipher; * * <p><h3>Example: Symmetric Key</h3> * The following example illustrates how to import an AES key into the Android KeyStore under alias - * {@code key1} authorized to be used only for encryption/decryption in CBC mode with PKCS#7 - * padding. The key must export its key material via {@link Key#getEncoded()} in {@code RAW} format. + * {@code key1} authorized to be used only for encryption/decryption in GCM mode with no padding. + * The key must export its key material via {@link Key#getEncoded()} in {@code RAW} format. * <pre> {@code * SecretKey key = ...; // AES key * @@ -62,8 +66,8 @@ import javax.crypto.Cipher; * "key1", * new KeyStore.SecretKeyEntry(key), * new KeyProtection.Builder(KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - * .setBlockMode(KeyProperties.BLOCK_MODE_CBC) - * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) + * .setBlockMode(KeyProperties.BLOCK_MODE_GCM) + * .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) * .build()); * // Key imported, obtain a reference to it. * SecretKey keyStoreKey = (SecretKey) keyStore.getKey("key1", null); @@ -232,7 +236,7 @@ public final class KeyProtection implements ProtectionParameter { } /** - * Gets the set of block modes (e.g., {@code CBC}, {@code CTR}) with which the key can be used + * Gets the set of block modes (e.g., {@code GCM}, {@code CBC}) with which the key can be used * when encrypting/decrypting. Attempts to use the key with any other block modes will be * rejected. * @@ -257,22 +261,32 @@ public final class KeyProtection implements ProtectionParameter { } /** - * Returns {@code true} if user authentication is required for this key to be used. + * Returns {@code true} if the key is authorized to be used only if the user has been + * authenticated. + * + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #getUserAuthenticationValidityDurationSeconds() + * @see Builder#setUserAuthenticationRequired(boolean) */ public boolean isUserAuthenticationRequired() { return mUserAuthenticationRequired; } /** - * Gets the duration of time (seconds) for which this key can be used after the user is - * successfully authenticated. This has effect only if user authentication is required. + * Gets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect only if user authentication is required + * (see {@link #isUserAuthenticationRequired()}). + * + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @return duration in seconds or {@code -1} if authentication is required for every use of the * key. * * @see #isUserAuthenticationRequired() + * @see Builder#setUserAuthenticationValidityDurationSeconds(int) */ public int getUserAuthenticationValidityDurationSeconds() { return mUserAuthenticationValidityDurationSeconds; @@ -424,11 +438,11 @@ public final class KeyProtection implements ProtectionParameter { } /** - * Sets the set of block modes (e.g., {@code CBC}, {@code CTR}, {@code ECB}) with which the - * key can be used when encrypting/decrypting. Attempts to use the key with any other block - * modes will be rejected. + * Sets the set of block modes (e.g., {@code GCM}, {@code CBC}) with which the key can be + * used when encrypting/decrypting. Attempts to use the key with any other block modes will + * be rejected. * - * <p>This must be specified for encryption/decryption keys. + * <p>This must be specified for symmetric encryption/decryption keys. * * <p>See {@link KeyProperties}.{@code BLOCK_MODE} constants. */ @@ -453,8 +467,8 @@ public final class KeyProtection implements ProtectionParameter { * <ul> * <li>transformation which do not offer {@code IND-CPA}, such as symmetric ciphers using * {@code ECB} mode or RSA encryption without padding, are prohibited;</li> - * <li>in transformations which use an IV, such as symmetric ciphers in {@code CBC}, - * {@code CTR}, and {@code GCM} block modes, caller-provided IVs are rejected when + * <li>in transformations which use an IV, such as symmetric ciphers in {@code GCM}, + * {@code CBC}, and {@code CTR} block modes, caller-provided IVs are rejected when * encrypting, to ensure that only random IVs are used.</li> * * <p>Before disabling this requirement, consider the following approaches instead: @@ -479,19 +493,38 @@ public final class KeyProtection implements ProtectionParameter { } /** - * Sets whether user authentication is required to use this key. + * Sets whether this key is authorized to be used only if the user has been authenticated. * - * <p>By default, the key can be used without user authentication. + * <p>By default, the key is authorized to be used regardless of whether the user has been + * authenticated. * - * <p>When user authentication is required, the user authorizes the use of the key by - * authenticating to this Android device using a subset of their secure lock screen - * credentials. Different authentication methods are used depending on whether the every - * use of the key must be authenticated (as specified by - * {@link #setUserAuthenticationValidityDurationSeconds(int)}). + * <p>When user authentication is required: + * <ul> + * <li>The key can only be import if secure lock screen is set up (see + * {@link KeyguardManager#isDeviceSecure()}). Additionally, if the key requires that user + * authentication takes place for every use of the key (see + * {@link #setUserAuthenticationValidityDurationSeconds(int)}), at least one fingerprint + * must be enrolled (see {@link FingerprintManager#hasEnrolledFingerprints()}).</li> + * <li>The use of the key must be authorized by the user by authenticating to this Android + * device using a subset of their secure lock screen credentials such as + * password/PIN/pattern or fingerprint. * <a href="{@docRoot}training/articles/keystore.html#UserAuthentication">More * information</a>. + * <li>The key will become <em>irreversibly invalidated</em> once the secure lock screen is + * disabled (reconfigured to None, Swipe or other mode which does not authenticate the user) + * or when the secure lock screen is forcibly reset (e.g., by a Device Administrator). + * Additionally, if the key requires that user authentication takes place for every use of + * the key, it is also irreversibly invalidated once a new fingerprint is enrolled or once\ + * no more fingerprints are enrolled. Attempts to initialize cryptographic operations using + * such keys will throw {@link KeyPermanentlyInvalidatedException}.</li> + * </ul> + * + * <p>This authorization applies only to secret key and private key operations. Public key + * operations are not restricted. * * @see #setUserAuthenticationValidityDurationSeconds(int) + * @see KeyguardManager#isDeviceSecure() + * @see FingerprintManager#hasEnrolledFingerprints() */ @NonNull public Builder setUserAuthenticationRequired(boolean required) { @@ -500,15 +533,39 @@ public final class KeyProtection implements ProtectionParameter { } /** - * Sets the duration of time (seconds) for which this key can be used after the user is - * successfully authenticated. This has effect only if user authentication is required. + * Sets the duration of time (seconds) for which this key is authorized to be used after the + * user is successfully authenticated. This has effect if the key requires user + * authentication for its use (see {@link #setUserAuthenticationRequired(boolean)}). + * + * <p>By default, if user authentication is required, it must take place for every use of + * the key. + * + * <p>Cryptographic operations involving keys which require user authentication to take + * place for every operation can only use fingerprint authentication. This is achieved by + * initializing a cryptographic operation ({@link Signature}, {@link Cipher}, {@link Mac}) + * with the key, wrapping it into a {@link FingerprintManager.CryptoObject}, invoking + * {@code FingerprintManager.authenticate} with {@code CryptoObject}, and proceeding with + * the cryptographic operation only if the authentication flow succeeds. * - * <p>By default, the user needs to authenticate for every use of the key. + * <p>Cryptographic operations involving keys which are authorized to be used for a duration + * of time after a successful user authentication event can only use secure lock screen + * authentication. These cryptographic operations will throw + * {@link UserNotAuthenticatedException} during initialization if the user needs to be + * authenticated to proceed. This situation can be resolved by the user unlocking the secure + * lock screen of the Android or by going through the confirm credential flow initiated by + * {@link KeyguardManager#createConfirmDeviceCredentialIntent(CharSequence, CharSequence)}. + * Once resolved, initializing a new cryptographic operation using this key (or any other + * key which is authorized to be used for a fixed duration of time after user + * authentication) should succeed provided the user authentication flow completed + * successfully. * - * @param seconds duration in seconds or {@code -1} if the user needs to authenticate for - * every use of the key. + * @param seconds duration in seconds or {@code -1} if user authentication must take place + * for every use of the key. * * @see #setUserAuthenticationRequired(boolean) + * @see FingerprintManager + * @see FingerprintManager.CryptoObject + * @see KeyguardManager */ @NonNull public Builder setUserAuthenticationValidityDurationSeconds( diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java index 9957e79..894d52a 100644 --- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java +++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java @@ -73,6 +73,8 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS private byte[] mBuffered = EmptyArray.BYTE; private int mBufferedOffset; private int mBufferedLength; + private long mConsumedInputSizeBytes; + private long mProducedOutputSizeBytes; public KeyStoreCryptoOperationChunkedStreamer(Stream operation) { this(operation, DEFAULT_MAX_CHUNK_SIZE); @@ -119,6 +121,7 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS // Update input array references to reflect that some of its bytes are now in mBuffered. inputOffset += inputBytesInChunk; inputLength -= inputBytesInChunk; + mConsumedInputSizeBytes += inputBytesInChunk; OperationResult opResult = mKeyStoreStream.update(chunk); if (opResult == null) { @@ -167,9 +170,10 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS } } else { // No more output will be produced in this loop + byte[] result; if (bufferedOutput == null) { // No previously buffered output - return opResult.output; + result = opResult.output; } else { // There was some previously buffered output try { @@ -177,18 +181,23 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS } catch (IOException e) { throw new IllegalStateException("Failed to buffer output", e); } - return bufferedOutput.toByteArray(); + result = bufferedOutput.toByteArray(); } + mProducedOutputSizeBytes += result.length; + return result; } } } + byte[] result; if (bufferedOutput == null) { // No output produced - return EmptyArray.BYTE; + result = EmptyArray.BYTE; } else { - return bufferedOutput.toByteArray(); + result = bufferedOutput.toByteArray(); } + mProducedOutputSizeBytes += result.length; + return result; } @Override @@ -210,14 +219,11 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS } else if (opResult.resultCode != KeyStore.NO_ERROR) { throw KeyStore.getKeyStoreException(opResult.resultCode); } + mProducedOutputSizeBytes += opResult.output.length; return ArrayUtils.concat(output, opResult.output); } - /** - * Passes all of buffered input into the the KeyStore operation (via the {@code update} - * operation) and returns output. - */ public byte[] flush() throws KeyStoreException { if (mBufferedLength <= 0) { return EmptyArray.BYTE; @@ -243,7 +249,19 @@ class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationS + " . Provided: " + chunk.length + ", consumed: " + opResult.inputConsumed); } - return (opResult.output != null) ? opResult.output : EmptyArray.BYTE; + byte[] result = (opResult.output != null) ? opResult.output : EmptyArray.BYTE; + mProducedOutputSizeBytes += result.length; + return result; + } + + @Override + public long getConsumedInputSizeBytes() { + return mConsumedInputSizeBytes; + } + + @Override + public long getProducedOutputSizeBytes() { + return mProducedOutputSizeBytes; } /** diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java index 1c6de2d..897bd71 100644 --- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java +++ b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java @@ -37,4 +37,6 @@ interface KeyStoreCryptoOperationStreamer { byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException; byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] additionalEntropy) throws KeyStoreException; + long getConsumedInputSizeBytes(); + long getProducedOutputSizeBytes(); } diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl index a3ea896..f3d755c 100644 --- a/location/java/android/location/ILocationManager.aidl +++ b/location/java/android/location/ILocationManager.aidl @@ -75,6 +75,7 @@ interface ILocationManager String getBestProvider(in Criteria criteria, boolean enabledOnly); boolean providerMeetsCriteria(String provider, in Criteria criteria); ProviderProperties getProviderProperties(String provider); + String getNetworkProviderPackage(); boolean isProviderEnabled(String provider); void addTestProvider(String name, in ProviderProperties properties, String opPackageName); diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java index 3cbc405..974b62e 100644 --- a/media/java/android/media/AudioRecord.java +++ b/media/java/android/media/AudioRecord.java @@ -527,10 +527,11 @@ public class AudioRecord } /** - * @return a new {@link AudioRecord} instance initialized with all the parameters set - * on this <code>Builder</code> + * @return a new {@link AudioRecord} instance successfully initialized with all + * the parameters set on this <code>Builder</code>. * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code> - * were incompatible, or if they are not supported by the device. + * were incompatible, or if they are not supported by the device, + * or if the device was not available. */ public AudioRecord build() throws UnsupportedOperationException { if (mFormat == null) { @@ -564,7 +565,13 @@ public class AudioRecord mBufferSizeInBytes = mFormat.getChannelCount() * mFormat.getBytesPerSample(mFormat.getEncoding()); } - return new AudioRecord(mAttributes, mFormat, mBufferSizeInBytes, mSessionId); + final AudioRecord record = new AudioRecord( + mAttributes, mFormat, mBufferSizeInBytes, mSessionId); + if (record.getState() == STATE_UNINITIALIZED) { + // release is not necessary + throw new UnsupportedOperationException("Cannot create AudioRecord"); + } + return record; } catch (IllegalArgumentException e) { throw new UnsupportedOperationException(e.getMessage()); } diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java index f395cb3..62810c6 100644 --- a/media/java/android/media/AudioTrack.java +++ b/media/java/android/media/AudioTrack.java @@ -661,9 +661,10 @@ public class AudioTrack /** * Builds an {@link AudioTrack} instance initialized with all the parameters set * on this <code>Builder</code>. - * @return a new {@link AudioTrack} instance. + * @return a new successfully initialized {@link AudioTrack} instance. * @throws UnsupportedOperationException if the parameters set on the <code>Builder</code> - * were incompatible, or if they are not supported by the device. + * were incompatible, or if they are not supported by the device, + * or if the device was not available. */ public @NonNull AudioTrack build() throws UnsupportedOperationException { if (mAttributes == null) { @@ -686,7 +687,13 @@ public class AudioTrack mBufferSizeInBytes = mFormat.getChannelCount() * mFormat.getBytesPerSample(mFormat.getEncoding()); } - return new AudioTrack(mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId); + final AudioTrack track = new AudioTrack( + mAttributes, mFormat, mBufferSizeInBytes, mMode, mSessionId); + if (track.getState() == STATE_UNINITIALIZED) { + // release is not necessary + throw new UnsupportedOperationException("Cannot create AudioTrack"); + } + return track; } catch (IllegalArgumentException e) { throw new UnsupportedOperationException(e.getMessage()); } diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl index 8e96218..c75c7e5 100644 --- a/media/java/android/media/IAudioService.aidl +++ b/media/java/android/media/IAudioService.aidl @@ -40,7 +40,7 @@ import android.view.KeyEvent; */ interface IAudioService { - void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, + oneway void adjustSuggestedStreamVolume(int direction, int suggestedStreamType, int flags, String callingPackage, String caller); void adjustStreamVolume(int streamType, int direction, int flags, String callingPackage); diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp index 634ba64..ba7634c 100644 --- a/media/jni/android_media_ImageWriter.cpp +++ b/media/jni/android_media_ImageWriter.cpp @@ -361,8 +361,7 @@ static void ImageWriter_close(JNIEnv* env, jobject thiz, jlong nativeCtx) { ALOGV("%s:", __FUNCTION__); JNIImageWriterContext* const ctx = reinterpret_cast<JNIImageWriterContext *>(nativeCtx); if (ctx == NULL || thiz == NULL) { - jniThrowException(env, "java/lang/IllegalStateException", - "ImageWriterContext is not initialized"); + // ImageWriter is already closed. return; } diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java index 90ccf91..fe148da 100644 --- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java +++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java @@ -393,25 +393,23 @@ public class DocumentsActivity extends BaseActivity { @Override public void updateActionBar() { if (mRootsToolbar != null) { - if (mState.action == ACTION_OPEN || - mState.action == ACTION_GET_CONTENT || - mState.action == ACTION_OPEN_TREE) { - mRootsToolbar.setTitle(R.string.title_open); - } else if (mState.action == ACTION_CREATE || - mState.action == ACTION_OPEN_COPY_DESTINATION) { - mRootsToolbar.setTitle(R.string.title_save); + final String prompt = getIntent().getStringExtra(DocumentsContract.EXTRA_PROMPT); + if (prompt != null) { + mRootsToolbar.setTitle(prompt); + } else { + if (mState.action == ACTION_OPEN || + mState.action == ACTION_GET_CONTENT || + mState.action == ACTION_OPEN_TREE) { + mRootsToolbar.setTitle(R.string.title_open); + } else if (mState.action == ACTION_CREATE || + mState.action == ACTION_OPEN_COPY_DESTINATION) { + mRootsToolbar.setTitle(R.string.title_save); + } } } - final RootInfo root = getCurrentRoot(); - final boolean showRootIcon = mShowAsDialog - || (mState.action == ACTION_MANAGE || mState.action == ACTION_BROWSE); - if (showRootIcon) { - mToolbar.setNavigationIcon( - root != null ? root.loadToolbarIcon(mToolbar.getContext()) : null); - mToolbar.setNavigationContentDescription(R.string.drawer_open); - mToolbar.setNavigationOnClickListener(null); - } else { + if (!mShowAsDialog && mDrawerLayout.getDrawerLockMode(mRootsDrawer) == + DrawerLayout.LOCK_MODE_UNLOCKED) { mToolbar.setNavigationIcon(R.drawable.ic_hamburger); mToolbar.setNavigationContentDescription(R.string.drawer_open); mToolbar.setNavigationOnClickListener(new View.OnClickListener() { @@ -420,6 +418,10 @@ public class DocumentsActivity extends BaseActivity { setRootsDrawerOpen(true); } }); + } else { + mToolbar.setNavigationIcon(null); + mToolbar.setNavigationContentDescription(R.string.drawer_open); + mToolbar.setNavigationOnClickListener(null); } if (mSearchManager.isExpanded()) { @@ -428,7 +430,7 @@ public class DocumentsActivity extends BaseActivity { mToolbarStack.setAdapter(null); } else { if (mState.stack.size() <= 1) { - mToolbar.setTitle(root.title); + mToolbar.setTitle(getCurrentRoot().title); mToolbarStack.setVisibility(View.GONE); mToolbarStack.setAdapter(null); } else { diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java index 442af90..89c456c 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java +++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java @@ -316,14 +316,12 @@ public class Recents extends SystemUI void hideRecentsInternal(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { if (mBootCompleted) { - ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask(); - if (topTask != null && mSystemServicesProxy.isRecentsTopMost(topTask, null)) { - // Notify recents to hide itself - Intent intent = createLocalBroadcastIntent(mContext, ACTION_HIDE_RECENTS_ACTIVITY); - intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab); - intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey); - mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); - } + // Defer to the activity to handle hiding recents, if it handles it, then it must still + // be visible + Intent intent = createLocalBroadcastIntent(mContext, ACTION_HIDE_RECENTS_ACTIVITY); + intent.putExtra(EXTRA_TRIGGERED_FROM_ALT_TAB, triggeredFromAltTab); + intent.putExtra(EXTRA_TRIGGERED_FROM_HOME_KEY, triggeredFromHomeKey); + mContext.sendBroadcastAsUser(intent, UserHandle.CURRENT); } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index 3885799..3cd769e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -134,9 +134,9 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView dismissRecentsToFocusedTaskOrHome(false); } else if (intent.getBooleanExtra(Recents.EXTRA_TRIGGERED_FROM_HOME_KEY, false)) { // Otherwise, dismiss Recents to Home - dismissRecentsToHome(true); + dismissRecentsToHomeRaw(true); } else { - // Do nothing, another activity is being launched on top of Recents + // Do nothing } } else if (action.equals(Recents.ACTION_TOGGLE_RECENTS_ACTIVITY)) { // If we are toggling Recents, then first unfilter any filtered stacks first diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java index 02a7b94..d4e50f8 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsAppWidgetHost.java @@ -70,6 +70,7 @@ public class RecentsAppWidgetHost extends AppWidgetHost { @Override protected void onProviderChanged(int appWidgetId, AppWidgetProviderInfo appWidgetInfo) { if (mCb == null) return; + if (mContext == null) return; SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy(); if (appWidgetId > -1 && appWidgetId == mConfig.searchBarAppWidgetId) { 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 5711cd6..ebfc796 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -22,10 +22,12 @@ import android.content.Context; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Rect; +import android.os.Bundle; import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.accessibility.AccessibilityEvent; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; import com.android.systemui.R; import com.android.systemui.recents.Constants; @@ -133,6 +135,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } }); + setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES); } /** Sets the callbacks */ @@ -350,6 +353,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mTmpTaskViewMap.clear(); List<TaskView> taskViews = getTaskViews(); int taskViewCount = taskViews.size(); + boolean reaquireAccessibilityFocus = false; for (int i = taskViewCount - 1; i >= 0; i--) { TaskView tv = taskViews.get(i); Task task = tv.getTask(); @@ -358,6 +362,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mTmpTaskViewMap.put(task, tv); } else { mViewPool.returnViewToPool(tv); + reaquireAccessibilityFocus |= (i == mPrevAccessibilityFocusedIndex); // Hide the dismiss button if the front most task is invisible if (task == mStack.getFrontMostTask()) { @@ -402,14 +407,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Request accessibility focus on the next view if we removed the task // that previously held accessibility focus - taskViews = getTaskViews(); - taskViewCount = taskViews.size(); - if (taskViewCount > 0 && ssp.isTouchExplorationEnabled()) { - TaskView atv = taskViews.get(taskViewCount - 1); - int indexOfTask = mStack.indexOfTask(atv.getTask()); - if (mPrevAccessibilityFocusedIndex != indexOfTask) { - tv.requestAccessibilityFocus(); - mPrevAccessibilityFocusedIndex = indexOfTask; + if (reaquireAccessibilityFocus) { + taskViews = getTaskViews(); + taskViewCount = taskViews.size(); + if (taskViewCount > 0 && ssp.isTouchExplorationEnabled() && + mPrevAccessibilityFocusedIndex != -1) { + TaskView atv = taskViews.get(taskViewCount - 1); + int indexOfTask = mStack.indexOfTask(atv.getTask()); + if (mPrevAccessibilityFocusedIndex != indexOfTask) { + tv.requestAccessibilityFocus(); + mPrevAccessibilityFocusedIndex = indexOfTask; + } } } } @@ -496,25 +504,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) { mFocusedTaskIndex = taskIndex; + mPrevAccessibilityFocusedIndex = taskIndex; // Focus the view if possible, otherwise, focus the view after we scroll into position - Task t = mStack.getTasks().get(taskIndex); - TaskView tv = getChildViewForTask(t); - Runnable postScrollRunnable = null; - if (tv != null) { - tv.setFocusedTask(animateFocusedState); - } else { - postScrollRunnable = new Runnable() { - @Override - public void run() { - Task t = mStack.getTasks().get(mFocusedTaskIndex); - TaskView tv = getChildViewForTask(t); - if (tv != null) { - tv.setFocusedTask(animateFocusedState); - } + final Task t = mStack.getTasks().get(mFocusedTaskIndex); + Runnable postScrollRunnable = new Runnable() { + @Override + public void run() { + TaskView tv = getChildViewForTask(t); + if (tv != null) { + tv.setFocusedTask(animateFocusedState); + tv.requestAccessibilityFocus(); } - }; - } + } + }; // Scroll the view into position (just center it in the curve) if (scrollToNewPosition) { @@ -534,25 +537,30 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal * Ensures that there is a task focused, if nothing is focused, then we will use the task * at the center of the visible stack. */ - public boolean ensureFocusedTask() { + public boolean ensureFocusedTask(boolean findClosestToCenter) { 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(); List<TaskView> taskViews = getTaskViews(); int taskViewCount = taskViews.size(); - for (int i = taskViewCount - 1; i >= 0; i--) { - TaskView tv = taskViews.get(i); - tv.getHitRect(mTmpRect); - if (mTmpRect.contains(x, y)) { - mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); - break; + if (findClosestToCenter) { + // 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(); + for (int i = taskViewCount - 1; i >= 0; i--) { + TaskView tv = taskViews.get(i); + tv.getHitRect(mTmpRect); + if (mTmpRect.contains(x, y)) { + mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); + mPrevAccessibilityFocusedIndex = mFocusedTaskIndex; + break; + } } } // If we can't find the center task, then use the front most index if (mFocusedTaskIndex < 0 && taskViewCount > 0) { - mFocusedTaskIndex = taskViewCount - 1; + TaskView tv = taskViews.get(taskViewCount - 1); + mFocusedTaskIndex = mStack.indexOfTask(tv.getTask()); + mPrevAccessibilityFocusedIndex = mFocusedTaskIndex; } } return mFocusedTaskIndex >= 0; @@ -600,6 +608,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } } mFocusedTaskIndex = -1; + mPrevAccessibilityFocusedIndex = -1; } @Override @@ -620,6 +629,53 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } @Override + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + List<TaskView> taskViews = getTaskViews(); + int taskViewCount = taskViews.size(); + if (taskViewCount > 1 && mPrevAccessibilityFocusedIndex != -1) { + info.setScrollable(true); + if (mPrevAccessibilityFocusedIndex > 0) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } + if (mPrevAccessibilityFocusedIndex < mStack.getTaskCount() - 1) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + } + } + } + + @Override + public CharSequence getAccessibilityClassName() { + return TaskStackView.class.getName(); + } + + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + if (super.performAccessibilityAction(action, arguments)) { + return true; + } + if (ensureFocusedTask(false)) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + if (mPrevAccessibilityFocusedIndex > 0) { + focusNextTask(true, false); + return true; + } + } + break; + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + if (mPrevAccessibilityFocusedIndex < mStack.getTaskCount() - 1) { + focusNextTask(false, false); + return true; + } + } + break; + } + } + return false; + } + + @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return mTouchHandler.onInterceptTouchEvent(ev); } @@ -724,8 +780,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (mDismissAllButton != null) { int taskRectWidth = mLayoutAlgorithm.mTaskRect.width(); mDismissAllButton.measure( - MeasureSpec.makeMeasureSpec(taskRectWidth, MeasureSpec.EXACTLY), - MeasureSpec.makeMeasureSpec(mConfig.dismissAllButtonSizePx, MeasureSpec.EXACTLY)); + MeasureSpec.makeMeasureSpec(taskRectWidth, MeasureSpec.EXACTLY), + MeasureSpec.makeMeasureSpec(mConfig.dismissAllButtonSizePx, MeasureSpec.EXACTLY)); } setMeasuredDimension(width, height); 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 509560eb..13bdbd2 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -396,11 +396,11 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { // 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()) { + if (mSv.ensureFocusedTask(true)) { mSv.focusNextTask(true, false); } } else { - if (mSv.ensureFocusedTask()) { + if (mSv.ensureFocusedTask(true)) { mSv.focusNextTask(false, false); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java index 79761ec..a496548 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java @@ -41,6 +41,7 @@ import android.content.res.Resources; import android.database.ContentObserver; import android.graphics.PorterDuff; import android.graphics.drawable.Drawable; +import android.graphics.drawable.Icon; import android.os.AsyncTask; import android.os.Build; import android.os.Handler; @@ -1396,6 +1397,7 @@ public abstract class BaseStatusBar extends SystemUI implements final StatusBarIcon ic = new StatusBarIcon( entry.notification.getUser(), + entry.notification.getPackageName(), entry.notification.getNotification().getSmallIcon(), entry.notification.getNotification().iconLevel, entry.notification.getNotification().number, @@ -1682,10 +1684,11 @@ public abstract class BaseStatusBar extends SystemUI implements final StatusBarIcon ic = new StatusBarIcon( sbn.getUser(), - n.getSmallIcon(), - n.iconLevel, - n.number, - n.tickerText); + sbn.getPackageName(), + n.getSmallIcon(), + n.iconLevel, + n.number, + n.tickerText); if (!iconView.set(ic)) { handleNotificationError(sbn, "Couldn't create icon: " + ic); return null; @@ -1825,6 +1828,7 @@ public abstract class BaseStatusBar extends SystemUI implements // Update the icon final StatusBarIcon ic = new StatusBarIcon( notification.getUser(), + notification.getPackageName(), n.getSmallIcon(), n.iconLevel, n.number, @@ -1847,6 +1851,7 @@ public abstract class BaseStatusBar extends SystemUI implements if (DEBUG) Log.d(TAG, "not reusing notification for key: " + key); final StatusBarIcon ic = new StatusBarIcon( notification.getUser(), + notification.getPackageName(), n.getSmallIcon(), n.iconLevel, n.number, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java index dbabe3f..aedae52 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java @@ -125,16 +125,22 @@ public class NotificationData { @Override public int compare(Entry a, Entry b) { - String mediaNotification = mEnvironment.getCurrentMediaNotificationKey(); - boolean aMedia = a.key.equals(mediaNotification); - boolean bMedia = b.key.equals(mediaNotification); - final StatusBarNotification na = a.notification; final StatusBarNotification nb = b.notification; + final int aPriority = na.getNotification().priority; + final int bPriority = nb.getNotification().priority; + + String mediaNotification = mEnvironment.getCurrentMediaNotificationKey(); + + // PRIORITY_MIN media streams are allowed to drift to the bottom + final boolean aMedia = a.key.equals(mediaNotification) + && aPriority > Notification.PRIORITY_MIN; + final boolean bMedia = b.key.equals(mediaNotification) + && bPriority > Notification.PRIORITY_MIN; - boolean aSystemMax = na.getNotification().priority >= Notification.PRIORITY_MAX && + boolean aSystemMax = aPriority >= Notification.PRIORITY_MAX && isSystemNotification(na); - boolean bSystemMax = nb.getNotification().priority >= Notification.PRIORITY_MAX && + boolean bSystemMax = bPriority >= Notification.PRIORITY_MAX && isSystemNotification(nb); int d = nb.getScore() - na.getScore(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java index 9e0b08b..5a4acb4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java @@ -251,6 +251,9 @@ public class SignalClusterView @Override public void setSubs(List<SubscriptionInfo> subs) { + if (hasCorrectSubs(subs)) { + return; + } // Clear out all old subIds. mPhoneStates.clear(); if (mMobileSignalGroup != null) { @@ -265,6 +268,19 @@ public class SignalClusterView } } + private boolean hasCorrectSubs(List<SubscriptionInfo> subs) { + final int N = subs.size(); + if (N != mPhoneStates.size()) { + return false; + } + for (int i = 0; i < N; i++) { + if (mPhoneStates.get(i).mSubId != subs.get(i).getSubscriptionId()) { + return false; + } + } + return true; + } + private PhoneState getOrInflateState(int subId) { for (PhoneState state : mPhoneStates) { if (state.mSubId == subId) { 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 26d1c86..fcdd4b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java @@ -124,6 +124,9 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { private void updateSlot(String slot, String iconPkg, int iconId) { if (!mDemoMode) return; + if (iconPkg == null) { + iconPkg = mContext.getPackageName(); + } int removeIndex = -1; for (int i = 0; i < getChildCount(); i++) { StatusBarIconView v = (StatusBarIconView) getChildAt(i); @@ -143,10 +146,10 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode { if (iconId == 0) { if (removeIndex != -1) { removeViewAt(removeIndex); - return; } + return; } - StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.CURRENT, iconId, 0, 0, "Demo"); + StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.OWNER, iconId, 0, 0, "Demo"); StatusBarIconView v = new StatusBarIconView(getContext(), null, null); v.setTag(slot); v.set(icon); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java index f57575d..10c35af 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpTouchHelper.java @@ -110,6 +110,8 @@ public class HeadsUpTouchHelper implements Gefingerpoken { mInitialTouchX = x; mInitialTouchY = y; int expandedHeight = mPickedChild.getActualHeight(); + mPanel.setPanelScrimMinFraction((float) expandedHeight + / mPanel.getMaxPanelHeight()); mPanel.startExpandMotion(x, y, true /* startTracking */, expandedHeight + mNotificationsTopPadding); mHeadsUpManager.unpinAll(); 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 5ac436a..c30cb34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java @@ -491,7 +491,7 @@ public class NotificationPanelView extends PanelView implements } public void closeQs() { - cancelAnimation(); + cancelQsAnimation(); setQsExpansion(mQsMinExpansionHeight); } @@ -508,7 +508,7 @@ public class NotificationPanelView extends PanelView implements } public void openQs() { - cancelAnimation(); + cancelQsAnimation(); if (mQsExpansionEnabled) { setQsExpansion(mQsMaxExpansionHeight); } @@ -921,7 +921,7 @@ public class NotificationPanelView extends PanelView implements @Override public void onOverscrollTopChanged(float amount, boolean isRubberbanded) { - cancelAnimation(); + cancelQsAnimation(); if (!mQsExpansionEnabled) { amount = 0f; } @@ -953,7 +953,8 @@ public class NotificationPanelView extends PanelView implements } private void onQsExpansionStarted(int overscrollAmount) { - cancelAnimation(); + cancelQsAnimation(); + cancelHeightAnimator(); // Reset scroll position and apply that position to the expanded height. float height = mQsExpansionHeight - mScrollView.getScrollY() - overscrollAmount; @@ -1391,7 +1392,7 @@ public class NotificationPanelView extends PanelView implements return mVelocityTracker.getYVelocity(); } - private void cancelAnimation() { + private void cancelQsAnimation() { if (mQsExpansionAnimator != null) { mQsExpansionAnimator.cancel(); } @@ -1767,6 +1768,7 @@ public class NotificationPanelView extends PanelView implements mIsExpansionFromHeadsUp = false; mNotificationStackScroller.setTrackingHeadsUp(false); mExpandingFromHeadsUp = false; + setPanelScrimMinFraction(0.0f); } private void setListening(boolean listening) { @@ -2317,7 +2319,7 @@ public class NotificationPanelView extends PanelView implements } x = Math.min(rightMost, Math.max(leftMost, x)); setVerticalPanelTranslation(x - - (mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth()/2)); + (mNotificationStackScroller.getLeft() + mNotificationStackScroller.getWidth() / 2)); } private void resetVerticalPanelPosition() { @@ -2334,4 +2336,8 @@ public class NotificationPanelView extends PanelView implements mNotificationStackScroller.setStackHeight(stackHeight); updateKeyguardBottomAreaAlpha(); } + + public void setPanelScrimMinFraction(float minFraction) { + mBar.panelScrimMinFractionChanged(minFraction); + } } 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 552a0b2..cf553ec 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java @@ -25,7 +25,7 @@ import android.widget.FrameLayout; import java.util.ArrayList; -public class PanelBar extends FrameLayout { +public abstract class PanelBar extends FrameLayout { public static final boolean DEBUG = false; public static final String TAG = PanelBar.class.getSimpleName(); public static final void LOG(String fmt, Object... args) { @@ -156,6 +156,8 @@ public class PanelBar extends FrameLayout { } } + public abstract void panelScrimMinFractionChanged(float minFraction); + /** * @param panel the panel which changed its expansion state * @param frac the fraction from the expansion in [0, 1] 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 9d4997c..094d5f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java @@ -535,7 +535,7 @@ public abstract class PanelView extends FrameLayout { */ protected abstract boolean isInContentBounds(float x, float y); - private void cancelHeightAnimator() { + protected void cancelHeightAnimator() { if (mHeightAnimator != null) { mHeightAnimator.cancel(); } 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 69198ed..cd90d27 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java @@ -3460,6 +3460,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode, mKeyguardIndicationController.setVisible(true); mNotificationPanel.resetViews(); mKeyguardUserSwitcher.setKeyguard(true, fromShadeLocked); + mStatusBarView.removePendingHideExpandedRunnables(); } else { mKeyguardIndicationController.setVisible(false); mKeyguardUserSwitcher.setKeyguard(false, 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 b7e675d..6a46924 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java @@ -40,6 +40,14 @@ public class PhoneStatusBarView extends PanelBar { PanelView mNotificationPanel; private final PhoneStatusBarTransitions mBarTransitions; private ScrimController mScrimController; + private float mMinFraction; + private float mPanelFraction; + private Runnable mHideExpandedRunnable = new Runnable() { + @Override + public void run() { + mBar.makeExpandedInvisible(); + } + }; public PhoneStatusBarView(Context context, AttributeSet attrs) { super(context, attrs); @@ -116,15 +124,14 @@ public class PhoneStatusBarView extends PanelBar { + Log.getStackTraceString(new Throwable())); } // Close the status bar in the next frame so we can show the end of the animation. - postOnAnimation(new Runnable() { - @Override - public void run() { - mBar.makeExpandedInvisible(); - } - }); + postOnAnimation(mHideExpandedRunnable); mLastFullyOpenedPanel = null; } + public void removePendingHideExpandedRunnables() { + removeCallbacks(mHideExpandedRunnable); + } + @Override public void onPanelFullyOpened(PanelView openPanel) { super.onPanelFullyOpened(openPanel); @@ -180,8 +187,22 @@ public class PhoneStatusBarView extends PanelBar { } @Override + public void panelScrimMinFractionChanged(float minFraction) { + if (mMinFraction != minFraction) { + mMinFraction = minFraction; + updateScrimFraction(); + } + } + + @Override public void panelExpansionChanged(PanelView panel, float frac, boolean expanded) { super.panelExpansionChanged(panel, frac, expanded); - mScrimController.setPanelExpansion(frac); + mPanelFraction = frac; + updateScrimFraction(); + } + + private void updateScrimFraction() { + float scrimFraction = Math.max(mPanelFraction - mMinFraction / (1.0f - mMinFraction), 0); + mScrimController.setPanelExpansion(scrimFraction); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java index 0eb7197..d1e4963 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/AccessPointControllerImpl.java @@ -116,7 +116,7 @@ public class AccessPointControllerImpl // Unknown network, need to add it. if (ap.getSecurity() != AccessPoint.SECURITY_NONE) { Intent intent = new Intent(Settings.ACTION_WIFI_SETTINGS); - intent.putExtra(EXTRA_START_CONNECT_SSID, ap.getSsid()); + intent.putExtra(EXTRA_START_CONNECT_SSID, ap.getSsidStr()); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); fireSettingsIntentCallback(intent); return true; 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 18b5820..1ba87da 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -408,7 +408,7 @@ public class NetworkControllerImpl extends BroadcastReceiver boolean hasNoSims = mHasMobileDataFeature && mMobileSignalControllers.size() == 0; if (hasNoSims != mHasNoSims) { mHasNoSims = hasNoSims; - notifyListeners(); + mCallbackHandler.setNoSims(mHasNoSims); } } @@ -660,8 +660,8 @@ public class NetworkControllerImpl extends BroadcastReceiver } String nosim = args.getString("nosim"); if (nosim != null) { - boolean show = nosim.equals("show"); - mCallbackHandler.setNoSims(show); + mHasNoSims = nosim.equals("show"); + mCallbackHandler.setNoSims(mHasNoSims); } String mobile = args.getString("mobile"); if (mobile != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java index 1bf4547..5700732 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java @@ -228,6 +228,7 @@ public class NotificationStackScrollLayout extends ViewGroup private ScrimController mScrimController; private boolean mForceNoOverlappingRendering; private NotificationOverflowContainer mOverflowContainer; + private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>(); public NotificationStackScrollLayout(Context context) { this(context, null); @@ -1608,7 +1609,7 @@ public class NotificationStackScrollLayout extends ViewGroup } @Override - protected void onViewRemoved(View child) { + public void onViewRemoved(View child) { super.onViewRemoved(child); // we only call our internal methods if this is actually a removal and not just a // notification which becomes a child notification @@ -1651,8 +1652,7 @@ public class NotificationStackScrollLayout extends ViewGroup * @return Whether an animation was generated. */ private boolean generateRemoveAnimation(View child) { - if (mAddedHeadsUpChildren.contains(child)) { - removeChildFromHeadsUpChangeAnimations(child); + if (removeRemovedChildFromHeadsUpChangeAnimations(child)) { mAddedHeadsUpChildren.remove(child); return false; } @@ -1671,15 +1671,27 @@ public class NotificationStackScrollLayout extends ViewGroup return false; } - private void removeChildFromHeadsUpChangeAnimations(View child) { - ArrayList<Pair<ExpandableNotificationRow, Boolean> > toRemove = new ArrayList<>(); + /** + * Remove a removed child view from the heads up animations if it was just added there + * + * @return whether any child was removed from the list to animate + */ + private boolean removeRemovedChildFromHeadsUpChangeAnimations(View child) { + boolean hasAddEvent = false; for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) { ExpandableNotificationRow row = eventPair.first; + boolean isHeadsUp = eventPair.second; if (child == row) { - toRemove.add(eventPair); + mTmpList.add(eventPair); + hasAddEvent |= isHeadsUp; } } - mHeadsUpChangeAnimations.removeAll(toRemove); + if (hasAddEvent) { + // This child was just added lets remove all events. + mHeadsUpChangeAnimations.removeAll(mTmpList); + } + mTmpList.clear(); + return hasAddEvent; } /** @@ -1745,7 +1757,7 @@ public class NotificationStackScrollLayout extends ViewGroup } @Override - protected void onViewAdded(View child) { + public void onViewAdded(View child) { super.onViewAdded(child); onViewAddedInternal(child); } diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java index d9f0598..ca6aaeb 100644 --- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java +++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java @@ -131,11 +131,14 @@ public class DemoModeFragment extends PreferenceFragment implements OnPreference intent.putExtra("mobile", "show"); intent.putExtra("sims", "1"); intent.putExtra("nosim", "false"); - intent.putExtra("fully", "true"); intent.putExtra("level", "4"); intent.putExtra("datatypel", ""); getContext().sendBroadcast(intent); + // Need to send this after so that the sim controller already exists. + intent.putExtra("fully", "true"); + getContext().sendBroadcast(intent); + intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_BATTERY); intent.putExtra("level", "100"); intent.putExtra("plugged", "false"); diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java index 12dca94..893c939 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/Events.java +++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java @@ -16,11 +16,13 @@ package com.android.systemui.volume; +import android.content.Context; import android.media.AudioManager; import android.media.AudioSystem; import android.provider.Settings.Global; import android.util.Log; +import com.android.internal.logging.MetricsLogger; import com.android.systemui.volume.VolumeDialogController.State; import java.util.Arrays; @@ -47,6 +49,7 @@ public class Events { public static final int EVENT_ZEN_MODE_CHANGED = 13; // (mode|int) public static final int EVENT_SUPPRESSOR_CHANGED = 14; // (component|string) (name|string) public static final int EVENT_MUTE_CHANGED = 15; // (stream|int) (muted|bool) + public static final int EVENT_TOUCH_LEVEL_DONE = 16; // (stream|int) (level|bool) private static final String[] EVENT_TAGS = { "show_dialog", @@ -65,6 +68,7 @@ public class Events { "zen_mode_changed", "suppressor_changed", "mute_changed", + "touch_level_done", }; public static final int DISMISS_REASON_UNKNOWN = 0; @@ -100,36 +104,59 @@ public class Events { public static Callback sCallback; - public static void writeEvent(int tag, Object... list) { + public static void writeEvent(Context context, int tag, Object... list) { final long time = System.currentTimeMillis(); final StringBuilder sb = new StringBuilder("writeEvent ").append(EVENT_TAGS[tag]); if (list != null && list.length > 0) { sb.append(" "); switch (tag) { case EVENT_SHOW_DIALOG: + MetricsLogger.visible(context, MetricsLogger.VOLUME_DIALOG); + MetricsLogger.histogram(context, "volume_from_keyguard", + (Boolean) list[1] ? 1 : 0); sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]); break; case EVENT_EXPAND: + MetricsLogger.visibility(context, MetricsLogger.VOLUME_DIALOG_DETAILS, + (Boolean) list[0]); sb.append(list[0]); break; case EVENT_DISMISS_DIALOG: + MetricsLogger.hidden(context, MetricsLogger.VOLUME_DIALOG); sb.append(DISMISS_REASONS[(Integer) list[0]]); break; case EVENT_ACTIVE_STREAM_CHANGED: + MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_STREAM, + (Integer) list[0]); sb.append(AudioSystem.streamToString((Integer) list[0])); break; case EVENT_ICON_CLICK: + MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_ICON, + (Integer) list[1]); sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ') .append(iconStateToString((Integer) list[1])); break; + case EVENT_TOUCH_LEVEL_DONE: + MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_SLIDER, + (Integer) list[1]); + // fall through case EVENT_TOUCH_LEVEL_CHANGED: case EVENT_LEVEL_CHANGED: case EVENT_MUTE_CHANGED: sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ') .append(list[1]); break; - case EVENT_INTERNAL_RINGER_MODE_CHANGED: + case EVENT_KEY: + MetricsLogger.action(context, MetricsLogger.ACTION_VOLUME_KEY, + (Integer) list[1]); + sb.append(AudioSystem.streamToString((Integer) list[0])).append(' ') + .append(list[1]); + break; case EVENT_EXTERNAL_RINGER_MODE_CHANGED: + MetricsLogger.action(context, MetricsLogger.ACTION_RINGER_MODE, + (Integer) list[0]); + // fall through + case EVENT_INTERNAL_RINGER_MODE_CHANGED: sb.append(ringerModeToString((Integer) list[0])); break; case EVENT_ZEN_MODE_CHANGED: diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java index aa891b6..5b2eb84 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java @@ -369,7 +369,7 @@ public class VolumeDialog { row.icon.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - Events.writeEvent(Events.EVENT_ICON_CLICK, row.stream, row.iconState); + Events.writeEvent(mContext, Events.EVENT_ICON_CLICK, row.stream, row.iconState); mController.setActiveStream(row.stream); if (row.stream == AudioManager.STREAM_RING) { final boolean hasVibrator = mController.hasVibrator(); @@ -417,7 +417,7 @@ public class VolumeDialog { if (mShowing) return; mShowing = true; mDialog.show(); - Events.writeEvent(Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked()); + Events.writeEvent(mContext, Events.EVENT_SHOW_DIALOG, reason, mKeyguard.isKeyguardLocked()); mController.notifyVisible(true); } @@ -444,7 +444,7 @@ public class VolumeDialog { if (!mShowing) return; mShowing = false; mDialog.dismiss(); - Events.writeEvent(Events.EVENT_DISMISS_DIALOG, reason); + Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason); setExpandedH(false); mController.notifyVisible(false); synchronized (mSafetyWarningLock) { @@ -834,7 +834,7 @@ public class VolumeDialog { public void onClick(View v) { if (mExpanding) return; final boolean newExpand = !mExpanded; - Events.writeEvent(Events.EVENT_EXPAND, v); + Events.writeEvent(mContext, Events.EVENT_EXPAND, newExpand); setExpandedH(newExpand); } }; @@ -845,7 +845,7 @@ public class VolumeDialog { mSettingsButton.postDelayed(new Runnable() { @Override public void run() { - Events.writeEvent(Events.EVENT_SETTINGS_CLICK); + Events.writeEvent(mContext, Events.EVENT_SETTINGS_CLICK); if (mCallback != null) { mCallback.onSettingsClicked(); } @@ -933,7 +933,8 @@ public class VolumeDialog { if (mRow.requestedLevel != userLevel) { mController.setStreamVolume(mRow.stream, userLevel); mRow.requestedLevel = userLevel; - Events.writeEvent(Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream, userLevel); + Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream, + userLevel); } } } @@ -951,6 +952,7 @@ public class VolumeDialog { mRow.tracking = false; mRow.userAttempt = SystemClock.uptimeMillis(); int userLevel = getImpliedLevel(seekBar, seekBar.getProgress()); + Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel); if (mRow.ss.level != userLevel) { mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow), USER_ATTEMPT_GRACE_PERIOD); diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java index c6d9e46..9a59a2a 100644 --- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java +++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogController.java @@ -104,7 +104,7 @@ public class VolumeDialogController { public VolumeDialogController(Context context, ComponentName component) { mContext = context.getApplicationContext(); - Events.writeEvent(Events.EVENT_COLLECTION_STARTED); + Events.writeEvent(mContext, Events.EVENT_COLLECTION_STARTED); mComponent = component; mWorkerThread = new HandlerThread(VolumeDialogController.class.getSimpleName()); mWorkerThread.start(); @@ -168,7 +168,7 @@ public class VolumeDialogController { if (D.BUG) Log.d(TAG, "destroy"); if (mDestroyed) return; mDestroyed = true; - Events.writeEvent(Events.EVENT_COLLECTION_STOPPED); + Events.writeEvent(mContext, Events.EVENT_COLLECTION_STOPPED); mMediaSessions.destroy(); mObserver.destroy(); mReceiver.destroy(); @@ -293,7 +293,8 @@ public class VolumeDialogController { if (showUI) { changed |= updateActiveStreamW(stream); } - changed |= updateStreamLevelW(stream, mAudio.getLastAudibleStreamVolume(stream)); + int lastAudibleStreamVolume = mAudio.getLastAudibleStreamVolume(stream); + changed |= updateStreamLevelW(stream, lastAudibleStreamVolume); changed |= checkRoutedToBluetoothW(showUI ? AudioManager.STREAM_MUSIC : stream); if (changed) { mCallbacks.onStateChanged(mState); @@ -308,14 +309,14 @@ public class VolumeDialogController { mCallbacks.onShowSilentHint(); } if (changed && fromKey) { - Events.writeEvent(Events.EVENT_KEY); + Events.writeEvent(mContext, Events.EVENT_KEY, stream, lastAudibleStreamVolume); } } private boolean updateActiveStreamW(int activeStream) { if (activeStream == mState.activeStream) return false; mState.activeStream = activeStream; - Events.writeEvent(Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream); + Events.writeEvent(mContext, Events.EVENT_ACTIVE_STREAM_CHANGED, activeStream); if (D.BUG) Log.d(TAG, "updateActiveStreamW " + activeStream); final int s = activeStream < DYNAMIC_STREAM_START_INDEX ? activeStream : -1; if (D.BUG) Log.d(TAG, "forceVolumeControlStream " + s); @@ -364,7 +365,7 @@ public class VolumeDialogController { if (ss.level == level) return false; ss.level = level; if (isLogWorthy(stream)) { - Events.writeEvent(Events.EVENT_LEVEL_CHANGED, stream, level); + Events.writeEvent(mContext, Events.EVENT_LEVEL_CHANGED, stream, level); } return true; } @@ -387,7 +388,7 @@ public class VolumeDialogController { if (ss.muted == muted) return false; ss.muted = muted; if (isLogWorthy(stream)) { - Events.writeEvent(Events.EVENT_MUTE_CHANGED, stream, muted); + Events.writeEvent(mContext, Events.EVENT_MUTE_CHANGED, stream, muted); } if (muted && isRinger(stream)) { updateRingerModeInternalW(mAudio.getRingerModeInternal()); @@ -410,7 +411,7 @@ public class VolumeDialogController { if (Objects.equals(mState.effectsSuppressor, effectsSuppressor)) return false; mState.effectsSuppressor = effectsSuppressor; mState.effectsSuppressorName = getApplicationName(mContext, mState.effectsSuppressor); - Events.writeEvent(Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor, + Events.writeEvent(mContext, Events.EVENT_SUPPRESSOR_CHANGED, mState.effectsSuppressor, mState.effectsSuppressorName); return true; } @@ -434,21 +435,21 @@ public class VolumeDialogController { Settings.Global.ZEN_MODE, Settings.Global.ZEN_MODE_OFF); if (mState.zenMode == zen) return false; mState.zenMode = zen; - Events.writeEvent(Events.EVENT_ZEN_MODE_CHANGED, zen); + Events.writeEvent(mContext, Events.EVENT_ZEN_MODE_CHANGED, zen); return true; } private boolean updateRingerModeExternalW(int rm) { if (rm == mState.ringerModeExternal) return false; mState.ringerModeExternal = rm; - Events.writeEvent(Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm); + Events.writeEvent(mContext, Events.EVENT_EXTERNAL_RINGER_MODE_CHANGED, rm); return true; } private boolean updateRingerModeInternalW(int rm) { if (rm == mState.ringerModeInternal) return false; mState.ringerModeInternal = rm; - Events.writeEvent(Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm); + Events.writeEvent(mContext, Events.EVENT_INTERNAL_RINGER_MODE_CHANGED, rm); return true; } diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java index 17d7078..30680ed 100644 --- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java +++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java @@ -37,6 +37,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; import android.content.pm.ResolveInfo; import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; @@ -1281,7 +1282,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku } @Override - public List<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, + public ParceledListSlice<AppWidgetProviderInfo> getInstalledProvidersForProfile(int categoryFilter, int profileId) { final int userId = UserHandle.getCallingUserId(); @@ -1297,7 +1298,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku synchronized (mLock) { ensureGroupStateLoadedLocked(userId); - ArrayList<AppWidgetProviderInfo> result = null; + ArrayList<AppWidgetProviderInfo> result = new ArrayList<AppWidgetProviderInfo>(); final int providerCount = mProviders.size(); for (int i = 0; i < providerCount; i++) { @@ -1314,14 +1315,11 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku if (providerProfileId == profileId && mSecurityPolicy.isProviderInCallerOrInProfileAndWhitelListed( provider.id.componentName.getPackageName(), providerProfileId)) { - if (result == null) { - result = new ArrayList<>(); - } result.add(cloneIfLocalBinder(info)); } } - return result; + return new ParceledListSlice<AppWidgetProviderInfo>(result); } } diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java index 26ece72..839b87a 100644 --- a/services/core/java/com/android/server/AlarmManagerService.java +++ b/services/core/java/com/android/server/AlarmManagerService.java @@ -20,13 +20,16 @@ import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.AlarmManager; +import android.app.BroadcastOptions; import android.app.IAlarmManager; import android.app.PendingIntent; import android.content.BroadcastReceiver; +import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.PackageManager; +import android.database.ContentObserver; import android.net.Uri; import android.os.Binder; import android.os.Bundle; @@ -43,6 +46,7 @@ import android.provider.Settings; import android.text.TextUtils; import android.text.format.DateFormat; import android.util.ArrayMap; +import android.util.KeyValueListParser; import android.util.Log; import android.util.Slog; import android.util.SparseArray; @@ -75,22 +79,6 @@ import static android.app.AlarmManager.ELAPSED_REALTIME; import com.android.internal.util.LocalLog; class AlarmManagerService extends SystemService { - // The threshold for how long an alarm can be late before we print a - // warning message. The time duration is in milliseconds. - private static final long LATE_ALARM_THRESHOLD = 10 * 1000; - - // Minimum futurity of a new alarm - private static final long MIN_FUTURITY = 5 * 1000; // 5 seconds, in millis - - // Minimum alarm recurrence interval - private static final long MIN_INTERVAL = 60 * 1000; // one minute, in millis - - // Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle. - private static final long ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000; - - // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling. - private static final long ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000; - private static final int RTC_WAKEUP_MASK = 1 << RTC_WAKEUP; private static final int RTC_MASK = 1 << RTC; private static final int ELAPSED_REALTIME_WAKEUP_MASK = 1 << ELAPSED_REALTIME_WAKEUP; @@ -102,7 +90,6 @@ class AlarmManagerService extends SystemService { static final int TYPE_NONWAKEUP_MASK = 0x1; // low bit => non-wakeup static final String TAG = "AlarmManager"; - static final String ClockReceiver_TAG = "ClockReceiver"; static final boolean localLOGV = false; static final boolean DEBUG_BATCH = localLOGV || false; static final boolean DEBUG_VALIDATE = localLOGV || false; @@ -148,7 +135,7 @@ class AlarmManagerService extends SystemService { long mNextNonWakeupDeliveryTime; long mLastTimeChangeClockTime; long mLastTimeChangeRealtime; - long mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_SHORT_TIME; + long mAllowWhileIdleMinTime; int mNumTimeChanged; /** @@ -157,6 +144,11 @@ class AlarmManagerService extends SystemService { */ final SparseLongArray mLastAllowWhileIdleDispatch = new SparseLongArray(); + /** + * Broadcast options to use for FLAG_ALLOW_WHILE_IDLE. + */ + Bundle mIdleOptions; + private final SparseArray<AlarmManager.AlarmClockInfo> mNextAlarmClockForUser = new SparseArray<>(); private final SparseArray<AlarmManager.AlarmClockInfo> mTmpSparseAlarmClockArray = @@ -169,12 +161,137 @@ class AlarmManagerService extends SystemService { private final SparseArray<AlarmManager.AlarmClockInfo> mHandlerSparseAlarmClockArray = new SparseArray<>(); + /** + * All times are in milliseconds. These constants are kept synchronized with the system + * global Settings. Any access to this class or its fields should be done while + * holding the AlarmManagerService.mLock lock. + */ + private final class Constants extends ContentObserver { + // Key names stored in the settings value. + private static final String KEY_MIN_FUTURITY = "min_futurity"; + private static final String KEY_MIN_INTERVAL = "min_interval"; + private static final String KEY_ALLOW_WHILE_IDLE_SHORT_TIME = "allow_while_idle_short_time"; + private static final String KEY_ALLOW_WHILE_IDLE_LONG_TIME = "allow_while_idle_long_time"; + private static final String KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION + = "allow_while_idle_whitelist_duration"; + + private static final long DEFAULT_MIN_FUTURITY = 5 * 1000; + private static final long DEFAULT_MIN_INTERVAL = 60 * 1000; + private static final long DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME = 60*1000; + private static final long DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME = 15*60*1000; + private static final long DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION = 10*1000; + + // Minimum futurity of a new alarm + public long MIN_FUTURITY = DEFAULT_MIN_FUTURITY; + + // Minimum alarm recurrence interval + public long MIN_INTERVAL = DEFAULT_MIN_INTERVAL; + + // Minimum time between ALLOW_WHILE_IDLE alarms when system is not idle. + public long ALLOW_WHILE_IDLE_SHORT_TIME = DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME; + + // Minimum time between ALLOW_WHILE_IDLE alarms when system is idling. + public long ALLOW_WHILE_IDLE_LONG_TIME = DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME; + + // BroadcastOptions.setTemporaryAppWhitelistDuration() to use for FLAG_ALLOW_WHILE_IDLE. + public long ALLOW_WHILE_IDLE_WHITELIST_DURATION + = DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION; + + private ContentResolver mResolver; + private final KeyValueListParser mParser = new KeyValueListParser(','); + private long mLastAllowWhileIdleWhitelistDuration = -1; + + public Constants(Handler handler) { + super(handler); + updateAllowWhileIdleMinTimeLocked(); + updateAllowWhileIdleWhitelistDurationLocked(); + } + + public void start(ContentResolver resolver) { + mResolver = resolver; + mResolver.registerContentObserver(Settings.Global.getUriFor( + Settings.Global.ALARM_MANAGER_CONSTANTS), false, this); + updateConstants(); + } + + public void updateAllowWhileIdleMinTimeLocked() { + mAllowWhileIdleMinTime = mPendingIdleUntil != null + ? ALLOW_WHILE_IDLE_LONG_TIME : ALLOW_WHILE_IDLE_SHORT_TIME; + } + + public void updateAllowWhileIdleWhitelistDurationLocked() { + if (mLastAllowWhileIdleWhitelistDuration != ALLOW_WHILE_IDLE_WHITELIST_DURATION) { + mLastAllowWhileIdleWhitelistDuration = ALLOW_WHILE_IDLE_WHITELIST_DURATION; + BroadcastOptions opts = BroadcastOptions.makeBasic(); + opts.setTemporaryAppWhitelistDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION); + mIdleOptions = opts.toBundle(); + } + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + updateConstants(); + } + + private void updateConstants() { + synchronized (mLock) { + try { + mParser.setString(Settings.Global.getString(mResolver, + Settings.Global.ALARM_MANAGER_CONSTANTS)); + } catch (IllegalArgumentException e) { + // Failed to parse the settings string, log this and move on + // with defaults. + Slog.e(TAG, "Bad device idle settings", e); + } + + MIN_FUTURITY = mParser.getLong(KEY_MIN_FUTURITY, DEFAULT_MIN_FUTURITY); + MIN_INTERVAL = mParser.getLong(KEY_MIN_INTERVAL, DEFAULT_MIN_INTERVAL); + ALLOW_WHILE_IDLE_SHORT_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_SHORT_TIME, + DEFAULT_ALLOW_WHILE_IDLE_SHORT_TIME); + ALLOW_WHILE_IDLE_LONG_TIME = mParser.getLong(KEY_ALLOW_WHILE_IDLE_LONG_TIME, + DEFAULT_ALLOW_WHILE_IDLE_LONG_TIME); + ALLOW_WHILE_IDLE_WHITELIST_DURATION = mParser.getLong( + KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION, + DEFAULT_ALLOW_WHILE_IDLE_WHITELIST_DURATION); + + updateAllowWhileIdleMinTimeLocked(); + updateAllowWhileIdleWhitelistDurationLocked(); + } + } + + void dump(PrintWriter pw) { + pw.println(" Settings:"); + + pw.print(" "); pw.print(KEY_MIN_FUTURITY); pw.print("="); + TimeUtils.formatDuration(MIN_FUTURITY, pw); + pw.println(); + + pw.print(" "); pw.print(KEY_MIN_INTERVAL); pw.print("="); + TimeUtils.formatDuration(MIN_INTERVAL, pw); + pw.println(); + + pw.print(" "); pw.print(KEY_ALLOW_WHILE_IDLE_SHORT_TIME); pw.print("="); + TimeUtils.formatDuration(ALLOW_WHILE_IDLE_SHORT_TIME, pw); + pw.println(); + + pw.print(" "); pw.print(KEY_ALLOW_WHILE_IDLE_LONG_TIME); pw.print("="); + TimeUtils.formatDuration(ALLOW_WHILE_IDLE_LONG_TIME, pw); + pw.println(); + + pw.print(" "); pw.print(KEY_ALLOW_WHILE_IDLE_WHITELIST_DURATION); pw.print("="); + TimeUtils.formatDuration(ALLOW_WHILE_IDLE_WHITELIST_DURATION, pw); + pw.println(); + } + } + + final Constants mConstants; + // Alarm delivery ordering bookkeeping static final int PRIO_TICK = 0; static final int PRIO_WAKEUP = 1; static final int PRIO_NORMAL = 2; - class PriorityClass { + final class PriorityClass { int seq; int priority; @@ -184,11 +301,10 @@ class AlarmManagerService extends SystemService { } } - final HashMap<String, PriorityClass> mPriorities = - new HashMap<String, PriorityClass>(); + final HashMap<String, PriorityClass> mPriorities = new HashMap<>(); int mCurrentSeq = 0; - class WakeupEvent { + static final class WakeupEvent { public long when; public int uid; public String action; @@ -482,6 +598,7 @@ class AlarmManagerService extends SystemService { public AlarmManagerService(Context context) { super(context); + mConstants = new Constants(mHandler); } static long convertToElapsed(long when, int type) { @@ -595,7 +712,7 @@ class AlarmManagerService extends SystemService { } // Make sure we are using the correct ALLOW_WHILE_IDLE min time. - mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_SHORT_TIME; + mConstants.updateAllowWhileIdleMinTimeLocked(); // Reschedule everything. rescheduleKernelAlarmsLocked(); @@ -714,6 +831,13 @@ class AlarmManagerService extends SystemService { } @Override + public void onBootPhase(int phase) { + if (phase == PHASE_SYSTEM_SERVICES_READY) { + mConstants.start(getContext().getContentResolver()); + } + } + + @Override protected void finalize() throws Throwable { try { close(mNativeData); @@ -784,11 +908,12 @@ class AlarmManagerService extends SystemService { // Sanity check the recurrence interval. This will catch people who supply // seconds when the API expects milliseconds. - if (interval > 0 && interval < MIN_INTERVAL) { + final long minInterval = mConstants.MIN_INTERVAL; + if (interval > 0 && interval < minInterval) { Slog.w(TAG, "Suspiciously short interval " + interval - + " millis; expanding to " + (int)(MIN_INTERVAL/1000) + + " millis; expanding to " + (minInterval/1000) + " seconds"); - interval = MIN_INTERVAL; + interval = minInterval; } if (type < RTC_WAKEUP || type > ELAPSED_REALTIME) { @@ -805,7 +930,7 @@ class AlarmManagerService extends SystemService { final long nowElapsed = SystemClock.elapsedRealtime(); final long nominalTrigger = convertToElapsed(triggerAtTime, type); // Try to prevent spamming by making sure we aren't firing alarms in the immediate future - final long minTrigger = nowElapsed + MIN_FUTURITY; + final long minTrigger = nowElapsed + mConstants.MIN_FUTURITY; final long triggerElapsed = (nominalTrigger > minTrigger) ? nominalTrigger : minTrigger; final long maxElapsed; @@ -904,7 +1029,7 @@ class AlarmManagerService extends SystemService { if ((a.flags&AlarmManager.FLAG_IDLE_UNTIL) != 0) { mPendingIdleUntil = a; - mAllowWhileIdleMinTime = ALLOW_WHILE_IDLE_LONG_TIME; + mConstants.updateAllowWhileIdleMinTimeLocked(); needRebatch = true; } else if ((a.flags&AlarmManager.FLAG_WAKE_FROM_IDLE) != 0) { if (mNextWakeFromIdle == null || mNextWakeFromIdle.whenElapsed > a.whenElapsed) { @@ -1054,45 +1179,48 @@ class AlarmManagerService extends SystemService { void dumpImpl(PrintWriter pw) { synchronized (mLock) { pw.println("Current Alarm Manager state:"); + mConstants.dump(pw); + pw.println(); + final long nowRTC = System.currentTimeMillis(); final long nowELAPSED = SystemClock.elapsedRealtime(); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - pw.print("nowRTC="); pw.print(nowRTC); + pw.print(" nowRTC="); pw.print(nowRTC); pw.print("="); pw.print(sdf.format(new Date(nowRTC))); pw.print(" nowELAPSED="); TimeUtils.formatDuration(nowELAPSED, pw); pw.println(); - pw.print("mLastTimeChangeClockTime="); pw.print(mLastTimeChangeClockTime); + pw.print(" mLastTimeChangeClockTime="); pw.print(mLastTimeChangeClockTime); pw.print("="); pw.println(sdf.format(new Date(mLastTimeChangeClockTime))); - pw.print("mLastTimeChangeRealtime="); + pw.print(" mLastTimeChangeRealtime="); TimeUtils.formatDuration(mLastTimeChangeRealtime, pw); pw.println(); if (!mInteractive) { - pw.print("Time since non-interactive: "); + pw.print(" Time since non-interactive: "); TimeUtils.formatDuration(nowELAPSED - mNonInteractiveStartTime, pw); pw.println(); - pw.print("Max wakeup delay: "); + pw.print(" Max wakeup delay: "); TimeUtils.formatDuration(currentNonWakeupFuzzLocked(nowELAPSED), pw); pw.println(); - pw.print("Time since last dispatch: "); + pw.print(" Time since last dispatch: "); TimeUtils.formatDuration(nowELAPSED - mLastAlarmDeliveryTime, pw); pw.println(); - pw.print("Next non-wakeup delivery time: "); + pw.print(" Next non-wakeup delivery time: "); TimeUtils.formatDuration(nowELAPSED - mNextNonWakeupDeliveryTime, pw); pw.println(); } long nextWakeupRTC = mNextWakeup + (nowRTC - nowELAPSED); long nextNonWakeupRTC = mNextNonWakeup + (nowRTC - nowELAPSED); - pw.print("Next non-wakeup alarm: "); + pw.print(" Next non-wakeup alarm: "); TimeUtils.formatDuration(mNextNonWakeup, nowELAPSED, pw); pw.print(" = "); pw.println(sdf.format(new Date(nextNonWakeupRTC))); - pw.print("Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw); + pw.print(" Next wakeup: "); TimeUtils.formatDuration(mNextWakeup, nowELAPSED, pw); pw.print(" = "); pw.println(sdf.format(new Date(nextWakeupRTC))); - pw.print("Num time change events: "); pw.println(mNumTimeChanged); + pw.print(" Num time change events: "); pw.println(mNumTimeChanged); pw.println(); - pw.println("Next alarm clock information: "); + pw.println(" Next alarm clock information: "); final TreeSet<Integer> users = new TreeSet<>(); for (int i = 0; i < mNextAlarmClockForUser.size(); i++) { users.add(mNextAlarmClockForUser.keyAt(i)); @@ -1104,7 +1232,7 @@ class AlarmManagerService extends SystemService { final AlarmManager.AlarmClockInfo next = mNextAlarmClockForUser.get(user); final long time = next != null ? next.getTriggerTime() : 0; final boolean pendingSend = mPendingSendNextAlarmClockChangedForUser.get(user); - pw.print(" user:"); pw.print(user); + pw.print(" user:"); pw.print(user); pw.print(" pendingSend:"); pw.print(pendingSend); pw.print(" time:"); pw.print(time); if (time > 0) { @@ -1115,25 +1243,25 @@ class AlarmManagerService extends SystemService { } if (mAlarmBatches.size() > 0) { pw.println(); - pw.print("Pending alarm batches: "); + pw.print(" Pending alarm batches: "); pw.println(mAlarmBatches.size()); for (Batch b : mAlarmBatches) { pw.print(b); pw.println(':'); - dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf); + dumpAlarmList(pw, b.alarms, " ", nowELAPSED, nowRTC, sdf); } } if (mPendingIdleUntil != null || mPendingWhileIdleAlarms.size() > 0) { pw.println(); - pw.println("Idle mode state:"); - pw.print(" Idling until: "); + pw.println(" Idle mode state:"); + pw.print(" Idling until: "); if (mPendingIdleUntil != null) { pw.println(mPendingIdleUntil); mPendingIdleUntil.dump(pw, " ", nowRTC, nowELAPSED, sdf); } else { pw.println("null"); } - pw.println(" Pending alarms:"); - dumpAlarmList(pw, mPendingWhileIdleAlarms, " ", nowELAPSED, nowRTC, sdf); + pw.println(" Pending alarms:"); + dumpAlarmList(pw, mPendingWhileIdleAlarms, " ", nowELAPSED, nowRTC, sdf); } if (mNextWakeFromIdle != null) { pw.println(); @@ -1142,17 +1270,17 @@ class AlarmManagerService extends SystemService { } pw.println(); - pw.print("Past-due non-wakeup alarms: "); + pw.print(" Past-due non-wakeup alarms: "); if (mPendingNonWakeupAlarms.size() > 0) { pw.println(mPendingNonWakeupAlarms.size()); - dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf); + dumpAlarmList(pw, mPendingNonWakeupAlarms, " ", nowELAPSED, nowRTC, sdf); } else { pw.println("(none)"); } - pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms); + pw.print(" Number of delayed alarms: "); pw.print(mNumDelayedAlarms); pw.print(", total delay time: "); TimeUtils.formatDuration(mTotalDelayTime, pw); pw.println(); - pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw); + pw.print(" Max delay time: "); TimeUtils.formatDuration(mMaxDelayTime, pw); pw.print(", max non-interactive time: "); TimeUtils.formatDuration(mNonInteractiveTime, pw); pw.println(); @@ -1161,11 +1289,11 @@ class AlarmManagerService extends SystemService { pw.print(" Broadcast ref count: "); pw.println(mBroadcastRefCount); pw.println(); - pw.print("mAllowWhileIdleMinTime="); + pw.print(" mAllowWhileIdleMinTime="); TimeUtils.formatDuration(mAllowWhileIdleMinTime, pw); pw.println(); if (mLastAllowWhileIdleDispatch.size() > 0) { - pw.println("Last allow while idle dispatch times:"); + pw.println(" Last allow while idle dispatch times:"); for (int i=0; i<mLastAllowWhileIdleDispatch.size(); i++) { pw.print(" UID "); UserHandle.formatUid(pw, mLastAllowWhileIdleDispatch.keyAt(i)); @@ -1969,6 +2097,7 @@ class AlarmManagerService extends SystemService { mLastAlarmDeliveryTime = nowELAPSED; for (int i=0; i<triggerList.size(); i++) { Alarm alarm = triggerList.get(i); + final boolean allowWhileIdle = (alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0; try { if (localLOGV) { Slog.v(TAG, "sending alarm " + alarm); @@ -1987,7 +2116,7 @@ class AlarmManagerService extends SystemService { alarm.operation.send(getContext(), 0, mBackgroundIntent.putExtra( Intent.EXTRA_ALARM_COUNT, alarm.count), - mResultReceiver, mHandler); + mResultReceiver, mHandler, null, allowWhileIdle ? mIdleOptions : null); // we have an active broadcast so stay awake. if (mBroadcastRefCount == 0) { @@ -2000,7 +2129,7 @@ class AlarmManagerService extends SystemService { mInFlight.add(inflight); mBroadcastRefCount++; - if ((alarm.flags&AlarmManager.FLAG_ALLOW_WHILE_IDLE) != 0) { + if (allowWhileIdle) { // Record the last time this uid handled an ALLOW_WHILE_IDLE alarm. mLastAllowWhileIdleDispatch.put(alarm.uid, nowELAPSED); } diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java index fbb6dc9..f9f6714 100644 --- a/services/core/java/com/android/server/BluetoothManagerService.java +++ b/services/core/java/com/android/server/BluetoothManagerService.java @@ -237,6 +237,12 @@ class BluetoothManagerService extends IBluetoothManager.Stub { sendEnableMsg(mQuietEnableExternal); } } + + if (!isNameAndAddressSet()) { + // Sync the Bluetooth name and address from the Bluetooth Adapter + if (DBG) Log.d(TAG,"Retrieving Bluetooth Adapter name and address..."); + getNameAndAddress(); + } } } }; diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 82399da..98f0b45 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -136,11 +136,13 @@ import java.io.FileReader; import java.io.IOException; import java.io.PrintWriter; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -3920,10 +3922,52 @@ public class ConnectivityService extends IConnectivityManager.Stub } return !routeDiff.added.isEmpty() || !routeDiff.removed.isEmpty(); } + + // TODO: investigate moving this into LinkProperties, if only to make more accurate + // the isProvisioned() checks. + private static Collection<InetAddress> getLikelyReachableDnsServers(LinkProperties lp) { + final ArrayList<InetAddress> dnsServers = new ArrayList<InetAddress>(); + final List<RouteInfo> allRoutes = lp.getAllRoutes(); + for (InetAddress nameserver : lp.getDnsServers()) { + // If the LinkProperties doesn't include a route to the nameserver, ignore it. + final RouteInfo bestRoute = RouteInfo.selectBestRoute(allRoutes, nameserver); + if (bestRoute == null) { + continue; + } + + // TODO: better source address evaluation for destination addresses. + if (nameserver instanceof Inet4Address) { + if (!lp.hasIPv4Address()) { + continue; + } + } else if (nameserver instanceof Inet6Address) { + if (nameserver.isLinkLocalAddress()) { + if (((Inet6Address)nameserver).getScopeId() == 0) { + // For now, just make sure link-local DNS servers have + // scopedIds set, since DNS lookups will fail otherwise. + // TODO: verify the scopeId matches that of lp's interface. + continue; + } + } else { + if (bestRoute.isIPv6Default() && !lp.hasGlobalIPv6Address()) { + // TODO: reconsider all corner cases (disconnected ULA networks, ...). + continue; + } + } + } + + dnsServers.add(nameserver); + } + return Collections.unmodifiableList(dnsServers); + } + private void updateDnses(LinkProperties newLp, LinkProperties oldLp, int netId, boolean flush, boolean useDefaultDns) { + // TODO: consider comparing the getLikelyReachableDnsServers() lists, in case the + // route to a DNS server has been removed (only really applicable in special cases + // where there is no default route). if (oldLp == null || (newLp.isIdenticalDnses(oldLp) == false)) { - Collection<InetAddress> dnses = newLp.getDnsServers(); + Collection<InetAddress> dnses = getLikelyReachableDnsServers(newLp); if (dnses.size() == 0 && mDefaultDns != null && useDefaultDns) { dnses = new ArrayList(); dnses.add(mDefaultDns); diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java index 6eba3f6..8dd087a 100644 --- a/services/core/java/com/android/server/DeviceIdleController.java +++ b/services/core/java/com/android/server/DeviceIdleController.java @@ -19,7 +19,6 @@ package com.android.server; import android.Manifest; import android.app.ActivityManagerNative; import android.app.AlarmManager; -import android.app.AppGlobals; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ContentResolver; @@ -27,7 +26,6 @@ import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.database.ContentObserver; @@ -101,10 +99,6 @@ public class DeviceIdleController extends SystemService private static final String ACTION_ENTER_INACTIVE_STATE = "com.android.server.device_idle.ENTER_INACTIVE_STATE"; - // TODO: These need to be moved to system settings. - - - private AlarmManager mAlarmManager; private IBatteryStats mBatteryStats; private PowerManagerInternal mLocalPowerManager; @@ -180,7 +174,7 @@ public class DeviceIdleController extends SystemService * List of end times for UIDs that are temporarily marked as being allowed to access * the network and acquire wakelocks. Times are in milliseconds. */ - private SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray(); + private final SparseLongArray mTempWhitelistAppIdEndTimes = new SparseLongArray(); /** * Current app IDs of temporarily whitelist apps for high-priority messages. @@ -234,7 +228,7 @@ public class DeviceIdleController extends SystemService * global Settings. Any access to this class or its fields should be done while * holding the DeviceIdleController lock. */ - private class Constants extends ContentObserver { + private final class Constants extends ContentObserver { // Key names stored in the settings value. private static final String KEY_INACTIVE_TIMEOUT = "inactive_to"; private static final String KEY_SENSING_TIMEOUT = "sensing_to"; @@ -403,49 +397,49 @@ public class DeviceIdleController extends SystemService void dump(PrintWriter pw) { pw.println(" Settings:"); - pw.print(" DOZE_INACTIVE_TIMEOUT="); + pw.print(" "); pw.print(KEY_INACTIVE_TIMEOUT); pw.print("="); TimeUtils.formatDuration(INACTIVE_TIMEOUT, pw); pw.println(); - pw.print(" DOZE_SENSING_TIMEOUT="); + pw.print(" "); pw.print(KEY_SENSING_TIMEOUT); pw.print("="); TimeUtils.formatDuration(SENSING_TIMEOUT, pw); pw.println(); - pw.print(" DOZE_MOTION_INACTIVE_TIMEOUT="); + pw.print(" "); pw.print(KEY_MOTION_INACTIVE_TIMEOUT); pw.print("="); TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw); pw.println(); - pw.print(" DOZE_IDLE_AFTER_INACTIVE_TIMEOUT="); + pw.print(" "); pw.print(KEY_IDLE_AFTER_INACTIVE_TIMEOUT); pw.print("="); TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw); pw.println(); - pw.print(" DOZE_IDLE_PENDING_TIMEOUT="); + pw.print(" "); pw.print(KEY_IDLE_PENDING_TIMEOUT); pw.print("="); TimeUtils.formatDuration(IDLE_PENDING_TIMEOUT, pw); pw.println(); - pw.print(" DOZE_MAX_IDLE_PENDING_TIMEOUT="); + pw.print(" "); pw.print(KEY_MAX_IDLE_PENDING_TIMEOUT); pw.print("="); TimeUtils.formatDuration(MAX_IDLE_PENDING_TIMEOUT, pw); pw.println(); - pw.print(" DOZE_IDLE_PENDING_FACTOR="); + pw.print(" "); pw.print(KEY_IDLE_PENDING_FACTOR); pw.print("="); pw.println(IDLE_PENDING_FACTOR); - pw.print(" DOZE_IDLE_TIMEOUT="); + pw.print(" "); pw.print(KEY_IDLE_TIMEOUT); pw.print("="); TimeUtils.formatDuration(IDLE_TIMEOUT, pw); pw.println(); - pw.print(" DOZE_MAX_IDLE_TIMEOUT="); + pw.print(" "); pw.print(KEY_MAX_IDLE_TIMEOUT); pw.print("="); TimeUtils.formatDuration(MAX_IDLE_TIMEOUT, pw); pw.println(); - pw.print(" DOZE_IDLE_FACTOR="); + pw.print(" "); pw.print(KEY_IDLE_FACTOR); pw.print("="); pw.println(IDLE_FACTOR); - pw.print(" DOZE_MIN_TIME_TO_ALARM="); + pw.print(" "); pw.print(KEY_MIN_TIME_TO_ALARM); pw.print("="); TimeUtils.formatDuration(MIN_TIME_TO_ALARM, pw); pw.println(); - pw.print(" DOZE_MAX_TEMP_APP_WHITELIST_DURATION="); + pw.print(" "); pw.print(KEY_MAX_TEMP_APP_WHITELIST_DURATION); pw.print("="); TimeUtils.formatDuration(MAX_TEMP_APP_WHITELIST_DURATION, pw); pw.println(); } @@ -465,6 +459,7 @@ public class DeviceIdleController extends SystemService } else if (result == AnyMotionDetector.RESULT_MOVED) { if (DEBUG) Slog.d(TAG, "RESULT_MOVED received."); synchronized (this) { + EventLogTags.writeDeviceIdle(mState, "sense_moved"); enterInactiveStateLocked(); } } @@ -573,15 +568,11 @@ public class DeviceIdleController extends SystemService userId, /*allowAll=*/ false, /*requireFull=*/ false, - "addAppBrieflyToWhitelist", null); + "addPowerSaveTempWhitelistApp", null); final long token = Binder.clearCallingIdentity(); try { - PackageInfo pi = AppGlobals.getPackageManager() - .getPackageInfo(packageName, 0, userId); - if (pi == null) return; DeviceIdleController.this.addPowerSaveTempWhitelistAppInternal(packageName, duration, userId); - } catch (RemoteException re) { } finally { Binder.restoreCallingIdentity(token); } @@ -592,6 +583,12 @@ public class DeviceIdleController extends SystemService } } + public final class LocalService { + public void addPowerSaveTempWhitelistAppDirect(int appId, long duration) { + DeviceIdleController.this.addPowerSaveTempWhitelistAppDirectInternal(appId, duration); + } + } + public DeviceIdleController(Context context) { super(context); mConfigFile = new AtomicFile(new File(getSystemDir(), "deviceidle.xml")); @@ -635,6 +632,7 @@ public class DeviceIdleController extends SystemService } publishBinderService(Context.DEVICE_IDLE_CONTROLLER, new BinderService()); + publishLocalService(LocalService.class, new LocalService()); } @Override @@ -765,33 +763,41 @@ public class DeviceIdleController extends SystemService try { int uid = getContext().getPackageManager().getPackageUid(packageName, userId); int appId = UserHandle.getAppId(uid); - final long timeNow = System.currentTimeMillis(); - synchronized (this) { - duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION); - long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId); - // Set the new end time - mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration); - if (DEBUG) { - Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist"); - } - if (currentEndTime == 0) { - // No pending timeout for the app id, post a delayed message - postTempActiveTimeoutMessage(appId, duration); - updateTempWhitelistAppIdsLocked(); - reportTempWhitelistChangedLocked(); - } - } + addPowerSaveTempWhitelistAppDirectInternal(appId, duration); } catch (NameNotFoundException e) { } } + /** + * Adds an app to the temporary whitelist and resets the endTime for granting the + * app an exemption to access network and acquire wakelocks. + */ + public void addPowerSaveTempWhitelistAppDirectInternal(int appId, long duration) { + final long timeNow = SystemClock.elapsedRealtime(); + synchronized (this) { + duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION); + long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId); + // Set the new end time + mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration); + if (DEBUG) { + Slog.d(TAG, "Adding AppId " + appId + " to temp whitelist"); + } + if (currentEndTime == 0) { + // No pending timeout for the app id, post a delayed message + postTempActiveTimeoutMessage(appId, duration); + updateTempWhitelistAppIdsLocked(); + reportTempWhitelistChangedLocked(); + } + } + } + private void postTempActiveTimeoutMessage(int uid, long delay) { mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TEMP_APP_WHITELIST_TIMEOUT, uid, 0), delay); } void checkTempAppWhitelistTimeout(int uid) { - final long timeNow = System.currentTimeMillis(); + final long timeNow = SystemClock.elapsedRealtime(); synchronized (this) { long endTime = mTempWhitelistAppIdEndTimes.get(uid); if (endTime == 0) { @@ -1295,6 +1301,8 @@ public class DeviceIdleController extends SystemService } synchronized (this) { + mConstants.dump(pw); + int size = mPowerSaveWhitelistApps.size(); if (size > 0) { pw.println(" Whitelist system apps:"); @@ -1313,17 +1321,34 @@ public class DeviceIdleController extends SystemService } size = mPowerSaveWhitelistAppIds.size(); if (size > 0) { - pw.println(" Whitelist app uids:"); + pw.println(" Whitelist app ids:"); for (int i = 0; i < size; i++) { - pw.print(" UID="); + pw.print(" "); pw.print(mPowerSaveWhitelistAppIds.keyAt(i)); + pw.println(); + } + } + size = mTempWhitelistAppIdEndTimes.size(); + if (size > 0) { + pw.println(" Temp whitelist schedule:"); + final long timeNow = SystemClock.elapsedRealtime(); + for (int i = 0; i < size; i++) { + pw.print(" UID="); + pw.print(mTempWhitelistAppIdEndTimes.keyAt(i)); pw.print(": "); - pw.print(mPowerSaveWhitelistAppIds.valueAt(i)); + TimeUtils.formatDuration(mTempWhitelistAppIdEndTimes.valueAt(i), timeNow, pw); + pw.println(); + } + } + size = mTempWhitelistAppIdArray != null ? mTempWhitelistAppIdArray.length : 0; + if (size > 0) { + pw.println(" Temp whitelist app ids:"); + for (int i = 0; i < size; i++) { + pw.print(" "); + pw.print(mTempWhitelistAppIdArray[i]); pw.println(); } } - - mConstants.dump(pw); pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor); pw.print(" mCurDisplay="); pw.println(mCurDisplay); diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index a5d536e..2f153a0 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -2112,8 +2112,23 @@ public class InputMethodManagerService extends IInputMethodManager.Stub if (DEBUG) Slog.v(TAG, "Not hiding: forced show not cancelled by not-always hide"); return false; } + + // There is a chance that IMM#hideSoftInput() is called in a transient state where + // IMMS#InputShown is already updated to be true whereas IMMS#mImeWindowVis is still waiting + // to be updated with the new value sent from IME process. Even in such a transient state + // historically we have accepted an incoming call of IMM#hideSoftInput() from the + // application process as a valid request, and have even promised such a behavior with CTS + // since Android Eclair. That's why we need to accept IMM#hideSoftInput() even when only + // IMMS#InputShown indicates that the software keyboard is shown. + // TODO: Clean up, IMMS#mInputShown, IMMS#mImeWindowVis and mShowRequested. + final boolean shouldHideSoftInput = (mCurMethod != null) && (mInputShown || + (mImeWindowVis & InputMethodService.IME_ACTIVE) != 0); boolean res; - if ((mImeWindowVis & InputMethodService.IME_ACTIVE) != 0 && mCurMethod != null) { + if (shouldHideSoftInput) { + // The IME will report its visible state again after the following message finally + // delivered to the IME process as an IPC. Hence the inconsistency between + // IMMS#mInputShown and IMMS#mImeWindowVis should be resolved spontaneously in + // the final state. executeOrSendMessage(mCurMethod, mCaller.obtainMessageOO( MSG_HIDE_SOFT_INPUT, mCurMethod, resultReceiver)); res = true; diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java index c76fc1c..743aafb 100644 --- a/services/core/java/com/android/server/LocationManagerService.java +++ b/services/core/java/com/android/server/LocationManagerService.java @@ -1958,6 +1958,27 @@ public class LocationManagerService extends ILocationManager.Stub { return p.getProperties(); } + /** + * @return null if the provider does not exist + * @throws SecurityException if the provider is not allowed to be + * accessed by the caller + */ + @Override + public String getNetworkProviderPackage() { + LocationProviderInterface p; + synchronized (mLock) { + if (mProvidersByName.get(LocationManager.NETWORK_PROVIDER) == null) { + return null; + } + p = mProvidersByName.get(LocationManager.NETWORK_PROVIDER); + } + + if (p instanceof LocationProviderProxy) { + return ((LocationProviderProxy) p).getConnectedPackageName(); + } + return null; + } + @Override public boolean isProviderEnabled(String provider) { // Fused provider is accessed indirectly via criteria rather than the provider-based APIs, diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index a1e2a54..baa55e7 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -19,6 +19,15 @@ package com.android.server; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; import static android.Manifest.permission.DUMP; import static android.Manifest.permission.SHUTDOWN; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY; +import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; +import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST; +import static android.net.NetworkPolicyManager.FIREWALL_TYPE_WHITELIST; import static android.net.NetworkStats.SET_DEFAULT; import static android.net.NetworkStats.TAG_ALL; import static android.net.NetworkStats.TAG_NONE; @@ -35,6 +44,7 @@ import static com.android.server.NetworkManagementService.NetdResponseCode.Tethe import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult; import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED; +import android.annotation.NonNull; import android.app.ActivityManagerNative; import android.content.Context; import android.net.ConnectivityManager; @@ -192,6 +202,21 @@ public class NetworkManagementService extends INetworkManagementService.Stub /** Set of UIDs that are to be blocked/allowed by firewall controller. */ @GuardedBy("mQuotaLock") private SparseIntArray mUidFirewallRules = new SparseIntArray(); + /** + * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches + * to application idles. + */ + @GuardedBy("mQuotaLock") + private SparseIntArray mUidFirewallStandbyRules = new SparseIntArray(); + /** + * Set of UIDs that are to be blocked/allowed by firewall controller. This set of Ids matches + * to device idles. + */ + @GuardedBy("mQuotaLock") + private SparseIntArray mUidFirewallDozableRules = new SparseIntArray(); + + private boolean mStandbyChainEnabled = false; + private boolean mDozableChainEnabled = false; private Object mIdleTimerLock = new Object(); /** Set of interfaces with active idle timers. */ @@ -282,6 +307,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub } public void systemReady() { + // init firewall states + mDozableChainEnabled = false; + mStandbyChainEnabled = true; prepareNativeDaemon(); if (DBG) Slog.d(TAG, "Prepared"); } @@ -568,9 +596,38 @@ public class NetworkManagementService extends INetworkManagementService.Stub final SparseIntArray uidFirewallRules = mUidFirewallRules; mUidFirewallRules = new SparseIntArray(); for (int i = 0; i < uidFirewallRules.size(); i++) { - setFirewallUidRule(uidFirewallRules.keyAt(i), uidFirewallRules.valueAt(i)); + setFirewallUidRuleInternal(FIREWALL_CHAIN_NONE, uidFirewallRules.keyAt(i), + uidFirewallRules.valueAt(i)); + } + } + + size = mUidFirewallStandbyRules.size(); + if (size > 0) { + Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules"); + final SparseIntArray uidFirewallRules = mUidFirewallStandbyRules; + mUidFirewallStandbyRules = new SparseIntArray(); + for (int i = 0; i < uidFirewallRules.size(); i++) { + setFirewallUidRuleInternal(FIREWALL_CHAIN_STANDBY, uidFirewallRules.keyAt(i), + uidFirewallRules.valueAt(i)); + } + } + if (mStandbyChainEnabled) { + setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true); + } + + size = mUidFirewallDozableRules.size(); + if (size > 0) { + Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules"); + final SparseIntArray uidFirewallRules = mUidFirewallDozableRules; + mUidFirewallDozableRules = new SparseIntArray(); + for (int i = 0; i < uidFirewallRules.size(); i++) { + setFirewallUidRuleInternal(FIREWALL_CHAIN_DOZABLE, uidFirewallRules.keyAt(i), + uidFirewallRules.valueAt(i)); } } + if (mDozableChainEnabled) { + setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true); + } } } @@ -1954,13 +2011,78 @@ public class NetworkManagementService extends INetworkManagementService.Stub } @Override - public void setFirewallUidRule(int uid, int rule) { + public void setFirewallChainEnabled(int chain, boolean enable) { enforceSystemUid(); - if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) { - Preconditions.checkState(mFirewallEnabled); + final String operation = enable ? "enable_chain" : "disable_chain"; + try { + String chainName; + switch(chain) { + case FIREWALL_CHAIN_STANDBY: + chainName = FIREWALL_CHAIN_NAME_STANDBY; + mStandbyChainEnabled = enable; + break; + case FIREWALL_CHAIN_DOZABLE: + chainName = FIREWALL_CHAIN_NAME_DOZABLE; + mDozableChainEnabled = enable; + break; + default: + throw new IllegalArgumentException("Bad child chain: " + chain); + } + mConnector.execute("firewall", operation, chainName); + } catch (NativeDaemonConnectorException e) { + throw e.rethrowAsParcelableException(); } + } + + private int getFirewallType(int chain) { + switch (chain) { + case FIREWALL_CHAIN_STANDBY: + return FIREWALL_TYPE_BLACKLIST; + case FIREWALL_CHAIN_DOZABLE: + return FIREWALL_TYPE_WHITELIST; + default: + return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST; + } + } + + @Override + public void setFirewallUidRules(int chain, int[] uids, int[] rules) { + enforceSystemUid(); + SparseIntArray uidFirewallRules = getUidFirewallRules(chain); + SparseIntArray newRules = new SparseIntArray(); + // apply new set of rules + for (int index = uids.length - 1; index >= 0; --index) { + int uid = uids[index]; + int rule = rules[index]; + setFirewallUidRule(chain, uid, rule); + newRules.put(uid, rule); + } + // collect the rules to remove. + SparseIntArray rulesToRemove = new SparseIntArray(); + for (int index = uidFirewallRules.size() - 1; index >= 0; --index) { + int uid = uidFirewallRules.keyAt(index); + if (newRules.indexOfKey(uid) < 0) { + rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT); + } + } + // remove dead rules + for (int index = rulesToRemove.size() - 1; index >= 0; --index) { + int uid = rulesToRemove.keyAt(index); + setFirewallUidRuleInternal(chain, uid, FIREWALL_RULE_DEFAULT); + } + } + + @Override + public void setFirewallUidRule(int chain, int uid, int rule) { + enforceSystemUid(); + setFirewallUidRuleInternal(chain, uid, rule); + } + + private void setFirewallUidRuleInternal(int chain, int uid, int rule) { synchronized (mQuotaLock) { - final int oldUidFirewallRule = mUidFirewallRules.get(uid); + SparseIntArray uidFirewallRules = getUidFirewallRules(chain); + + final int oldUidFirewallRule = uidFirewallRules.get(uid, FIREWALL_RULE_DEFAULT); if (DBG) { Slog.d(TAG, "oldRule = " + oldUidFirewallRule + ", newRule=" + rule + " for uid=" + uid); @@ -1973,7 +2095,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub try { String ruleName; - if (isFirewallEnabled()) { // Whitelist mode + if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) { if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) { ruleName = "allow"; } else { @@ -1988,17 +2110,44 @@ public class NetworkManagementService extends INetworkManagementService.Stub } if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) { - mUidFirewallRules.delete(uid); + uidFirewallRules.delete(uid); } else { - mUidFirewallRules.put(uid, rule); + uidFirewallRules.put(uid, rule); } - mConnector.execute("firewall", "set_uid_rule", uid, ruleName); + mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid, + ruleName); } catch (NativeDaemonConnectorException e) { throw e.rethrowAsParcelableException(); } } } + private @NonNull SparseIntArray getUidFirewallRules(int chain) { + switch (chain) { + case FIREWALL_CHAIN_STANDBY: + return mUidFirewallStandbyRules; + case FIREWALL_CHAIN_DOZABLE: + return mUidFirewallDozableRules; + case FIREWALL_CHAIN_NONE: + return mUidFirewallRules; + default: + throw new IllegalArgumentException("Unknown chain:" + chain); + } + } + + public @NonNull String getFirewallChainName(int chain) { + switch (chain) { + case FIREWALL_CHAIN_STANDBY: + return FIREWALL_CHAIN_NAME_STANDBY; + case FIREWALL_CHAIN_DOZABLE: + return FIREWALL_CHAIN_NAME_DOZABLE; + case FIREWALL_CHAIN_NONE: + return FIREWALL_CHAIN_NAME_NONE; + default: + throw new IllegalArgumentException("Unknown chain:" + chain); + } + } + private static void enforceSystemUid() { final int uid = Binder.getCallingUid(); if (uid != Process.SYSTEM_UID) { @@ -2123,6 +2272,32 @@ public class NetworkManagementService extends INetworkManagementService.Stub pw.println("]"); } + pw.println("UID firewall standby chain enabled: " + mStandbyChainEnabled); + synchronized (mUidFirewallStandbyRules) { + pw.print("UID firewall standby rule: ["); + final int size = mUidFirewallStandbyRules.size(); + for (int i = 0; i < size; i++) { + pw.print(mUidFirewallStandbyRules.keyAt(i)); + pw.print(":"); + pw.print(mUidFirewallStandbyRules.valueAt(i)); + if (i < size - 1) pw.print(","); + } + pw.println("]"); + } + + pw.println("UID firewall dozable chain enabled: " + mDozableChainEnabled); + synchronized (mUidFirewallDozableRules) { + pw.print("UID firewall dozable rule: ["); + final int size = mUidFirewallDozableRules.size(); + for (int i = 0; i < size; i++) { + pw.print(mUidFirewallDozableRules.keyAt(i)); + pw.print(":"); + pw.print(mUidFirewallDozableRules.valueAt(i)); + if (i < size - 1) pw.print(","); + } + pw.println("]"); + } + synchronized (mIdleTimerLock) { pw.println("Idle timers:"); for (HashMap.Entry<String, IdleTimerParams> ent : mActiveIdleTimers.entrySet()) { diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java index 56f9942..94316fe 100644 --- a/services/core/java/com/android/server/PersistentDataBlockService.java +++ b/services/core/java/com/android/server/PersistentDataBlockService.java @@ -18,18 +18,14 @@ package com.android.server; import android.Manifest; import android.app.ActivityManager; -import android.app.PendingIntent; import android.content.Context; -import android.content.Intent; import android.content.pm.PackageManager; import android.os.Binder; -import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; import android.service.persistentdata.IPersistentDataBlockService; -import android.service.persistentdata.PersistentDataBlockManager; import android.util.Slog; import com.android.internal.R; @@ -432,29 +428,6 @@ public class PersistentDataBlockService extends SystemService { } @Override - public void wipeIfAllowed(Bundle bundle, PendingIntent pi) { - // Should only be called by owner - if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { - throw new SecurityException("Only the Owner is allowed to wipe"); - } - // Caller must be able to query the the state of the PersistentDataBlock - enforcePersistentDataBlockAccess(); - String allowedPackage = mContext.getResources() - .getString(R.string.config_persistentDataPackageName); - Intent intent = new Intent(); - intent.setPackage(allowedPackage); - intent.setAction(PersistentDataBlockManager.ACTION_WIPE_IF_ALLOWED); - intent.putExtras(bundle); - intent.putExtra(PersistentDataBlockManager.EXTRA_WIPE_IF_ALLOWED_CALLBACK, pi); - long id = Binder.clearCallingIdentity(); - try { - mContext.sendBroadcastAsUser(intent, UserHandle.OWNER); - } finally { - restoreCallingIdentity(id); - } - } - - @Override public void setOemUnlockEnabled(boolean enabled) { // do not allow monkey to flip the flag if (ActivityManager.isUserAMonkey()) { diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index 6e67970..e0a9ab4 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -34,7 +34,7 @@ import android.os.ServiceManager; * local interfaces that other services within the system server may use to access * privileged internal functions. * <li>Then {@link #onBootPhase(int)} is called as many times as there are boot phases - * until {@link #PHASE_BOOT_COMPLETE} is sent, which is the last boot phase. Each phase + * until {@link #PHASE_BOOT_COMPLETED} is sent, which is the last boot phase. Each phase * is an opportunity to do special work, like acquiring optional service dependencies, * waiting to see if SafeMode is enabled, or registering with a service that gets * started after this one. diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 667abb6..c4f460e 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -39,6 +39,7 @@ import static org.xmlpull.v1.XmlPullParser.START_TAG; import android.Manifest; import android.app.AppOpsManager; import android.app.ApplicationThreadNative; +import android.app.BroadcastOptions; import android.app.IActivityContainer; import android.app.IActivityContainerCallback; import android.app.IAppTask; @@ -89,6 +90,7 @@ import com.android.internal.util.MemInfoReader; import com.android.internal.util.Preconditions; import com.android.server.AppOpsService; import com.android.server.AttributeCache; +import com.android.server.DeviceIdleController; import com.android.server.IntentResolver; import com.android.server.LocalServices; import com.android.server.ServiceThread; @@ -941,6 +943,11 @@ public final class ActivityManagerService extends ActivityManagerNative UsageStatsManagerInternal mUsageStatsService; /** + * Access to DeviceIdleController service. + */ + DeviceIdleController.LocalService mLocalDeviceIdleController; + + /** * Information about and control over application operations */ final AppOpsService mAppOpsService; @@ -1438,7 +1445,7 @@ public final class ActivityManagerService extends ActivityManagerNative } broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */); + null, false, false, MY_PID, Process.SYSTEM_UID, 0 /* TODO: Verify */); if (mShowDialogs) { Dialog d = new AppNotRespondingDialog(ActivityManagerService.this, @@ -2559,9 +2566,9 @@ public final class ActivityManagerService extends ActivityManagerNative @Override public void batterySendBroadcast(Intent intent) { - broadcastIntentLocked(null, null, intent, null, - null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1, - Process.SYSTEM_UID, UserHandle.USER_ALL); + broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, + AppOpsManager.OP_NONE, null, false, false, + -1, Process.SYSTEM_UID, UserHandle.USER_ALL); } /** @@ -5089,7 +5096,7 @@ public final class ActivityManagerService extends ActivityManagerNative Uri.fromParts("package", packageName, null)); intent.putExtra(Intent.EXTRA_UID, pkgUid); broadcastIntentInPackage("android", Process.SYSTEM_UID, intent, - null, null, 0, null, null, null, false, false, userId); + null, null, 0, null, null, null, null, false, false, userId); } catch (RemoteException e) { } } finally { @@ -5322,9 +5329,9 @@ public final class ActivityManagerService extends ActivityManagerNative mStackSupervisor.closeSystemDialogsLocked(); - broadcastIntentLocked(null, null, intent, null, - null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1, - Process.SYSTEM_UID, UserHandle.USER_ALL); + broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, + AppOpsManager.OP_NONE, null, false, false, + -1, Process.SYSTEM_UID, UserHandle.USER_ALL); } @Override @@ -5423,8 +5430,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent.putExtra(Intent.EXTRA_USER_HANDLE, UserHandle.getUserId(uid)); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - false, false, - MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid)); + null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.getUserId(uid)); } private void forceStopUserLocked(int userId, String reason) { @@ -5435,8 +5441,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - false, false, - MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } private final boolean killPackageProcessesLocked(String packageName, int appId, @@ -6329,8 +6334,8 @@ public final class ActivityManagerService extends ActivityManagerNative }, 0, null, null, android.Manifest.permission.RECEIVE_BOOT_COMPLETED, - AppOpsManager.OP_NONE, true, false, MY_PID, Process.SYSTEM_UID, - userId); + AppOpsManager.OP_NONE, null, true, false, + MY_PID, Process.SYSTEM_UID, userId); } } scheduleStartProfilesLocked(); @@ -11442,8 +11447,7 @@ public final class ActivityManagerService extends ActivityManagerNative EventLogTags.writeAmPreBoot(users[curUser], intent.getComponent().getPackageName()); broadcastIntentLocked(null, null, intent, null, this, 0, null, null, null, AppOpsManager.OP_NONE, - true, false, MY_PID, Process.SYSTEM_UID, - users[curUser]); + null, true, false, MY_PID, Process.SYSTEM_UID, users[curUser]); } public void performReceive(Intent intent, int resultCode, @@ -11535,6 +11539,9 @@ public final class ActivityManagerService extends ActivityManagerNative return; } + mLocalDeviceIdleController + = LocalServices.getService(DeviceIdleController.LocalService.class); + // Make sure we have the current profile info, since it is needed for // security checks. updateCurrentProfileIdsLocked(); @@ -11704,7 +11711,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId); + null, false, false, MY_PID, Process.SYSTEM_UID, mCurrentUserId); intent = new Intent(Intent.ACTION_USER_STARTING); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); intent.putExtra(Intent.EXTRA_USER_HANDLE, mCurrentUserId); @@ -11717,7 +11724,7 @@ public final class ActivityManagerService extends ActivityManagerNative } }, 0, null, null, INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE, - true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } catch (Throwable t) { Slog.wtf(TAG, "Failed sending first user broadcasts", t); } finally { @@ -16101,8 +16108,8 @@ public final class ActivityManagerService extends ActivityManagerNative Intent intent = allSticky.get(i); BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, null, - null, -1, -1, null, null, AppOpsManager.OP_NONE, receivers, null, 0, - null, null, false, true, true, -1); + null, -1, -1, null, null, AppOpsManager.OP_NONE, null, receivers, + null, 0, null, null, false, true, true, -1); queue.enqueueParallelBroadcastLocked(r); queue.scheduleBroadcastsLocked(); } @@ -16255,9 +16262,8 @@ public final class ActivityManagerService extends ActivityManagerNative private final int broadcastIntentLocked(ProcessRecord callerApp, String callerPackage, Intent intent, String resolvedType, IIntentReceiver resultTo, int resultCode, String resultData, - Bundle map, String requiredPermission, int appOp, - boolean ordered, boolean sticky, int callingPid, int callingUid, - int userId) { + Bundle resultExtras, String requiredPermission, int appOp, Bundle options, + boolean ordered, boolean sticky, int callingPid, int callingUid, int userId) { intent = new Intent(intent); // By default broadcasts do not go to stopped apps. @@ -16292,6 +16298,28 @@ public final class ActivityManagerService extends ActivityManagerNative } } + BroadcastOptions brOptions = null; + if (options != null) { + brOptions = new BroadcastOptions(options); + if (brOptions.getTemporaryAppWhitelistDuration() > 0) { + // See if the caller is allowed to do this. Note we are checking against + // the actual real caller (not whoever provided the operation as say a + // PendingIntent), because that who is actually supplied the arguments. + if (checkComponentPermission( + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST, + Binder.getCallingPid(), Binder.getCallingUid(), -1, true) + != PackageManager.PERMISSION_GRANTED) { + String msg = "Permission Denial: " + intent.getAction() + + " broadcast from " + callerPackage + " (pid=" + callingPid + + ", uid=" + callingUid + ")" + + " requires " + + android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST; + Slog.w(TAG, msg); + throw new SecurityException(msg); + } + } + } + /* * Prevent non-system code (defined here to be non-persistent * processes) from sending protected broadcasts. @@ -16598,8 +16626,8 @@ public final class ActivityManagerService extends ActivityManagerNative final BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, requiredPermission, - appOp, registeredReceivers, resultTo, resultCode, resultData, map, - ordered, sticky, false, userId); + appOp, brOptions, registeredReceivers, resultTo, resultCode, resultData, + resultExtras, ordered, sticky, false, userId); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing parallel broadcast " + r); final boolean replaced = replacePending && queue.replaceParallelBroadcastLocked(r); if (!replaced) { @@ -16687,8 +16715,8 @@ public final class ActivityManagerService extends ActivityManagerNative BroadcastQueue queue = broadcastQueueForIntent(intent); BroadcastRecord r = new BroadcastRecord(queue, intent, callerApp, callerPackage, callingPid, callingUid, resolvedType, - requiredPermission, appOp, receivers, resultTo, resultCode, - resultData, map, ordered, sticky, false, userId); + requiredPermission, appOp, brOptions, receivers, resultTo, resultCode, + resultData, resultExtras, ordered, sticky, false, userId); if (DEBUG_BROADCAST) Slog.v(TAG_BROADCAST, "Enqueueing ordered broadcast " + r + ": prev had " + queue.mOrderedBroadcasts.size()); @@ -16735,8 +16763,9 @@ public final class ActivityManagerService extends ActivityManagerNative public final int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType, IIntentReceiver resultTo, - int resultCode, String resultData, Bundle map, - String requiredPermission, int appOp, boolean serialized, boolean sticky, int userId) { + int resultCode, String resultData, Bundle resultExtras, + String requiredPermission, int appOp, Bundle options, + boolean serialized, boolean sticky, int userId) { enforceNotIsolatedCaller("broadcastIntent"); synchronized(this) { intent = verifyBroadcastLocked(intent); @@ -16747,8 +16776,8 @@ public final class ActivityManagerService extends ActivityManagerNative final long origId = Binder.clearCallingIdentity(); int res = broadcastIntentLocked(callerApp, callerApp != null ? callerApp.info.packageName : null, - intent, resolvedType, resultTo, - resultCode, resultData, map, requiredPermission, appOp, serialized, sticky, + intent, resolvedType, resultTo, resultCode, resultData, resultExtras, + requiredPermission, appOp, null, serialized, sticky, callingPid, callingUid, userId); Binder.restoreCallingIdentity(origId); return res; @@ -16757,15 +16786,16 @@ public final class ActivityManagerService extends ActivityManagerNative int broadcastIntentInPackage(String packageName, int uid, Intent intent, String resolvedType, IIntentReceiver resultTo, - int resultCode, String resultData, Bundle map, - String requiredPermission, boolean serialized, boolean sticky, int userId) { + int resultCode, String resultData, Bundle resultExtras, + String requiredPermission, Bundle options, boolean serialized, boolean sticky, + int userId) { synchronized(this) { intent = verifyBroadcastLocked(intent); final long origId = Binder.clearCallingIdentity(); int res = broadcastIntentLocked(null, packageName, intent, resolvedType, - resultTo, resultCode, resultData, map, requiredPermission, - AppOpsManager.OP_NONE, serialized, sticky, -1, uid, userId); + resultTo, resultCode, resultData, resultExtras, requiredPermission, + AppOpsManager.OP_NONE, options, serialized, sticky, -1, uid, userId); Binder.restoreCallingIdentity(origId); return res; } @@ -17162,8 +17192,8 @@ public final class ActivityManagerService extends ActivityManagerNative | Intent.FLAG_RECEIVER_REPLACE_PENDING | Intent.FLAG_RECEIVER_FOREGROUND); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, - null, AppOpsManager.OP_NONE, false, false, MY_PID, - Process.SYSTEM_UID, UserHandle.USER_ALL); + null, AppOpsManager.OP_NONE, null, false, false, + MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); if ((changes&ActivityInfo.CONFIG_LOCALE) != 0) { intent = new Intent(Intent.ACTION_LOCALE_CHANGED); intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); @@ -17172,7 +17202,7 @@ public final class ActivityManagerService extends ActivityManagerNative } broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } } } @@ -19642,7 +19672,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent.putExtra(Intent.EXTRA_USER_HANDLE, userId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - false, false, MY_PID, Process.SYSTEM_UID, userId); + null, false, false, MY_PID, Process.SYSTEM_UID, userId); } if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) { @@ -19657,8 +19687,7 @@ public final class ActivityManagerService extends ActivityManagerNative onUserInitialized(uss, foreground, oldUserId, userId); } }, 0, null, null, null, AppOpsManager.OP_NONE, - true, false, MY_PID, Process.SYSTEM_UID, - userId); + null, true, false, MY_PID, Process.SYSTEM_UID, userId); uss.initializing = true; } else { getUserManagerLocked().makeInitialized(userInfo.id); @@ -19680,13 +19709,13 @@ public final class ActivityManagerService extends ActivityManagerNative broadcastIntentLocked(null, null, intent, null, new IIntentReceiver.Stub() { @Override - public void performReceive(Intent intent, int resultCode, String data, - Bundle extras, boolean ordered, boolean sticky, int sendingUser) - throws RemoteException { + public void performReceive(Intent intent, int resultCode, + String data, Bundle extras, boolean ordered, boolean sticky, + int sendingUser) throws RemoteException { } }, 0, null, null, INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE, - true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } } } finally { @@ -19724,7 +19753,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - false, false, MY_PID, Process.SYSTEM_UID, profileUserId); + null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId); } } if (newUserId >= 0) { @@ -19739,7 +19768,7 @@ public final class ActivityManagerService extends ActivityManagerNative intent.putExtra(Intent.EXTRA_USER_HANDLE, profileUserId); broadcastIntentLocked(null, null, intent, null, null, 0, null, null, null, AppOpsManager.OP_NONE, - false, false, MY_PID, Process.SYSTEM_UID, profileUserId); + null, false, false, MY_PID, Process.SYSTEM_UID, profileUserId); } intent = new Intent(Intent.ACTION_USER_SWITCHED); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY @@ -19748,7 +19777,7 @@ public final class ActivityManagerService extends ActivityManagerNative broadcastIntentLocked(null, null, intent, null, null, 0, null, null, android.Manifest.permission.MANAGE_USERS, AppOpsManager.OP_NONE, - false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + null, false, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } } finally { Binder.restoreCallingIdentity(ident); @@ -19925,7 +19954,7 @@ public final class ActivityManagerService extends ActivityManagerNative broadcastIntentLocked(null, null, intent, null, null, 0, null, null, android.Manifest.permission.RECEIVE_BOOT_COMPLETED, AppOpsManager.OP_NONE, - true, false, MY_PID, Process.SYSTEM_UID, userId); + null, true, false, MY_PID, Process.SYSTEM_UID, userId); } } } @@ -20057,14 +20086,14 @@ public final class ActivityManagerService extends ActivityManagerNative mSystemServiceManager.stopUser(userId); broadcastIntentLocked(null, null, shutdownIntent, null, shutdownReceiver, 0, null, null, null, AppOpsManager.OP_NONE, - true, false, MY_PID, Process.SYSTEM_UID, userId); + null, true, false, MY_PID, Process.SYSTEM_UID, userId); } }; // Kick things off. broadcastIntentLocked(null, null, stoppingIntent, null, stoppingReceiver, 0, null, null, INTERACT_ACROSS_USERS, AppOpsManager.OP_NONE, - true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); + null, true, false, MY_PID, Process.SYSTEM_UID, UserHandle.USER_ALL); } finally { Binder.restoreCallingIdentity(ident); } diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java index eb5af9e..0714d36 100644 --- a/services/core/java/com/android/server/am/ActivityStack.java +++ b/services/core/java/com/android/server/am/ActivityStack.java @@ -1326,7 +1326,12 @@ final class ActivityStack { if (r != starting) { mStackSupervisor.startSpecificActivityLocked( r, noStackActivityResumed, false); - noStackActivityResumed = false; + if (activityNdx >= activities.size()) { + // Record may be removed if its process needs to restart. + activityNdx = activities.size() - 1; + } else { + noStackActivityResumed = false; + } } } else if (r.visible) { diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java index 80b8a93..2335071 100644 --- a/services/core/java/com/android/server/am/BroadcastQueue.java +++ b/services/core/java/com/android/server/am/BroadcastQueue.java @@ -26,6 +26,7 @@ import java.util.Set; import android.app.ActivityManager; import android.app.AppGlobals; import android.app.AppOpsManager; +import android.app.BroadcastOptions; import android.content.ComponentName; import android.content.IIntentReceiver; import android.content.Intent; @@ -43,6 +44,7 @@ import android.os.SystemClock; import android.os.UserHandle; import android.util.EventLog; import android.util.Slog; +import com.android.server.DeviceIdleController; import static com.android.server.am.ActivityManagerDebugConfig.*; @@ -146,6 +148,8 @@ public final class BroadcastQueue { static final int BROADCAST_INTENT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG; static final int BROADCAST_TIMEOUT_MSG = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 1; + static final int SCHEDULE_TEMP_WHITELIST_MSG + = ActivityManagerService.FIRST_BROADCAST_QUEUE_MSG + 2; final BroadcastHandler mHandler; @@ -167,6 +171,13 @@ public final class BroadcastQueue { broadcastTimeoutLocked(true); } } break; + case SCHEDULE_TEMP_WHITELIST_MSG: { + DeviceIdleController.LocalService dic = mService.mLocalDeviceIdleController; + if (dic != null) { + dic.addPowerSaveTempWhitelistAppDirect(UserHandle.getAppId(msg.arg1), + msg.arg2); + } + } break; } } }; @@ -547,6 +558,19 @@ public final class BroadcastQueue { } } + final void scheduleTempWhitelistLocked(int uid, long duration) { + if (duration > Integer.MAX_VALUE) { + duration = Integer.MAX_VALUE; + } + // XXX ideally we should pause the broadcast until everything behind this is done, + // or else we will likely start dispatching the broadcast before we have opened + // access to the app (there is a lot of asynchronicity behind this). It is probably + // not that big a deal, however, because the main purpose here is to allow apps + // to hold wake locks, and they will be able to acquire their wake lock immediately + // it just won't be enabled until we get through this work. + mHandler.obtainMessage(SCHEDULE_TEMP_WHITELIST_MSG, uid, (int)duration).sendToTarget(); + } + final void processNextBroadcast(boolean fromMsg) { synchronized(mService) { BroadcastRecord r; @@ -721,7 +745,9 @@ public final class BroadcastQueue { setBroadcastTimeoutLocked(timeoutTime); } - Object nextReceiver = r.receivers.get(recIdx); + final BroadcastOptions brOptions = r.options; + final Object nextReceiver = r.receivers.get(recIdx); + if (nextReceiver instanceof BroadcastFilter) { // Simple case: this is a registered receiver who gets // a direct call. @@ -739,6 +765,11 @@ public final class BroadcastQueue { + r.ordered + " receiver=" + r.receiver); r.state = BroadcastRecord.IDLE; scheduleBroadcastsLocked(); + } else { + if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { + scheduleTempWhitelistLocked(filter.owningUid, + brOptions.getTemporaryAppWhitelistDuration()); + } } return; } @@ -882,6 +913,11 @@ public final class BroadcastQueue { + info.activityInfo.applicationInfo.uid); } + if (brOptions != null && brOptions.getTemporaryAppWhitelistDuration() > 0) { + scheduleTempWhitelistLocked(receiverUid, + brOptions.getTemporaryAppWhitelistDuration()); + } + // Broadcast is being executed, its package can't be stopped. try { AppGlobals.getPackageManager().setPackageStoppedState( diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java index c050d03..b943222 100644 --- a/services/core/java/com/android/server/am/BroadcastRecord.java +++ b/services/core/java/com/android/server/am/BroadcastRecord.java @@ -17,6 +17,7 @@ package com.android.server.am; import android.app.AppOpsManager; +import android.app.BroadcastOptions; import android.content.IIntentReceiver; import android.content.ComponentName; import android.content.Intent; @@ -52,6 +53,7 @@ final class BroadcastRecord extends Binder { final String resolvedType; // the resolved data type final String requiredPermission; // a permission the caller has required final int appOp; // an app op that is associated with this broadcast + final BroadcastOptions options; // BroadcastOptions supplied by caller final List receivers; // contains BroadcastFilter and ResolveInfo IIntentReceiver resultTo; // who receives final result if non-null long enqueueClockTime; // the clock time the broadcast was enqueued @@ -105,6 +107,9 @@ final class BroadcastRecord extends Binder { pw.print(prefix); pw.print("requiredPermission="); pw.print(requiredPermission); pw.print(" appOp="); pw.println(appOp); } + if (options != null) { + pw.print(prefix); pw.print("options="); pw.println(options.toBundle()); + } pw.print(prefix); pw.print("enqueueClockTime="); pw.print(new Date(enqueueClockTime)); pw.print(" dispatchClockTime="); @@ -180,8 +185,8 @@ final class BroadcastRecord extends Binder { BroadcastRecord(BroadcastQueue _queue, Intent _intent, ProcessRecord _callerApp, String _callerPackage, int _callingPid, int _callingUid, String _resolvedType, String _requiredPermission, - int _appOp, List _receivers, IIntentReceiver _resultTo, int _resultCode, - String _resultData, Bundle _resultExtras, boolean _serialized, + int _appOp, BroadcastOptions _options, List _receivers, IIntentReceiver _resultTo, + int _resultCode, String _resultData, Bundle _resultExtras, boolean _serialized, boolean _sticky, boolean _initialSticky, int _userId) { queue = _queue; @@ -194,6 +199,7 @@ final class BroadcastRecord extends Binder { resolvedType = _resolvedType; requiredPermission = _requiredPermission; appOp = _appOp; + options = _options; receivers = _receivers; resultTo = _resultTo; resultCode = _resultCode; diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java index 531de46..ece3ffb 100644 --- a/services/core/java/com/android/server/am/PendingIntentRecord.java +++ b/services/core/java/com/android/server/am/PendingIntentRecord.java @@ -199,9 +199,9 @@ final class PendingIntentRecord extends IIntentSender.Stub { } public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, - String requiredPermission) throws TransactionTooLargeException { + String requiredPermission, Bundle options) throws TransactionTooLargeException { return sendInner(code, intent, resolvedType, finishedReceiver, - requiredPermission, null, null, 0, 0, 0, null, null); + requiredPermission, null, null, 0, 0, 0, options, null); } int sendInner(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, @@ -293,9 +293,9 @@ final class PendingIntentRecord extends IIntentSender.Stub { // If a completion callback has been requested, require // that the broadcast be delivered synchronously int sent = owner.broadcastIntentInPackage(key.packageName, uid, - finalIntent, resolvedType, - finishedReceiver, code, null, null, - requiredPermission, (finishedReceiver != null), false, userId); + finalIntent, resolvedType, finishedReceiver, code, null, null, + requiredPermission, options, (finishedReceiver != null), + false, userId); if (sent == ActivityManager.BROADCAST_SUCCESS) { sendFinish = false; } diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 236af37..87cb40e 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -445,6 +445,11 @@ final class ServiceRecord extends Binder { // icon, but this used to be able to slip through, so for // those dirty apps we will create a notification clearly // blaming the app. + Slog.v(TAG, "Attempted to start a foreground service (" + + name + + ") with a broken notification (no icon: " + + localForegroundNoti + + ")"); CharSequence appName = appInfo.loadLabel( ams.mContext.getPackageManager()); @@ -461,6 +466,12 @@ final class ServiceRecord extends Binder { // it's ugly, but it clearly identifies the app notiBuilder.setSmallIcon(appInfo.icon); + // mark as foreground + notiBuilder.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true); + + // we are doing the app a kindness here + notiBuilder.setPriority(Notification.PRIORITY_MIN); + Intent runningIntent = new Intent( Settings.ACTION_APPLICATION_DETAILS_SETTINGS); runningIntent.setData(Uri.fromParts("package", @@ -498,6 +509,8 @@ final class ServiceRecord extends Binder { nm.enqueueNotification(localPackageName, localPackageName, appUid, appPid, null, localForegroundId, localForegroundNoti, outId, userId); + + foregroundNoti = localForegroundNoti; // save it for amending next time } catch (RuntimeException e) { Slog.w(TAG, "Error showing notification for service", e); // If it gave us a garbage notification, it doesn't diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d39b25f..47d3bde 100644 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1542,11 +1542,7 @@ public class AudioService extends IAudioService.Stub { // UI update and Broadcast Intent private void sendVolumeUpdate(int streamType, int oldIndex, int index, int flags) { - if (!isPlatformVoice() && (streamType == AudioSystem.STREAM_RING)) { - streamType = AudioSystem.STREAM_NOTIFICATION; - } else { - streamType = mStreamVolumeAlias[streamType]; - } + streamType = mStreamVolumeAlias[streamType]; if (streamType == AudioSystem.STREAM_MUSIC) { flags = updateFlagsForSystemAudio(flags); diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java index dca762c..569a0fc 100644 --- a/services/core/java/com/android/server/media/MediaSessionRecord.java +++ b/services/core/java/com/android/server/media/MediaSessionRecord.java @@ -242,19 +242,17 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { } if (mVolumeType == PlaybackInfo.PLAYBACK_TYPE_LOCAL) { int stream = AudioAttributes.toLegacyStreamType(mAudioAttrs); + // Adjust the volume with a handler not to be blocked by other system service. if (useSuggested) { if (AudioSystem.isStreamActive(stream, 0)) { - mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(stream, direction, - flags, packageName, uid); + postAdjustSuggestedStreamVolume(stream, direction, flags, packageName, uid); } else { flags |= previousFlagPlaySound; - mAudioManagerInternal.adjustSuggestedStreamVolumeForUid( - AudioManager.USE_DEFAULT_STREAM_TYPE, direction, flags, packageName, - uid); + postAdjustSuggestedStreamVolume(AudioManager.USE_DEFAULT_STREAM_TYPE, direction, + flags, packageName, uid); } } else { - mAudioManagerInternal.adjustStreamVolumeForUid(stream, direction, flags, - packageName, uid); + postAdjustStreamVolume(stream, direction, flags, packageName, uid); } } else { if (mVolumeControlType == VolumeProvider.VOLUME_CONTROL_FIXED) { @@ -461,6 +459,28 @@ public class MediaSessionRecord implements IBinder.DeathRecipient { return mPackageName + "/" + mTag; } + private void postAdjustSuggestedStreamVolume(final int streamType, final int direction, + final int flags, final String callingPackage, final int uid) { + mHandler.post(new Runnable() { + @Override + public void run() { + mAudioManagerInternal.adjustSuggestedStreamVolumeForUid(streamType, direction, + flags, callingPackage, uid); + } + }); + } + + private void postAdjustStreamVolume(final int streamType, final int direction, final int flags, + final String callingPackage, final int uid) { + mHandler.post(new Runnable() { + @Override + public void run() { + mAudioManagerInternal.adjustStreamVolumeForUid(streamType, direction, flags, + callingPackage, uid); + } + }); + } + private String getShortMetadataString() { int fields = mMetadata == null ? 0 : mMetadata.size(); MediaDescription description = mMetadata == null ? null : mMetadata diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java index 0f88883..9db6a06 100644 --- a/services/core/java/com/android/server/net/LockdownVpnTracker.java +++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java @@ -17,6 +17,7 @@ package com.android.server.net; import static android.Manifest.permission.CONNECTIVITY_INTERNAL; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE; import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; @@ -201,8 +202,8 @@ public class LockdownVpnTracker { setFirewallEgressSourceRule(addr, true); } - mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_ALLOW); - mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_ALLOW); + mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, ROOT_UID, FIREWALL_RULE_ALLOW); + mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, Os.getuid(), FIREWALL_RULE_ALLOW); mErrorCount = 0; mAcceptedIface = iface; @@ -291,8 +292,8 @@ public class LockdownVpnTracker { setFirewallEgressSourceRule(addr, false); } - mNetService.setFirewallUidRule(ROOT_UID, FIREWALL_RULE_DEFAULT); - mNetService.setFirewallUidRule(Os.getuid(), FIREWALL_RULE_DEFAULT); + mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, ROOT_UID, FIREWALL_RULE_DEFAULT); + mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE,Os.getuid(), FIREWALL_RULE_DEFAULT); mAcceptedSourceAddr = null; } diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java index e009455..b0550d6 100644 --- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java +++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java @@ -36,8 +36,10 @@ import static android.net.NetworkPolicy.LIMIT_DISABLED; import static android.net.NetworkPolicy.SNOOZE_NEVER; import static android.net.NetworkPolicy.WARNING_DISABLED; import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE; +import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY; +import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW; import static android.net.NetworkPolicyManager.FIREWALL_RULE_DENY; -import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT; import static android.net.NetworkPolicyManager.POLICY_ALLOW_BACKGROUND_BATTERY_SAVE; import static android.net.NetworkPolicyManager.POLICY_NONE; import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND; @@ -80,7 +82,6 @@ import android.app.AppGlobals; import android.app.AppOpsManager; import android.app.IActivityManager; import android.app.INotificationManager; -import android.app.IProcessObserver; import android.app.IUidObserver; import android.app.Notification; import android.app.PendingIntent; @@ -141,7 +142,6 @@ import android.util.Log; import android.util.NtpTrustedTime; import android.util.Pair; import android.util.Slog; -import android.util.SparseArray; import android.util.SparseBooleanArray; import android.util.SparseIntArray; import android.util.TrustedTime; @@ -279,6 +279,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub final SparseIntArray mUidPolicy = new SparseIntArray(); /** Currently derived rules for each UID. */ final SparseIntArray mUidRules = new SparseIntArray(); + final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray(); /** * UIDs that have been white-listed to always be able to have network access @@ -412,8 +413,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class); - final PackageManager pm = mContext.getPackageManager(); - synchronized (mRulesLock) { updatePowerSaveWhitelistLocked(); mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class); @@ -1103,7 +1102,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub // will not have a bandwidth limit. Also only do this if restrict // background data use is *not* enabled, since that takes precendence // use over those networks can have a cost associated with it). - final boolean powerSave = (mRestrictPower || mDeviceIdleMode) && !mRestrictBackground; + final boolean powerSave = mRestrictPower && !mRestrictBackground; // First, generate identities of all connected networks so we can // quickly compare them against all defined policies below. @@ -2024,6 +2023,29 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub } } + void updateRulesForDeviceIdleLocked() { + if (mDeviceIdleMode) { + // sync the whitelists before enable dozable chain. We don't care about the rules if + // we are disabling the chain. + SparseIntArray uidRules = new SparseIntArray(); + final List<UserInfo> users = mUserManager.getUsers(); + for (UserInfo user : users) { + for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) { + int appId = mPowerSaveTempWhitelistAppIds.keyAt(i); + int uid = UserHandle.getUid(user.id, appId); + uidRules.put(uid, FIREWALL_RULE_ALLOW); + } + for (int i = mPowerSaveWhitelistAppIds.size() - 1; i >= 0; i--) { + int appId = mPowerSaveWhitelistAppIds.keyAt(i); + int uid = UserHandle.getUid(user.id, appId); + uidRules.put(uid, FIREWALL_RULE_ALLOW); + } + } + setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules); + } + enableFirewallChain(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode); + } + /** * Update rules that might be changed by {@link #mRestrictBackground}, * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value. @@ -2034,10 +2056,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub // If we are in restrict power mode, we allow all important apps // to have data access. Otherwise, we restrict data access to only // the top apps. - mCurForegroundState = (!mRestrictBackground && (mRestrictPower || mDeviceIdleMode)) + mCurForegroundState = (!mRestrictBackground && mRestrictPower) ? ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE : ActivityManager.PROCESS_STATE_TOP; + updateRulesForDeviceIdleLocked(); + // update rules for all installed applications final List<UserInfo> users = mUserManager.getUsers(); final List<ApplicationInfo> apps = pm.getInstalledApplications( @@ -2131,7 +2155,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub // uid in background, and global background disabled uidRules = RULE_REJECT_METERED; } - } else if (mRestrictPower || mDeviceIdleMode) { + } else if (mRestrictPower) { final boolean whitelisted = mPowerSaveWhitelistAppIds.get(appId) || mPowerSaveTempWhitelistAppIds.get(appId); if (!whitelisted && !uidForeground @@ -2162,7 +2186,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub final boolean oldFirewallReject = (oldRules & RULE_REJECT_ALL) != 0; final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0; if (oldFirewallReject != firewallReject) { - setUidFirewallRules(uid, firewallReject); + setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, firewallReject); + if (mDeviceIdleMode && !firewallReject) { + // if we are in device idle mode, and we decide to allow this uid. we need to punch + // a hole in the device idle chain. + setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, false); + } } // dispatch changed rule to existing listeners @@ -2314,14 +2343,34 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub } /** + * Set uid rules on a particular firewall chain. This is going to synchronize the rules given + * here to netd. It will clean up dead rules and make sure the target chain only contains rules + * specified here. + */ + private void setUidFirewallRules(int chain, SparseIntArray uidRules) { + try { + int size = uidRules.size(); + int[] uids = new int[size]; + int[] rules = new int[size]; + for(int index = size - 1; index >= 0; --index) { + uids[index] = uidRules.keyAt(index); + rules[index] = uidRules.valueAt(index); + } + mNetworkManager.setFirewallUidRules(chain, uids, rules); + } catch (IllegalStateException e) { + Log.wtf(TAG, "problem setting firewall uid rules", e); + } catch (RemoteException e) { + // ignored; service lives in system_server + } + } + + /** * Add or remove a uid to the firewall blacklist for all network ifaces. - * @param uid - * @param rejectOnAll */ - private void setUidFirewallRules(int uid, boolean rejectOnAll) { + private void setUidFirewallRule(int chain, int uid, boolean rejectOnAll) { try { - mNetworkManager.setFirewallUidRule(uid, - rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_DEFAULT); + mNetworkManager.setFirewallUidRule(chain, uid, + rejectOnAll ? FIREWALL_RULE_DENY : FIREWALL_RULE_ALLOW); } catch (IllegalStateException e) { Log.wtf(TAG, "problem setting firewall uid rules", e); } catch (RemoteException e) { @@ -2329,6 +2378,24 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub } } + /** + * Add or remove a uid to the firewall blacklist for all network ifaces. + */ + private void enableFirewallChain(int chain, boolean enable) { + if (mFirewallChainStates.indexOfKey(chain) >= 0 && + mFirewallChainStates.get(chain) == enable) { + // All is the same, nothing to do. + return; + } + try { + mNetworkManager.setFirewallChainEnabled(chain, enable); + } catch (IllegalStateException e) { + Log.wtf(TAG, "problem enable firewall chain", e); + } catch (RemoteException e) { + // ignored; service lives in system_server + } + } + private long getTotalBytes(NetworkTemplate template, long start, long end) { try { return mNetworkStats.getNetworkTotalBytes(template, start, end); diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 5b7dd70..06e27fc 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -8808,7 +8808,7 @@ public class PackageManagerService extends IPackageManager.Stub { } am.broadcastIntent(null, intent, null, finishedReceiver, 0, null, null, null, android.app.AppOpsManager.OP_NONE, - finishedReceiver != null, false, id); + null, finishedReceiver != null, false, id); } } catch (RemoteException ex) { } @@ -8982,7 +8982,7 @@ public class PackageManagerService extends IPackageManager.Stub { .addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES) .setPackage(packageName); am.broadcastIntent(null, bcIntent, null, null, 0, null, null, null, - android.app.AppOpsManager.OP_NONE, false, false, userId); + android.app.AppOpsManager.OP_NONE, null, false, false, userId); } } catch (RemoteException e) { // shouldn't happen diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java index dbcfa19..6fb9a5c 100644 --- a/services/core/java/com/android/server/policy/PhoneWindowManager.java +++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java @@ -3739,13 +3739,14 @@ public class PhoneWindowManager implements WindowManagerPolicy { attrs.gravity = Gravity.BOTTOM; mDockLayer = win.getSurfaceLayer(); } else if (attrs.type == TYPE_VOICE_INTERACTION) { - pf.left = df.left = of.left = cf.left = vf.left = mUnrestrictedScreenLeft; + pf.left = df.left = of.left = mUnrestrictedScreenLeft; pf.top = df.top = of.top = mUnrestrictedScreenTop; - pf.right = df.right = of.right = cf.right = vf.right = mUnrestrictedScreenLeft - + mUnrestrictedScreenWidth; - pf.bottom = df.bottom = of.bottom = cf.bottom = mUnrestrictedScreenTop - + mUnrestrictedScreenHeight; + pf.right = df.right = of.right = mUnrestrictedScreenLeft + mUnrestrictedScreenWidth; + pf.bottom = df.bottom = of.bottom = mUnrestrictedScreenTop + mUnrestrictedScreenHeight; cf.bottom = vf.bottom = mStableBottom; + // Note: In Phone landscape mode, the button bar should also be excluded. + cf.right = vf.right = mStableRight; + cf.left = vf.left = mStableLeft; cf.top = vf.top = mStableTop; } else if (win == mStatusBar) { pf.left = df.left = of.left = mUnrestrictedScreenLeft; diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 1b63ca0..ace5997 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -7139,20 +7139,14 @@ public class WindowManagerService extends IWindowManager.Stub public Configuration computeNewConfiguration() { synchronized (mWindowMap) { - if (!mDisplayReady) { - return null; - } - Configuration config = computeNewConfigurationLocked(); - if (mWaitingForConfig) { - mWaitingForConfig = false; - mLastFinishedFreezeSource = "new-config"; - performLayoutAndPlaceSurfacesLocked(); - } - return config; + return computeNewConfigurationLocked(); } } - Configuration computeNewConfigurationLocked() { + private Configuration computeNewConfigurationLocked() { + if (!mDisplayReady) { + return null; + } Configuration config = new Configuration(); config.fontScale = 0; computeScreenConfigurationLocked(config); @@ -9678,7 +9672,7 @@ public class WindowManagerService extends IWindowManager.Stub /** * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method. - * @param w WindowState this method is applied to. + * @param w WindowState this method is applied to. * @param innerDw Width of app window. * @param innerDh Height of app window. */ diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f1f61f3..3b62b61 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -211,6 +211,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SMS); DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_FUN); DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SAFE_BOOT); + DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_CREATE_WINDOWS); } // The following user restrictions cannot be changed by any active admin, including device diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java index 75b8278..3767fce 100644 --- a/services/usage/java/com/android/server/usage/UsageStatsService.java +++ b/services/usage/java/com/android/server/usage/UsageStatsService.java @@ -981,7 +981,7 @@ public class UsageStatsService extends SystemService implements } } - private class BinderService extends IUsageStatsManager.Stub { + private final class BinderService extends IUsageStatsManager.Stub { private boolean hasPermission(String callingPackage) { final int callingUid = Binder.getCallingUid(); @@ -1121,7 +1121,7 @@ public class UsageStatsService extends SystemService implements * ActivityManagerService will call these methods holding the 'am' lock, which means we * shouldn't be doing any IO work or other long running tasks in these methods. */ - private class LocalService extends UsageStatsManagerInternal { + private final class LocalService extends UsageStatsManagerInternal { @Override public void reportEvent(ComponentName component, int userId, int eventType) { diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java index 0b430ca..47a230a 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java @@ -180,8 +180,6 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { public boolean showLocked(Bundle args, int flags, IVoiceInteractionSessionShowCallback showCallback) { - // For now we never allow screenshots. - flags &= ~VoiceInteractionSession.SHOW_WITH_SCREENSHOT; if (mBound) { if (!mFullyBound) { mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection, @@ -190,13 +188,15 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { new UserHandle(mUser)); } mShown = true; + boolean allDataEnabled = Settings.Secure.getIntForUser(mContext.getContentResolver(), + Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0; mShowArgs = args; mShowFlags = flags; mHaveAssistData = false; if ((flags& VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) { if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid, mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED - && isStructureEnabled()) { + && allDataEnabled) { try { mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL, mAssistReceiver); @@ -212,7 +212,8 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mHaveScreenshot = false; if ((flags& VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) { if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_SCREENSHOT, mCallingUid, - mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED) { + mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED + && allDataEnabled) { try { mIWindowManager.requestAssistScreenshot(mScreenshotReceiver); } catch (RemoteException e) { @@ -466,11 +467,6 @@ final class VoiceInteractionSessionConnection implements ServiceConnection { mService = null; } - private boolean isStructureEnabled() { - return Settings.Secure.getIntForUser(mContext.getContentResolver(), - Settings.Secure.ASSIST_STRUCTURE_ENABLED, 1, mUser) != 0; - } - public void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("mToken="); pw.println(mToken); pw.print(prefix); pw.print("mShown="); pw.println(mShown); diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index bcfee30..0eb94b8 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -125,6 +125,10 @@ public class CarrierConfigManager { public static final String KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL = "hide_carrier_network_settings_bool"; + /** Control whether users can reach the SIM lock settings. */ + public static final String + KEY_HIDE_SIM_LOCK_SETTINGS_BOOL = "hide_sim_lock_settings_bool"; + /** Control whether users can edit APNs in Settings. */ public static final String KEY_APN_EXPAND_BOOL = "apn_expand_bool"; @@ -178,6 +182,34 @@ public class CarrierConfigManager { public static final String KEY_DISABLE_CDMA_ACTIVATION_CODE_BOOL = "disable_cdma_activation_code_bool"; + /** + * Override the platform's notion of a network operator being considered roaming. + * Value is string array of MCCMNCs to be considered roaming for 3GPP RATs. + */ + public static final String + KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY = "gsm_roaming_networks_string_array"; + + /** + * Override the platform's notion of a network operator being considered not roaming. + * Value is string array of MCCMNCs to be considered not roaming for 3GPP RATs. + */ + public static final String + KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY = "gsm_nonroaming_networks_string_array"; + + /** + * Override the platform's notion of a network operator being considered roaming. + * Value is string array of SIDs to be considered roaming for 3GPP2 RATs. + */ + public static final String + KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY = "cdma_roaming_networks_string_array"; + + /** + * Override the platform's notion of a network operator being considered non roaming. + * Value is string array of SIDs to be considered not roaming for 3GPP2 RATs. + */ + public static final String + KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY = "cdma_nonroaming_networks_string_array"; + /** * Flag specifying whether VoLTE should be available for carrier, independent of carrier * provisioning. If false: hard disabled. If true: then depends on carrier provisioning, @@ -328,6 +360,7 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_ENABLE_DIALER_KEY_VIBRATION_BOOL, true); sDefaults.putBoolean(KEY_HAS_IN_CALL_NOISE_SUPPRESSION_BOOL, false); sDefaults.putBoolean(KEY_HIDE_CARRIER_NETWORK_SETTINGS_BOOL, false); + sDefaults.putBoolean(KEY_HIDE_SIM_LOCK_SETTINGS_BOOL, false); sDefaults.putBoolean(KEY_IGNORE_SIM_NETWORK_LOCKED_EVENTS_BOOL, false); sDefaults.putBoolean(KEY_OPERATOR_SELECTION_EXPAND_BOOL, true); sDefaults.putBoolean(KEY_PREFER_2G_BOOL, true); @@ -353,6 +386,11 @@ public class CarrierConfigManager { sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING, ""); sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_VAL_STRING, ""); + sDefaults.putStringArray(KEY_GSM_ROAMING_NETWORKS_STRING_ARRAY, null); + sDefaults.putStringArray(KEY_GSM_NONROAMING_NETWORKS_STRING_ARRAY, null); + sDefaults.putStringArray(KEY_CDMA_ROAMING_NETWORKS_STRING_ARRAY, null); + sDefaults.putStringArray(KEY_CDMA_NONROAMING_NETWORKS_STRING_ARRAY, null); + // MMS defaults sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false); sDefaults.putBoolean(KEY_MMS_ALLOW_ATTACH_AUDIO_BOOL, true); diff --git a/telephony/java/android/telephony/DisconnectCause.java b/telephony/java/android/telephony/DisconnectCause.java index 674777e..8443490 100644 --- a/telephony/java/android/telephony/DisconnectCause.java +++ b/telephony/java/android/telephony/DisconnectCause.java @@ -153,17 +153,17 @@ public class DisconnectCause { /** * The outgoing call failed with an unknown cause. */ - public static final int OUTGOING_FAILURE = 43; + public static final int OUTGOING_FAILURE = 43; /** * The outgoing call was canceled by the {@link android.telecom.ConnectionService}. */ - public static final int OUTGOING_CANCELED = 44; + public static final int OUTGOING_CANCELED = 44; /** * The call, which was an IMS call, disconnected because it merged with another call. */ - public static final int IMS_MERGED_SUCCESSFULLY = 45; + public static final int IMS_MERGED_SUCCESSFULLY = 45; /** * Stk Call Control modified DIAL request to USSD request. @@ -181,6 +181,12 @@ public class DisconnectCause { */ public static final int DIAL_MODIFIED_TO_DIAL = 48; + /** + * The call was terminated because CDMA phone service and roaming have already been activated. + * {@hide} + */ + public static final int CDMA_ALREADY_ACTIVATED = 49; + //********************************************************************************************* // When adding a disconnect type: // 1) Please assign the new type the next id value below. @@ -189,14 +195,14 @@ public class DisconnectCause { // 4) Update toString() with the newly added disconnect type. // 5) Update android.telecom.DisconnectCauseUtil with any mappings to a telecom.DisconnectCause. // - // NextId: 49 + // NextId: 50 //********************************************************************************************* /** Smallest valid value for call disconnect codes. */ public static final int MINIMUM_VALID_VALUE = NOT_DISCONNECTED; /** Largest valid value for call disconnect codes. */ - public static final int MAXIMUM_VALID_VALUE = DIAL_MODIFIED_TO_DIAL; + public static final int MAXIMUM_VALID_VALUE = CDMA_ALREADY_ACTIVATED; /** Private constructor to avoid class instantiation. */ private DisconnectCause() { @@ -302,6 +308,8 @@ public class DisconnectCause { return "OUTGOING_CANCELED"; case IMS_MERGED_SUCCESSFULLY: return "IMS_MERGED_SUCCESSFULLY"; + case CDMA_ALREADY_ACTIVATED: + return "CDMA_ALREADY_ACTIVATED"; default: return "INVALID: " + cause; } diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index e085d89..fa1ed54 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -1124,13 +1124,14 @@ public class SubscriptionManager { * {@hide} */ public static int getSimStateForSlotIdx(int slotIdx) { - int simState; + int simState = TelephonyManager.SIM_STATE_UNKNOWN; try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); - simState = iSub.getSimStateForSlotIdx(slotIdx); + if (iSub != null) { + simState = iSub.getSimStateForSlotIdx(slotIdx); + } } catch (RemoteException ex) { - simState = TelephonyManager.SIM_STATE_UNKNOWN; } logd("getSimStateForSubscriber: simState=" + simState + " slotIdx=" + slotIdx); return simState; @@ -1144,7 +1145,9 @@ public class SubscriptionManager { public boolean isActiveSubId(int subId) { try { ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub")); - return iSub.isActiveSubId(subId); + if (iSub != null) { + return iSub.isActiveSubId(subId); + } } catch (RemoteException ex) { } return false; diff --git a/test-runner/src/android/test/mock/MockContext.java b/test-runner/src/android/test/mock/MockContext.java index 04ded9d..e5e3e44 100644 --- a/test-runner/src/android/test/mock/MockContext.java +++ b/test-runner/src/android/test/mock/MockContext.java @@ -16,6 +16,7 @@ package android.test.mock; +import android.annotation.SystemApi; import android.content.ComponentName; import android.content.ContentResolver; import android.content.Context; @@ -317,6 +318,13 @@ public class MockContext extends Context { } /** @hide */ + @SystemApi + @Override + public void sendBroadcast(Intent intent, String receiverPermission, Bundle options) { + throw new UnsupportedOperationException(); + } + + /** @hide */ @Override public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { throw new UnsupportedOperationException(); @@ -336,6 +344,15 @@ public class MockContext extends Context { } /** @hide */ + @SystemApi + @Override + public void sendOrderedBroadcast(Intent intent, String receiverPermission, + Bundle options, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, + Bundle initialExtras) { + throw new UnsupportedOperationException(); + } + + /** @hide */ @Override public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, diff --git a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml index d282fc9..0f3fb95 100644 --- a/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml +++ b/tests/VectorDrawableTest/res/drawable/vector_drawable04.xml @@ -13,37 +13,41 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:width="64dp" - android:height="64dp" - android:viewportWidth="7.30625" - android:viewportHeight="12.25" - android:autoMirrored="true"> + android:autoMirrored="true" + android:height="64dp" + android:viewportHeight="12.25" + android:viewportWidth="7.30625" + android:width="64dp" > <group> <clip-path - android:name="clip1" - android:pathData=" + android:name="clip1" + android:pathData=" M 3.65, 6.125 m-.001, 0 a .001,.001 0 1,0 .002,0 - a .001,.001 0 1,0-.002,0z"/> + a .001,.001 0 1,0-.002,0z" /> + <path - android:name="one" - android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 + android:name="one" + android:fillColor="#ff88ff" + android:pathData="M 1.215625,9.5l 1.9375,0.0 0.0-6.671875-2.109375,0.421875 0.0-1.078125 l 2.09375-0.421875 1.1874998,0.0 0.0,7.75 1.9375,0.0 0.0,1.0 - l-5.046875,0.0 0.0-1.0Z" - android:fillColor="#ff88ff"/> - + l-5.046875,0.0 0.0-1.0Z" /> + </group> + <group> <clip-path - android:name="clip2" - android:pathData=" + android:name="clip2" + android:pathData=" M 3.65, 6.125 m-6, 0 a 6,6 0 1,0 12,0 - a 6,6 0 1,0-12,0z"/> + a 6,6 0 1,0-12,0z" /> + <path - android:name="two" - android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 + android:name="two" + android:fillColor="#ff88ff" + android:pathData="M 2.534375,9.6875l 4.140625,0.0 0.0,1.0-5.5625,0.0 0.0-1.0q 0.671875-0.6875 1.828125-1.859375 q 1.1718752-1.1875 1.4687502-1.53125 0.578125-0.625 0.796875-1.0625 q 0.234375-0.453125 0.234375-0.875 0.0-0.703125-0.5-1.140625 q-0.484375-0.4375-1.2656252-0.4375-0.5625,0.0-1.1875,0.1875 @@ -51,7 +55,7 @@ q 0.625-0.15625 1.140625-0.15625 1.3593752,0.0 2.1718752,0.6875 q 0.8125,0.671875 0.8125,1.8125 0.0,0.53125-0.203125,1.015625 q-0.203125,0.484375-0.734375,1.140625-0.15625,0.171875-0.9375,0.984375 - q-0.78125024,0.8125-2.2187502,2.265625Z" - android:fillColor="#ff88ff"/> + q-0.78125024,0.8125-2.2187502,2.265625Z" /> </group> -</vector> + +</vector>
\ No newline at end of file diff --git a/tools/aapt2/BinaryResourceParser.cpp b/tools/aapt2/BinaryResourceParser.cpp index 3559f43..4f1947a 100644 --- a/tools/aapt2/BinaryResourceParser.cpp +++ b/tools/aapt2/BinaryResourceParser.cpp @@ -116,9 +116,11 @@ private: BinaryResourceParser::BinaryResourceParser(const std::shared_ptr<ResourceTable>& table, const std::shared_ptr<IResolver>& resolver, const Source& source, + const std::u16string& defaultPackage, const void* data, size_t len) : - mTable(table), mResolver(resolver), mSource(source), mData(data), mDataLen(len) { + mTable(table), mResolver(resolver), mSource(source), mDefaultPackage(defaultPackage), + mData(data), mDataLen(len) { } bool BinaryResourceParser::parse() { @@ -177,6 +179,9 @@ bool BinaryResourceParser::getSymbol(const void* data, ResourceNameRef* outSymbo if (!type) { return false; } + if (outSymbol->package.empty()) { + outSymbol->package = mTable->getPackage(); + } outSymbol->type = *type; // Since we scan the symbol table in order, we can start looking for the @@ -350,7 +355,22 @@ bool BinaryResourceParser::parsePackage(const ResChunk_header* chunk) { size_t len = strnlen16(reinterpret_cast<const char16_t*>(packageHeader->name), sizeof(packageHeader->name) / sizeof(packageHeader->name[0])); - mTable->setPackage(StringPiece16(reinterpret_cast<const char16_t*>(packageHeader->name), len)); + if (mTable->getPackage().empty() && len == 0) { + mTable->setPackage(mDefaultPackage); + } else if (len > 0) { + StringPiece16 thisPackage(reinterpret_cast<const char16_t*>(packageHeader->name), len); + if (mTable->getPackage().empty()) { + mTable->setPackage(thisPackage); + } else if (thisPackage != mTable->getPackage()) { + Logger::error(mSource) + << "incompatible packages: " + << mTable->getPackage() + << " vs. " + << thisPackage + << std::endl; + return false; + } + } ResChunkPullParser parser(getChunkData(packageHeader->header), getChunkDataLen(packageHeader->header)); diff --git a/tools/aapt2/BinaryResourceParser.h b/tools/aapt2/BinaryResourceParser.h index 32876cd..3aab301 100644 --- a/tools/aapt2/BinaryResourceParser.h +++ b/tools/aapt2/BinaryResourceParser.h @@ -45,6 +45,7 @@ public: BinaryResourceParser(const std::shared_ptr<ResourceTable>& table, const std::shared_ptr<IResolver>& resolver, const Source& source, + const std::u16string& defaultPackage, const void* data, size_t len); BinaryResourceParser(const BinaryResourceParser&) = delete; // No copy. @@ -97,12 +98,12 @@ private: const Source mSource; + // The package name of the resource table. + std::u16string mDefaultPackage; + const void* mData; const size_t mDataLen; - // The package name of the resource table. - std::u16string mPackage; - // The array of symbol entries. Each element points to an offset // in the table and an index into the symbol table string pool. const SymbolTable_entry* mSymbolEntries = nullptr; diff --git a/tools/aapt2/Linker.cpp b/tools/aapt2/Linker.cpp index f3f04a5..c37cc93 100644 --- a/tools/aapt2/Linker.cpp +++ b/tools/aapt2/Linker.cpp @@ -160,7 +160,7 @@ const Attribute* Linker::doResolveAttribute(Reference& attribute, const SourceLi void Linker::visit(Reference& reference, ValueVisitorArgs& a) { Args& args = static_cast<Args&>(a); - if (!reference.name.isValid()) { + if (reference.name.entry.empty()) { // We can't have a completely bad reference. if (!reference.id.isValid()) { Logger::error() << "srsly? " << args.referrer << std::endl; diff --git a/tools/aapt2/Main.cpp b/tools/aapt2/Main.cpp index 41c229d..54a7329 100644 --- a/tools/aapt2/Main.cpp +++ b/tools/aapt2/Main.cpp @@ -756,8 +756,8 @@ bool link(const AaptOptions& options, const std::shared_ptr<ResourceTable>& outT zipFile->uncompress(entry)); assert(uncompressedData); - BinaryResourceParser parser(table, resolver, source, uncompressedData.get(), - entry->getUncompressedLen()); + BinaryResourceParser parser(table, resolver, source, options.appInfo.package, + uncompressedData.get(), entry->getUncompressedLen()); if (!parser.parse()) { return false; } @@ -1085,50 +1085,47 @@ static AaptOptions prepareArgs(int argc, char** argv) { } bool isStaticLib = false; + if (options.phase == AaptOptions::Phase::Link) { + flag::requiredFlag("--manifest", "AndroidManifest.xml of your app", + [&options](const StringPiece& arg) { + options.manifest = Source{ arg.toString() }; + }); + + flag::optionalFlag("-I", "add an Android APK to link against", + [&options](const StringPiece& arg) { + options.libraries.push_back(Source{ arg.toString() }); + }); + + flag::optionalFlag("--java", "directory in which to generate R.java", + [&options](const StringPiece& arg) { + options.generateJavaClass = Source{ arg.toString() }; + }); + + flag::optionalFlag("--proguard", "file in which to output proguard rules", + [&options](const StringPiece& arg) { + options.generateProguardRules = Source{ arg.toString() }; + }); + + flag::optionalSwitch("--static-lib", "generate a static Android library", true, + &isStaticLib); + + flag::optionalFlag("--binding", "Output directory for binding XML files", + [&options](const StringPiece& arg) { + options.bindingOutput = Source{ arg.toString() }; + }); + flag::optionalSwitch("--no-version", "Disables automatic style and layout versioning", + false, &options.versionStylesAndLayouts); + } + if (options.phase == AaptOptions::Phase::Compile || options.phase == AaptOptions::Phase::Link) { - if (options.phase == AaptOptions::Phase::Compile) { - flag::requiredFlag("--package", "Android package name", - [&options](const StringPiece& arg) { - options.appInfo.package = util::utf8ToUtf16(arg); - }); - } else if (options.phase == AaptOptions::Phase::Link) { - flag::requiredFlag("--manifest", "AndroidManifest.xml of your app", - [&options](const StringPiece& arg) { - options.manifest = Source{ arg.toString() }; - }); - - flag::optionalFlag("-I", "add an Android APK to link against", - [&options](const StringPiece& arg) { - options.libraries.push_back(Source{ arg.toString() }); - }); - - flag::optionalFlag("--java", "directory in which to generate R.java", - [&options](const StringPiece& arg) { - options.generateJavaClass = Source{ arg.toString() }; - }); - - flag::optionalFlag("--proguard", "file in which to output proguard rules", - [&options](const StringPiece& arg) { - options.generateProguardRules = Source{ arg.toString() }; - }); - - flag::optionalSwitch("--static-lib", "generate a static Android library", true, - &isStaticLib); - - flag::optionalFlag("--binding", "Output directory for binding XML files", - [&options](const StringPiece& arg) { - options.bindingOutput = Source{ arg.toString() }; - }); - flag::optionalSwitch("--no-version", "Disables automatic style and layout versioning", - false, &options.versionStylesAndLayouts); - } - // Common flags for all steps. flag::requiredFlag("-o", "Output path", [&options](const StringPiece& arg) { options.output = Source{ arg.toString() }; }); - } else if (options.phase == AaptOptions::Phase::DumpStyleGraph) { + } + + if (options.phase == AaptOptions::Phase::DumpStyleGraph) { flag::requiredFlag("--style", "Name of the style to dump", [&options](const StringPiece& arg, std::string* outError) -> bool { Reference styleReference; @@ -1191,7 +1188,7 @@ static bool doDump(const AaptOptions& options) { zipFile->uncompress(entry)); assert(uncompressedData); - BinaryResourceParser parser(table, resolver, source, uncompressedData.get(), + BinaryResourceParser parser(table, resolver, source, {}, uncompressedData.get(), entry->getUncompressedLen()); if (!parser.parse()) { return false; @@ -1223,16 +1220,17 @@ int main(int argc, char** argv) { if (!loadAppInfo(options.manifest, &options.appInfo)) { return false; } - } - // Verify we have some common options set. - if (options.appInfo.package.empty()) { - Logger::error() << "no package name specified." << std::endl; - return false; + if (options.appInfo.package.empty()) { + Logger::error() << "no package name specified." << std::endl; + return false; + } } // Every phase needs a resource table. std::shared_ptr<ResourceTable> table = std::make_shared<ResourceTable>(); + + // The package name is empty when in the compile phase. table->setPackage(options.appInfo.package); if (options.appInfo.package == u"android") { table->setPackageId(0x01); diff --git a/tools/aapt2/TableFlattener.cpp b/tools/aapt2/TableFlattener.cpp index 539c48f..b7c04f0 100644 --- a/tools/aapt2/TableFlattener.cpp +++ b/tools/aapt2/TableFlattener.cpp @@ -79,7 +79,7 @@ public: // Write the key. if (!Res_INTERNALID(key.id.id) && !key.id.isValid()) { - assert(key.name.isValid()); + assert(!key.name.entry.empty()); mSymbols->push_back(std::make_pair(ResourceNameRef(key.name), mOut->size() - sizeof(*outMapEntry))); } @@ -284,13 +284,6 @@ bool TableFlattener::flattenValue(BigBuffer* out, const FlatEntry& flatEntry, bool TableFlattener::flatten(BigBuffer* out, const ResourceTable& table) { const size_t beginning = out->size(); - if (table.getPackage().size() == 0) { - Logger::error() - << "ResourceTable has no package name." - << std::endl; - return false; - } - if (table.getPackageId() == ResourceTable::kUnsetPackageId) { Logger::error() << "ResourceTable has no package ID set." diff --git a/tools/aapt2/data/Makefile b/tools/aapt2/data/Makefile index 3387135..91ff5fe 100644 --- a/tools/aapt2/data/Makefile +++ b/tools/aapt2/data/Makefile @@ -50,7 +50,7 @@ $(info PRIVATE_INTERMEDIATE_TABLES = $(PRIVATE_INTERMEDIATE_TABLES)) # returns: out/values-v4.apk: res/values-v4/styles.xml res/values-v4/colors.xml define make-collect-rule $(LOCAL_OUT)/$1.apk: $(filter $(LOCAL_RESOURCE_DIR)/$1/%,$(PRIVATE_RESOURCES)) - $(AAPT) compile --package $(LOCAL_PACKAGE) -o $$@ $$^ + $(AAPT) compile -o $$@ $$^ endef # Collect: out/values-v4.apk <- res/values-v4/styles.xml res/values-v4/colors.xml diff --git a/tools/aapt2/data/lib/Makefile b/tools/aapt2/data/lib/Makefile index 372c225..741be9a 100644 --- a/tools/aapt2/data/lib/Makefile +++ b/tools/aapt2/data/lib/Makefile @@ -48,7 +48,7 @@ $(info PRIVATE_INTERMEDIATE_TABLES = $(PRIVATE_INTERMEDIATE_TABLES)) # returns: out/values-v4.apk: res/values-v4/styles.xml res/values-v4/colors.xml define make-collect-rule $(LOCAL_OUT)/$1.apk: $(filter $(LOCAL_RESOURCE_DIR)/$1/%,$(PRIVATE_RESOURCES)) - $(AAPT) compile --package $(LOCAL_PACKAGE) -o $$@ $$^ + $(AAPT) compile -o $$@ $$^ endef # Collect: out/values-v4.apk <- res/values-v4/styles.xml res/values-v4/colors.xml diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java index 6be5a95..422b2aa 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java @@ -1506,6 +1506,12 @@ public final class BridgeContext extends Context { } @Override + public void sendBroadcast(Intent arg0, String arg1, Bundle arg2) { + // pass + + } + + @Override public void sendBroadcast(Intent intent, String receiverPermission, int appOp) { // pass } @@ -1525,6 +1531,14 @@ public final class BridgeContext extends Context { } @Override + public void sendOrderedBroadcast(Intent arg0, String arg1, + Bundle arg7, BroadcastReceiver arg2, Handler arg3, int arg4, String arg5, + Bundle arg6) { + // pass + + } + + @Override public void sendOrderedBroadcast(Intent intent, String receiverPermission, int appOp, BroadcastReceiver resultReceiver, Handler scheduler, int initialCode, String initialData, Bundle initialExtras) { |
