Merge "Prevent recursion in resumeTopActivityLocked" into lmp-dev
diff --git a/api/current.txt b/api/current.txt
index 7e2b0ed..f3fc017 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -14015,7 +14015,7 @@
ctor public SettingInjectorService(java.lang.String);
method public final android.os.IBinder onBind(android.content.Intent);
method protected abstract boolean onGetEnabled();
- method protected deprecated java.lang.String onGetSummary();
+ method protected abstract deprecated java.lang.String onGetSummary();
method public final void onStart(android.content.Intent, int);
method public final int onStartCommand(android.content.Intent, int, int);
field public static final java.lang.String ACTION_INJECTED_SETTING_CHANGED = "android.location.InjectedSettingChanged";
@@ -21563,7 +21563,7 @@
field public static final int JELLY_BEAN_MR2 = 18; // 0x12
field public static final int KITKAT = 19; // 0x13
field public static final int KITKAT_WATCH = 20; // 0x14
- field public static final int L = 10000; // 0x2710
+ field public static final int L = 21; // 0x15
}
public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -23686,7 +23686,7 @@
field public static final java.lang.String DATE = "date";
field public static final java.lang.String DEFAULT_SORT_ORDER = "date DESC";
field public static final java.lang.String DURATION = "duration";
- field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.call_type_filter";
+ field public static final java.lang.String EXTRA_CALL_TYPE_FILTER = "android.provider.extra.CALL_TYPE_FILTER";
field public static final java.lang.String FEATURES = "features";
field public static final int FEATURES_NONE = 0; // 0x0
field public static final int FEATURES_VIDEO = 1; // 0x1
@@ -24050,11 +24050,11 @@
public static final class ContactsContract.CommonDataKinds.Callable implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
ctor public ContactsContract.CommonDataKinds.Callable();
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
}
protected static abstract interface ContactsContract.CommonDataKinds.CommonColumns implements android.provider.ContactsContract.CommonDataKinds.BaseTypes {
@@ -24065,11 +24065,11 @@
public static final class ContactsContract.CommonDataKinds.Contactables implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
ctor public ContactsContract.CommonDataKinds.Contactables();
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
}
@@ -24077,15 +24077,15 @@
method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
method public static final int getTypeLabelResource(int);
field public static final java.lang.String ADDRESS = "data1";
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/email_v2";
field public static final android.net.Uri CONTENT_LOOKUP_URI;
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/email_v2";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DISPLAY_NAME = "data4";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final int TYPE_HOME = 1; // 0x1
field public static final int TYPE_MOBILE = 4; // 0x4
field public static final int TYPE_OTHER = 3; // 0x3
@@ -24095,10 +24095,10 @@
public static final class ContactsContract.CommonDataKinds.Event implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
method public static int getTypeResource(java.lang.Integer);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_event";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String START_DATE = "data1";
field public static final int TYPE_ANNIVERSARY = 1; // 0x1
field public static final int TYPE_BIRTHDAY = 3; // 0x3
@@ -24106,19 +24106,19 @@
}
public static final class ContactsContract.CommonDataKinds.GroupMembership implements android.provider.ContactsContract.DataColumnsWithJoins {
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/group_membership";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String GROUP_ROW_ID = "data1";
field public static final java.lang.String GROUP_SOURCE_ID = "group_sourceid";
}
public static final class ContactsContract.CommonDataKinds.Identity implements android.provider.ContactsContract.DataColumnsWithJoins {
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/identity";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String IDENTITY = "data1";
field public static final java.lang.String NAMESPACE = "data2";
}
@@ -24128,11 +24128,11 @@
method public static final int getProtocolLabelResource(int);
method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
method public static final int getTypeLabelResource(int);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/im";
field public static final java.lang.String CUSTOM_PROTOCOL = "data6";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String PROTOCOL = "data5";
field public static final int PROTOCOL_AIM = 0; // 0x0
field public static final int PROTOCOL_CUSTOM = -1; // 0xffffffff
@@ -24150,10 +24150,10 @@
}
public static final class ContactsContract.CommonDataKinds.Nickname implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String NAME = "data1";
field public static final int TYPE_DEFAULT = 1; // 0x1
field public static final int TYPE_INITIALS = 5; // 0x5
@@ -24164,22 +24164,22 @@
}
public static final class ContactsContract.CommonDataKinds.Note implements android.provider.ContactsContract.DataColumnsWithJoins {
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/note";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String NOTE = "data1";
}
public static final class ContactsContract.CommonDataKinds.Organization implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
method public static final int getTypeLabelResource(int);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String COMPANY = "data1";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/organization";
field public static final java.lang.String DEPARTMENT = "data5";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String JOB_DESCRIPTION = "data6";
field public static final java.lang.String OFFICE_LOCATION = "data9";
field public static final java.lang.String PHONETIC_NAME = "data8";
@@ -24192,13 +24192,13 @@
public static final class ContactsContract.CommonDataKinds.Phone implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
method public static final int getTypeLabelResource(int);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/phone_v2";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/phone_v2";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String NORMALIZED_NUMBER = "data4";
field public static final java.lang.String NUMBER = "data1";
field public static final java.lang.String SEARCH_DISPLAY_NAME_KEY = "search_display_name";
@@ -24226,10 +24226,10 @@
}
public static final class ContactsContract.CommonDataKinds.Photo implements android.provider.ContactsContract.DataColumnsWithJoins {
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/photo";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String PHOTO = "data15";
field public static final java.lang.String PHOTO_FILE_ID = "data14";
}
@@ -24237,10 +24237,10 @@
public static final class ContactsContract.CommonDataKinds.Relation implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
method public static final int getTypeLabelResource(int);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/relation";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String NAME = "data1";
field public static final int TYPE_ASSISTANT = 1; // 0x1
field public static final int TYPE_BROTHER = 2; // 0x2
@@ -24261,10 +24261,10 @@
public static final class ContactsContract.CommonDataKinds.SipAddress implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
method public static final int getTypeLabelResource(int);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/sip_address";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String SIP_ADDRESS = "data1";
field public static final int TYPE_HOME = 1; // 0x1
field public static final int TYPE_OTHER = 3; // 0x3
@@ -24272,11 +24272,11 @@
}
public static final class ContactsContract.CommonDataKinds.StructuredName implements android.provider.ContactsContract.DataColumnsWithJoins {
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
field public static final java.lang.String DISPLAY_NAME = "data1";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String FAMILY_NAME = "data3";
field public static final java.lang.String FULL_NAME_STYLE = "data10";
field public static final java.lang.String GIVEN_NAME = "data2";
@@ -24291,14 +24291,14 @@
public static final class ContactsContract.CommonDataKinds.StructuredPostal implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
method public static final java.lang.CharSequence getTypeLabel(android.content.res.Resources, int, java.lang.CharSequence);
method public static final int getTypeLabelResource(int);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CITY = "data7";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/postal-address_v2";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/postal-address_v2";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String COUNTRY = "data10";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String FORMATTED_ADDRESS = "data1";
field public static final java.lang.String NEIGHBORHOOD = "data6";
field public static final java.lang.String POBOX = "data5";
@@ -24311,10 +24311,10 @@
}
public static final class ContactsContract.CommonDataKinds.Website implements android.provider.ContactsContract.CommonDataKinds.CommonColumns android.provider.ContactsContract.DataColumnsWithJoins {
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/website";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final int TYPE_BLOG = 2; // 0x2
field public static final int TYPE_FTP = 6; // 0x6
field public static final int TYPE_HOME = 4; // 0x4
@@ -24362,7 +24362,6 @@
method public static deprecated void markAsContacted(android.content.ContentResolver, long);
method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri, boolean);
method public static java.io.InputStream openContactPhotoInputStream(android.content.ContentResolver, android.net.Uri);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final android.net.Uri CONTENT_FILTER_URI;
field public static final android.net.Uri CONTENT_FREQUENT_URI;
field public static final android.net.Uri CONTENT_GROUP_URI;
@@ -24375,8 +24374,9 @@
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String CONTENT_VCARD_TYPE = "text/x-vcard";
field public static final android.net.Uri CONTENT_VCARD_URI;
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
}
public static final class ContactsContract.Contacts.AggregationSuggestions implements android.provider.BaseColumns android.provider.ContactsContract.ContactOptionsColumns android.provider.ContactsContract.ContactStatusColumns android.provider.ContactsContract.ContactsColumns {
@@ -24421,11 +24421,11 @@
public static final class ContactsContract.Data implements android.provider.ContactsContract.DataColumnsWithJoins {
method public static android.net.Uri getContactLookupUri(android.content.ContentResolver, android.net.Uri);
- field public static final java.lang.String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/data";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
- field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX = "android.provider.extra.ADDRESS_BOOK_INDEX";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
+ field public static final java.lang.String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
field public static final java.lang.String VISIBLE_CONTACTS_ONLY = "visible_contacts_only";
}
@@ -24669,7 +24669,7 @@
ctor public ContactsContract.QuickContact();
method public static void showQuickContact(android.content.Context, android.view.View, android.net.Uri, int, java.lang.String[]);
method public static void showQuickContact(android.content.Context, android.graphics.Rect, android.net.Uri, int, java.lang.String[]);
- field public static final java.lang.String ACTION_QUICK_CONTACT = "com.android.contacts.action.QUICK_CONTACT";
+ field public static final java.lang.String ACTION_QUICK_CONTACT = "android.provider.action.QUICK_CONTACT";
field public static final java.lang.String EXTRA_EXCLUDE_MIMES = "android.provider.extra.EXCLUDE_MIMES";
field public static final int MODE_LARGE = 3; // 0x3
field public static final int MODE_MEDIUM = 2; // 0x2
@@ -28870,35 +28870,21 @@
}
public final class SmsManager {
- method public android.net.Uri addMultimediaMessageDraft(android.net.Uri);
- method public android.net.Uri addTextMessageDraft(java.lang.String, java.lang.String);
- method public boolean archiveStoredConversation(long, boolean);
- method public boolean deleteStoredConversation(long);
- method public boolean deleteStoredMessage(android.net.Uri);
method public java.util.ArrayList<java.lang.String> divideMessage(java.lang.String);
- method public void downloadMultimediaMessage(java.lang.String, android.net.Uri, android.content.ContentValues, android.app.PendingIntent);
- method public boolean getAutoPersisting();
+ method public void downloadMultimediaMessage(java.lang.String, android.net.Uri, android.os.Bundle, android.app.PendingIntent);
method public android.os.Bundle getCarrierConfigValues();
method public static android.telephony.SmsManager getDefault();
method public static android.telephony.SmsManager getSmsManagerUsingSubId(long);
method public long getSubId();
- method public android.net.Uri importMultimediaMessage(android.net.Uri, java.lang.String, long, boolean, boolean);
- method public android.net.Uri importTextMessage(java.lang.String, int, java.lang.String, long, boolean, boolean);
method public void injectSmsPdu(byte[], java.lang.String, android.app.PendingIntent);
method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
- method public void sendMultimediaMessage(android.net.Uri, java.lang.String, android.content.ContentValues, android.app.PendingIntent);
+ method public void sendMultimediaMessage(android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
- method public void sendStoredMultimediaMessage(android.net.Uri, android.content.ContentValues, android.app.PendingIntent);
- method public void sendStoredMultipartTextMessage(android.net.Uri, java.lang.String, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
- method public void sendStoredTextMessage(android.net.Uri, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
- method public void setAutoPersisting(boolean);
method public void updateMmsDownloadStatus(int, byte[]);
method public void updateMmsSendStatus(int, boolean);
method public void updateSmsSendStatus(int, boolean);
- method public boolean updateStoredMessageStatus(android.net.Uri, android.content.ContentValues);
- field public static final java.lang.String MESSAGE_STATUS_READ = "read";
- field public static final java.lang.String MESSAGE_STATUS_SEEN = "seen";
+ field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
field public static final java.lang.String MMS_CONFIG_ALIAS_MAX_CHARS = "aliasMaxChars";
field public static final java.lang.String MMS_CONFIG_ALIAS_MIN_CHARS = "aliasMinChars";
@@ -28933,13 +28919,10 @@
field public static final int MMS_ERROR_IO_ERROR = 5; // 0x5
field public static final int MMS_ERROR_UNABLE_CONNECT_MMS = 3; // 0x3
field public static final int MMS_ERROR_UNSPECIFIED = 1; // 0x1
- field public static final java.lang.String MMS_EXTRA_DATA = "data";
field public static final int RESULT_ERROR_GENERIC_FAILURE = 1; // 0x1
field public static final int RESULT_ERROR_NO_SERVICE = 4; // 0x4
field public static final int RESULT_ERROR_NULL_PDU = 3; // 0x3
field public static final int RESULT_ERROR_RADIO_OFF = 2; // 0x2
- field public static final int SMS_TYPE_INCOMING = 0; // 0x0
- field public static final int SMS_TYPE_OUTGOING = 1; // 0x1
field public static final int STATUS_ON_ICC_FREE = 0; // 0x0
field public static final int STATUS_ON_ICC_READ = 1; // 0x1
field public static final int STATUS_ON_ICC_SENT = 5; // 0x5
@@ -34350,7 +34333,7 @@
}
public final class ViewAnimationUtils {
- method public static final android.animation.Animator createCircularReveal(android.view.View, int, int, float, float);
+ method public static android.animation.Animator createCircularReveal(android.view.View, int, int, float, float);
}
public class ViewConfiguration {
diff --git a/core/java/android/hardware/hdmi/HdmiControlManager.java b/core/java/android/hardware/hdmi/HdmiControlManager.java
index 4b5ced9..30f3576 100644
--- a/core/java/android/hardware/hdmi/HdmiControlManager.java
+++ b/core/java/android/hardware/hdmi/HdmiControlManager.java
@@ -55,10 +55,29 @@
public static final int OSD_MESSAGE_ARC_CONNECTED_INVALID_PORT = 1;
/**
+ * Message used by TV to receive volume status from Audio Receiver. It should check volume value
+ * that is retrieved from extra value with the key {@link #EXTRA_MESSAGE_EXTRAM_PARAM1}. If the
+ * value is in range of [0,100], it is current volume of Audio Receiver. And there is another
+ * value, {@link #AVR_VOLUME_MUTED}, which is used to inform volume mute.
+ */
+ public static final int OSD_MESSAGE_AVR_VOLUME_CHANGED = 2;
+
+ /**
* Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the ID of
* the message to display on screen.
*/
public static final String EXTRA_MESSAGE_ID = "android.hardware.hdmi.extra.MESSAGE_ID";
+ /**
+ * Used as an extra field in the intent {@link #ACTION_OSD_MESSAGE}. Contains the extra value
+ * of the message.
+ */
+ public static final String EXTRA_MESSAGE_EXTRAM_PARAM1 =
+ "android.hardware.hdmi.extra.MESSAGE_EXTRA_PARAM1";
+
+ /**
+ * Volume value for mute state.
+ */
+ public static final int AVR_VOLUME_MUTED = 101;
public static final int POWER_STATUS_UNKNOWN = -1;
public static final int POWER_STATUS_ON = 0;
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index b0e0b49..1e0dc53 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -541,7 +541,7 @@
* Intent.</li>
* </ul>
*/
- public static final int L = CUR_DEVELOPMENT;
+ public static final int L = 21;
}
/** The type of build, like "user" or "eng". */
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index 0202f91..5fa1cc9 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -116,8 +116,8 @@
* </pre>
* </p>
*/
- public static final String EXTRA_CALL_TYPE_FILTER
- = "android.provider.extra.call_type_filter";
+ public static final String EXTRA_CALL_TYPE_FILTER =
+ "android.provider.extra.CALL_TYPE_FILTER";
/**
* Content uri used to access call log entries, including voicemail records. You must have
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index 27473e3..18a9eb1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -1125,7 +1125,7 @@
* import android.provider.ContactsContract.Contacts;
*
* Uri uri = Contacts.CONTENT_URI.buildUpon()
- * .appendQueryParameter(Contacts.ADDRESS_BOOK_INDEX_EXTRAS, "true")
+ * .appendQueryParameter(Contacts.EXTRA_ADDRESS_BOOK_INDEX, "true")
* .build();
* Cursor cursor = getContentResolver().query(uri,
* new String[] {Contacts.DISPLAY_NAME},
@@ -1140,21 +1140,24 @@
* </pre>
* </p>
*/
- public static final String ADDRESS_BOOK_INDEX_EXTRAS = "address_book_index_extras";
+ public static final String EXTRA_ADDRESS_BOOK_INDEX =
+ "android.provider.extra.ADDRESS_BOOK_INDEX";
/**
* The array of address book index titles, which are returned in the
* same order as the data in the cursor.
* <p>TYPE: String[]</p>
*/
- public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES = "address_book_index_titles";
+ public static final String EXTRA_ADDRESS_BOOK_INDEX_TITLES =
+ "android.provider.extra.ADDRESS_BOOK_INDEX_TITLES";
/**
* The array of group counts for the corresponding group. Contains the same number
* of elements as the EXTRA_ADDRESS_BOOK_INDEX_TITLES array.
* <p>TYPE: int[]</p>
*/
- public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS = "address_book_index_counts";
+ public static final String EXTRA_ADDRESS_BOOK_INDEX_COUNTS =
+ "android.provider.extra.ADDRESS_BOOK_INDEX_COUNTS";
}
/**
@@ -8111,7 +8114,7 @@
* for the provided {@link Contacts} entry.
*/
public static final String ACTION_QUICK_CONTACT =
- "com.android.contacts.action.QUICK_CONTACT";
+ "android.provider.action.QUICK_CONTACT";
/**
* Extra used to specify pivot dialog location in screen coordinates.
diff --git a/core/java/android/text/Selection.java b/core/java/android/text/Selection.java
index 679e2cc..3222dbf 100644
--- a/core/java/android/text/Selection.java
+++ b/core/java/android/text/Selection.java
@@ -116,7 +116,8 @@
/**
* Move the cursor to the buffer offset physically above the current
- * offset, or return false if the cursor is already on the top line.
+ * offset, to the beginning if it is on the top line but not at the
+ * start, or return false if the cursor is already on the top line.
*/
public static boolean moveUp(Spannable text, Layout layout) {
int start = getSelectionStart(text);
@@ -149,6 +150,9 @@
setSelection(text, move);
return true;
+ } else if (end != 0) {
+ setSelection(text, 0);
+ return true;
}
}
@@ -157,7 +161,9 @@
/**
* Move the cursor to the buffer offset physically below the current
- * offset, or return false if the cursor is already on the bottom line.
+ * offset, to the end of the buffer if it is on the bottom line but
+ * not at the end, or return false if the cursor is already at the
+ * end of the buffer.
*/
public static boolean moveDown(Spannable text, Layout layout) {
int start = getSelectionStart(text);
@@ -190,6 +196,9 @@
setSelection(text, move);
return true;
+ } else if (end != text.length()) {
+ setSelection(text, text.length());
+ return true;
}
}
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 96abf51..9b65232 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -29,6 +29,7 @@
import com.android.internal.view.menu.ActionMenuItemView;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.view.menu.MenuView;
/**
@@ -53,6 +54,7 @@
private boolean mReserveOverflow;
private ActionMenuPresenter mPresenter;
+ private MenuPresenter.Callback mActionMenuPresenterCallback;
private boolean mFormatItems;
private int mFormatItemsWidth;
private int mMinCellSize;
@@ -608,7 +610,8 @@
mMenu = new MenuBuilder(context);
mMenu.setCallback(new MenuBuilderCallback());
mPresenter = new ActionMenuPresenter(context);
- mPresenter.setCallback(new ActionMenuPresenterCallback());
+ mPresenter.setCallback(mActionMenuPresenterCallback != null
+ ? mActionMenuPresenterCallback : new ActionMenuPresenterCallback());
mMenu.addMenuPresenter(mPresenter, mPopupContext);
mPresenter.setMenuView(this);
}
@@ -617,6 +620,14 @@
}
/**
+ * Must be called before the first call to getMenu()
+ * @hide
+ */
+ public void setActionMenuPresenterCallback(MenuPresenter.Callback cb) {
+ mActionMenuPresenterCallback = cb;
+ }
+
+ /**
* Returns the current menu or null if one has not yet been configured.
* @hide Internal use only for action bar integration
*/
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 57b8dcb..033b99a 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -52,12 +52,15 @@
private static final String TAG = "EdgeEffect";
// Time it will take the effect to fully recede in ms
- private static final int RECEDE_TIME = 1000;
+ private static final int RECEDE_TIME = 600;
// Time it will take before a pulled glow begins receding in ms
private static final int PULL_TIME = 167;
- private static final float MAX_ALPHA = 1.f;
+ // Time it will take in ms for a pulled glow to decay to partial strength before release
+ private static final int PULL_DECAY_TIME = 2000;
+
+ private static final float MAX_ALPHA = 0.5f;
private static final float MAX_GLOW_SCALE = 2.f;
@@ -93,12 +96,9 @@
private static final int STATE_RECEDE = 3;
private static final int STATE_PULL_DECAY = 4;
- // How much dragging should effect the height of the glow image.
- // Number determined by user testing.
- private static final int PULL_DISTANCE_GLOW_FACTOR = 7;
- private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f;
+ private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 0.8f;
- private static final int VELOCITY_GLOW_FACTOR = 12;
+ private static final int VELOCITY_GLOW_FACTOR = 6;
private int mState = STATE_IDLE;
@@ -107,7 +107,7 @@
private final Rect mBounds = new Rect();
private final Paint mPaint = new Paint();
private float mRadius;
- private float mBaseGlowHeight;
+ private float mBaseGlowScale;
private float mDisplacement = 0.5f;
private float mTargetDisplacement = 0.5f;
@@ -138,8 +138,12 @@
final float r = width * 0.75f / SIN;
final float y = COS * r;
final float h = r - y;
+ final float or = height * 0.75f / SIN;
+ final float oy = COS * or;
+ final float oh = or - oy;
+
mRadius = r;
- mBaseGlowHeight = h;
+ mBaseGlowScale = h > 0 ? Math.min(oh / h, 1.f) : 1.f;
mBounds.set(mBounds.left, mBounds.top, width, (int) Math.min(height, h));
}
@@ -319,13 +323,14 @@
final float centerX = mBounds.centerX();
final float centerY = mBounds.height() - mRadius;
- canvas.scale(1.f, Math.min(mGlowScaleY, 1.f), centerX, 0);
+ canvas.scale(1.f, Math.min(mGlowScaleY, 1.f) * mBaseGlowScale, centerX, 0);
final float displacement = Math.max(0, Math.min(mDisplacement, 1.f)) - 0.5f;
float translateX = mBounds.width() * displacement / 2;
canvas.clipRect(mBounds);
canvas.translate(translateX, 0);
+ mPaint.setAlpha((int) (0xff * mGlowAlpha));
canvas.drawCircle(centerX, centerY, mRadius, mPaint);
canvas.restoreToCount(count);
@@ -372,7 +377,16 @@
mGlowScaleYFinish = 0.f;
break;
case STATE_PULL:
- // Hold in this state until explicitly released.
+ mState = STATE_PULL_DECAY;
+ mStartTime = AnimationUtils.currentAnimationTimeMillis();
+ mDuration = PULL_DECAY_TIME;
+
+ mGlowAlphaStart = mGlowAlpha;
+ mGlowScaleYStart = mGlowScaleY;
+
+ // After pull, the glow should fade to nothing.
+ mGlowAlphaFinish = 0.f;
+ mGlowScaleYFinish = 0.f;
break;
case STATE_PULL_DECAY:
mState = STATE_RECEDE;
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 3ba03b8..80309f7 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -37,6 +37,7 @@
import android.view.ViewGroup;
import com.android.internal.R;
+import com.android.internal.app.ToolbarActionBar;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuItemImpl;
import com.android.internal.view.menu.MenuPresenter;
@@ -153,6 +154,7 @@
private ToolbarWidgetWrapper mWrapper;
private ActionMenuPresenter mOuterActionMenuPresenter;
private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
+ private MenuPresenter.Callback mActionMenuPresenterCallback;
private boolean mCollapsible;
@@ -825,6 +827,7 @@
mMenuView = new ActionMenuView(getContext());
mMenuView.setPopupTheme(mPopupTheme);
mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener);
+ mMenuView.setActionMenuPresenterCallback(mActionMenuPresenterCallback);
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
mMenuView.setLayoutParams(lp);
@@ -1678,6 +1681,14 @@
}
/**
+ * Must be called before the menu is accessed
+ * @hide
+ */
+ public void setActionMenuPresenterCallback(MenuPresenter.Callback cb) {
+ mActionMenuPresenterCallback = cb;
+ }
+
+ /**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
*/
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 6f1c7ec..3b024e9 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -35,6 +35,7 @@
import android.widget.Toolbar;
import com.android.internal.R;
import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuPresenter;
import com.android.internal.widget.DecorToolbar;
import com.android.internal.widget.ToolbarWidgetWrapper;
@@ -45,6 +46,7 @@
private DecorToolbar mDecorToolbar;
private boolean mToolbarMenuPrepared;
private Window.Callback mWindowCallback;
+ private boolean mMenuCallbackSet;
private CharSequence mHomeDescription;
@@ -453,6 +455,10 @@
}
void populateOptionsMenu() {
+ if (!mMenuCallbackSet) {
+ mToolbar.setActionMenuPresenterCallback(new ActionMenuPresenterCallback());
+ mMenuCallbackSet = true;
+ }
final Menu menu = mToolbar.getMenu();
final MenuBuilder mb = menu instanceof MenuBuilder ? (MenuBuilder) menu : null;
if (mb != null) {
@@ -514,4 +520,31 @@
return result;
}
}
+
+ private final class ActionMenuPresenterCallback implements MenuPresenter.Callback {
+ private boolean mClosingActionMenu;
+
+ @Override
+ public boolean onOpenSubMenu(MenuBuilder subMenu) {
+ if (mWindowCallback != null) {
+ mWindowCallback.onMenuOpened(Window.FEATURE_ACTION_BAR, subMenu);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+ if (mClosingActionMenu) {
+ return;
+ }
+
+ mClosingActionMenu = true;
+ mToolbar.dismissPopupMenus();
+ if (mWindowCallback != null) {
+ mWindowCallback.onPanelClosed(Window.FEATURE_ACTION_BAR, menu);
+ }
+ mClosingActionMenu = false;
+ }
+ }
}
diff --git a/location/java/android/location/SettingInjectorService.java b/location/java/android/location/SettingInjectorService.java
index 98c7864..fcd2cde 100644
--- a/location/java/android/location/SettingInjectorService.java
+++ b/location/java/android/location/SettingInjectorService.java
@@ -196,10 +196,7 @@
* @deprecated not called any more
*/
@Deprecated
- protected String onGetSummary() {
- // Do not delete until no callers have @Override annotations for this method
- return null;
- }
+ protected abstract String onGetSummary();
/**
* Returns the {@link android.preference.Preference#isEnabled()} value. Should not perform
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index af5c13d..ac0ca0a 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -708,7 +708,6 @@
// Send an event to the end of the drag gesture.
sendMotionEvent(event, MotionEvent.ACTION_UP, pointerIdBits, policyFlags);
}
- mCurrentState = STATE_TOUCH_EXPLORING;
} break;
case MotionEvent.ACTION_UP: {
mAms.onTouchInteractionEnd();
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 2ef806f..d05de69 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -440,12 +440,10 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- throw new SecurityException("Permission Denial: can't dump from from pid="
- + Binder.getCallingPid()
- + ", uid=" + Binder.getCallingUid());
- }
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
+ "Permission Denial: can't dump from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
synchronized (mLock) {
int N = mProviders.size();
@@ -4038,4 +4036,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/MmsServiceBroker.java b/services/core/java/com/android/server/MmsServiceBroker.java
index 65ad1ce..b452a38 100644
--- a/services/core/java/com/android/server/MmsServiceBroker.java
+++ b/services/core/java/com/android/server/MmsServiceBroker.java
@@ -193,7 +193,7 @@
private final class BinderService extends IMms.Stub {
@Override
public void sendMessage(long subId, String callingPkg, Uri contentUri,
- String locationUrl, ContentValues configOverrides, PendingIntent sentIntent)
+ String locationUrl, Bundle configOverrides, PendingIntent sentIntent)
throws RemoteException {
mContext.enforceCallingPermission(Manifest.permission.SEND_SMS, "Send MMS message");
if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
@@ -206,7 +206,7 @@
@Override
public void downloadMessage(long subId, String callingPkg, String locationUrl,
- Uri contentUri, ContentValues configOverrides,
+ Uri contentUri, Bundle configOverrides,
PendingIntent downloadedIntent) throws RemoteException {
mContext.enforceCallingPermission(Manifest.permission.RECEIVE_MMS,
"Download MMS message");
@@ -333,7 +333,7 @@
@Override
public void sendStoredMessage(long subId, String callingPkg, Uri messageUri,
- ContentValues configOverrides, PendingIntent sentIntent) throws RemoteException {
+ Bundle configOverrides, PendingIntent sentIntent) throws RemoteException {
mContext.enforceCallingPermission(Manifest.permission.SEND_SMS,
"Send stored MMS message");
if (getAppOpsManager().noteOp(AppOpsManager.OP_SEND_SMS, Binder.getCallingUid(),
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 43fc88d..81c379a 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -459,7 +459,7 @@
final ActivityRecord r = ActivityRecord.forToken(token);
if (r != null) {
final TaskRecord task = r.task;
- if (task.mActivities.contains(r) && mTaskHistory.contains(task)) {
+ if (task != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
if (task.stack != this) Slog.w(TAG,
"Illegal state! task does not point to stack it is in.");
return r;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java
index bb22b4d..c5a6dbd 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecController.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java
@@ -31,8 +31,6 @@
import libcore.util.EmptyArray;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
@@ -102,11 +100,6 @@
// Stores the local CEC devices in the system. Device type is used for key.
private final SparseArray<HdmiCecLocalDevice> mLocalDevices = new SparseArray<>();
- @IoThreadOnly
- private final HdmiLogger mIoThreadLogger = new HdmiLogger(TAG);
- @ServiceThreadOnly
- private final HdmiLogger mServiceThreadLogger = new HdmiLogger(TAG);
-
// Private constructor. Use HdmiCecController.create().
private HdmiCecController(HdmiControlService service) {
mService = service;
@@ -210,9 +203,8 @@
}
final int assignedAddress = logicalAddress;
- mIoThreadLogger.debug(
- String.format("New logical address for device [%d]: [preferred:%d, assigned:%d]",
- deviceType, preferredAddress, assignedAddress));
+ HdmiLogger.debug("New logical address for device [%d]: [preferred:%d, assigned:%d]",
+ deviceType, preferredAddress, assignedAddress);
if (callback != null) {
runOnServiceThread(new Runnable() {
@Override
@@ -449,7 +441,7 @@
allocated.add(address);
}
}
- mIoThreadLogger.debug("[P]:Allocated Address=" + allocated);
+ HdmiLogger.debug("[P]:Allocated Address=" + allocated);
if (callback != null) {
runOnServiceThread(new Runnable() {
@Override
@@ -551,7 +543,7 @@
runOnIoThread(new Runnable() {
@Override
public void run() {
- mIoThreadLogger.debug("[S]:" + cecMessage);
+ HdmiLogger.debug("[S]:" + cecMessage);
byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams());
int i = 0;
int errorCode = Constants.SEND_RESULT_SUCCESS;
@@ -586,7 +578,7 @@
private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) {
assertRunOnServiceThread();
HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body);
- mServiceThreadLogger.debug("[R]:" + command);
+ HdmiLogger.debug("[R]:" + command);
onReceiveCommand(command);
}
@@ -596,8 +588,7 @@
@ServiceThreadOnly
private void handleHotplug(int port, boolean connected) {
assertRunOnServiceThread();
- mServiceThreadLogger.debug(
- "Hotplug event:[port:" + port + " , connected:" + connected + "]");
+ HdmiLogger.debug("Hotplug event:[port:%d, connected:%b]", port, connected);
mService.onHotplug(port, connected);
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
index 85f5be2..b2300a6 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecFeatureAction.java
@@ -43,9 +43,6 @@
*/
abstract class HdmiCecFeatureAction {
private static final String TAG = "HdmiCecFeatureAction";
- // As all actions run in the same thread (service thread), it's fine to have single logger.
- // TODO: create global logger for each threads and use them.
- protected static final HdmiLogger DLOGGER = new HdmiLogger(TAG);
// Timer handler message used for timeout event
protected static final int MSG_TIMEOUT = 100;
@@ -264,10 +261,7 @@
}
protected final void sendUserControlPressedAndReleased(int targetAddress, int uiCommand) {
- sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(
- getSourceAddress(), targetAddress, uiCommand));
- sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
- getSourceAddress(), targetAddress));
+ mSource.sendUserControlPressedAndReleased(targetAddress, uiCommand);
}
protected final void addOnFinishedCallback(HdmiCecFeatureAction action, Runnable runnable) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index bc6a299..04e38dc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -810,6 +810,13 @@
Slog.w(TAG, "sendKeyEvent not implemented");
}
+ void sendUserControlPressedAndReleased(int targetAddress, int cecKeycode) {
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildUserControlPressed(
+ mAddress, targetAddress, cecKeycode));
+ mService.sendCecCommand(HdmiCecMessageBuilder.buildUserControlReleased(
+ mAddress, targetAddress));
+ }
+
/**
* Dump internal status of HdmiCecLocalDevice object.
*/
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 7ae2198..5994c76 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -120,8 +120,6 @@
// other CEC devices since they might not have logical address.
private final ArraySet<Integer> mCecSwitches = new ArraySet<Integer>();
- private final HdmiLogger mSafeLogger = new HdmiLogger(TAG);
-
HdmiCecLocalDeviceTv(HdmiControlService service) {
super(service, HdmiDeviceInfo.DEVICE_TV);
mPrevPortId = Constants.INVALID_PORT_ID;
@@ -700,8 +698,7 @@
// # Seq 25
void setSystemAudioMode(boolean on, boolean updateSetting) {
- mSafeLogger.debug(String.format("System Audio Mode change[old:%b new:%b]",
- mSystemAudioActivated, on));
+ HdmiLogger.debug("System Audio Mode change[old:%b new:%b]", mSystemAudioActivated, on);
if (updateSetting) {
mService.writeBooleanSetting(Global.HDMI_SYSTEM_AUDIO_ENABLED, on);
@@ -832,6 +829,8 @@
AudioManager.STREAM_MUSIC);
mService.setAudioStatus(mute,
VolumeControlAction.scaleToCustomVolume(volume, maxVolume));
+ displayOsd(HdmiControlManager.OSD_MESSAGE_AVR_VOLUME_CHANGED,
+ mute ? HdmiControlManager.AVR_VOLUME_MUTED : volume);
}
}
@@ -855,12 +854,13 @@
}
}
- // Remove existing volume action.
- removeAction(VolumeControlAction.class);
-
- HdmiDeviceInfo avr = getAvrDeviceInfo();
- addAndStartAction(VolumeControlAction.ofVolumeChange(this, avr.getLogicalAddress(),
- cecVolume, delta > 0));
+ List<VolumeControlAction> actions = getActions(VolumeControlAction.class);
+ if (actions.isEmpty()) {
+ addAndStartAction(new VolumeControlAction(this,
+ getAvrDeviceInfo().getLogicalAddress(), delta > 0));
+ } else {
+ actions.get(0).handleVolumeChange(delta > 0);
+ }
}
@ServiceThreadOnly
@@ -872,8 +872,9 @@
// Remove existing volume action.
removeAction(VolumeControlAction.class);
- HdmiDeviceInfo avr = getAvrDeviceInfo();
- addAndStartAction(VolumeControlAction.ofMute(this, avr.getLogicalAddress(), mute));
+ sendUserControlPressedAndReleased(getAvrDeviceInfo().getLogicalAddress(),
+ mute ? HdmiCecKeycode.CEC_KEYCODE_MUTE_FUNCTION :
+ HdmiCecKeycode.CEC_KEYCODE_RESTORE_VOLUME_FUNCTION);
}
@Override
@@ -935,7 +936,7 @@
protected boolean handleSetSystemAudioMode(HdmiCecMessage message) {
assertRunOnServiceThread();
if (!isMessageForSystemAudio(message)) {
- mSafeLogger.warning("Invalid <Set System Audio Mode> message:" + message);
+ HdmiLogger.warning("Invalid <Set System Audio Mode> message:" + message);
return false;
}
SystemAudioActionFromAvr action = new SystemAudioActionFromAvr(this,
@@ -949,7 +950,7 @@
protected boolean handleSystemAudioModeStatus(HdmiCecMessage message) {
assertRunOnServiceThread();
if (!isMessageForSystemAudio(message)) {
- mSafeLogger.warning("Invalid <System Audio Mode Status> message:" + message);
+ HdmiLogger.warning("Invalid <System Audio Mode Status> message:" + message);
return false;
}
setSystemAudioMode(HdmiUtils.parseCommandParamSystemAudioStatus(message), true);
@@ -1445,6 +1446,12 @@
mService.displayOsd(messageId);
}
+ @ServiceThreadOnly
+ void displayOsd(int messageId, int extra) {
+ assertRunOnServiceThread();
+ mService.displayOsd(messageId, extra);
+ }
+
// Seq #54 and #55
@ServiceThreadOnly
void startOneTouchRecord(int recorderAddress, byte[] recordSource) {
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 8b345cf..0b3d9fb 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -51,7 +51,6 @@
}
final SparseArray<ValidationInfo> mValidationInfo = new SparseArray<>();
- private final HdmiLogger mSpamSafeLogger = new HdmiLogger(TAG);
public HdmiCecMessageValidator(HdmiControlService service) {
mService = service;
@@ -183,32 +182,32 @@
int opcode = message.getOpcode();
ValidationInfo info = mValidationInfo.get(opcode);
if (info == null) {
- mSpamSafeLogger.warning("No validation information for the message: " + message);
+ HdmiLogger.warning("No validation information for the message: " + message);
return true;
}
// Check the source field.
if (message.getSource() == Constants.ADDR_UNREGISTERED &&
(info.addressType & SRC_UNREGISTERED) == 0) {
- mSpamSafeLogger.warning("Unexpected source: " + message);
+ HdmiLogger.warning("Unexpected source: " + message);
return false;
}
// Check the destination field.
if (message.getDestination() == Constants.ADDR_BROADCAST) {
if ((info.addressType & DEST_BROADCAST) == 0) {
- mSpamSafeLogger.warning("Unexpected broadcast message: " + message);
+ HdmiLogger.warning("Unexpected broadcast message: " + message);
return false;
}
} else { // Direct addressing.
if ((info.addressType & DEST_DIRECT) == 0) {
- mSpamSafeLogger.warning("Unexpected direct message: " + message);
+ HdmiLogger.warning("Unexpected direct message: " + message);
return false;
}
}
// Check the parameter type.
if (!info.parameterValidator.isValid(message.getParams())) {
- mSpamSafeLogger.warning("Unexpected parameters: " + message);
+ HdmiLogger.warning("Unexpected parameters: " + message);
return false;
}
return true;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 9314cf8..38c6fb3 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -166,8 +166,6 @@
// Type of logical devices hosted in the system. Stored in the unmodifiable list.
private final List<Integer> mLocalDevices;
- private final HdmiLogger mSpamSafeLogger = new HdmiLogger(TAG);
-
// List of records for hotplug event listener to handle the the caller killed in action.
@GuardedBy("mLock")
private final ArrayList<HotplugEventListenerRecord> mHotplugEventListenerRecords =
@@ -656,7 +654,7 @@
if (mMessageValidator.isValid(command)) {
mCecController.sendCommand(command, callback);
} else {
- mSpamSafeLogger.error("Invalid message type:" + command);
+ HdmiLogger.error("Invalid message type:" + command);
if (callback != null) {
callback.onSendCompleted(Constants.SEND_RESULT_FAILURE);
}
@@ -705,7 +703,7 @@
}
if (message.getDestination() != Constants.ADDR_BROADCAST) {
- mSpamSafeLogger.warning("Unhandled cec command:" + message);
+ HdmiLogger.warning("Unhandled cec command:" + message);
}
return false;
}
@@ -794,7 +792,6 @@
// FLAG_HDMI_SYSTEM_AUDIO_VOLUME prevents audio manager from announcing
// volume change notification back to hdmi control service.
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume,
- AudioManager.FLAG_SHOW_UI |
AudioManager.FLAG_HDMI_SYSTEM_AUDIO_VOLUME);
}
}
@@ -2033,4 +2030,14 @@
getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
HdmiControlService.PERMISSION);
}
+
+ @ServiceThreadOnly
+ void displayOsd(int messageId, int extra) {
+ assertRunOnServiceThread();
+ Intent intent = new Intent(HdmiControlManager.ACTION_OSD_MESSAGE);
+ intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_ID, messageId);
+ intent.putExtra(HdmiControlManager.EXTRA_MESSAGE_EXTRAM_PARAM1, extra);
+ getContext().sendBroadcastAsUser(intent, UserHandle.ALL,
+ HdmiControlService.PERMISSION);
+ }
}
diff --git a/services/core/java/com/android/server/hdmi/HdmiLogger.java b/services/core/java/com/android/server/hdmi/HdmiLogger.java
index c7add75..2562ffc 100644
--- a/services/core/java/com/android/server/hdmi/HdmiLogger.java
+++ b/services/core/java/com/android/server/hdmi/HdmiLogger.java
@@ -26,44 +26,83 @@
/**
* A logger that prevents spammy log. For the same log message, it logs once every 20seconds.
* This class is not thread-safe.
+ * <p>
+ * For convenience, use single character prefix for all messages.
+ * Here are common acronyms
+ * <ul>
+ * <li>[T]: Timout
+ * <li>[R]: Received message
+ * <li>[S]: Sent message
+ * <li>[P]: Device polling result
+ * </ul>
*/
final class HdmiLogger {
+ private static final String TAG = "HDMI";
// Logging duration for same error message.
private static final long ERROR_LOG_DURATTION_MILLIS = 20 * 1000; // 20s
private static final boolean DEBUG = false;
+ private static final ThreadLocal<HdmiLogger> sLogger = new ThreadLocal<>();
+
// Key (String): log message.
// Value (Pair(Long, Integer)): a pair of last log time millis and the number of logMessage.
// Cache for warning.
private final HashMap<String, Pair<Long, Integer>> mWarningTimingCache = new HashMap<>();
// Cache for error.
private final HashMap<String, Pair<Long, Integer>> mErrorTimingCache = new HashMap<>();
- private final String mTag;
- HdmiLogger(String tag) {
- mTag = "HDMI:" + tag;
+ private HdmiLogger() {
}
- void warning(String logMessage) {
+ static final void warning(String logMessage, Object... objs) {
+ getLogger().warningInternal(toLogString(logMessage, objs));
+ }
+
+ private void warningInternal(String logMessage) {
String log = updateLog(mWarningTimingCache, logMessage);
if (!log.isEmpty()) {
- Slog.w(mTag, log);
+ Slog.w(TAG, log);
}
}
- void error(String logMessage) {
+ static final void error(String logMessage, Object... objs) {
+ getLogger().errorInternal(toLogString(logMessage, objs));
+ }
+
+ private void errorInternal(String logMessage) {
String log = updateLog(mErrorTimingCache, logMessage);
if (!log.isEmpty()) {
- Slog.e(mTag, log);
+ Slog.e(TAG, log);
}
}
- void debug(String logMessage) {
+ static final void debug(String logMessage, Object... objs) {
+ getLogger().debugInternal(toLogString(logMessage, objs));
+ }
+
+ private void debugInternal(String logMessage) {
if (!DEBUG) {
return;
}
- Slog.d(mTag, logMessage);
+ Slog.d(TAG, logMessage);
+ }
+
+ private static final String toLogString(String logMessage, Object[] objs) {
+ if (objs.length > 0) {
+ return String.format(logMessage, objs);
+ } else {
+ return logMessage;
+ }
+ }
+
+ private static HdmiLogger getLogger() {
+ HdmiLogger logger = sLogger.get();
+ if (logger == null) {
+ logger = new HdmiLogger();
+ sLogger.set(logger);
+ }
+ return logger;
}
private static String updateLog(HashMap<String, Pair<Long, Integer>> cache, String logMessage) {
diff --git a/services/core/java/com/android/server/hdmi/RequestArcAction.java b/services/core/java/com/android/server/hdmi/RequestArcAction.java
index 17c2d6c..3fb450f 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcAction.java
@@ -85,6 +85,7 @@
if (mState != state || state != STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE) {
return;
}
+ HdmiLogger.debug("[T]RequestArcAction.");
disableArcTransmission();
finish();
}
diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
index f25363d..d9e1f24 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java
@@ -35,15 +35,15 @@
@Override
boolean start() {
+ mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
+
HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation(
getSourceAddress(), mAvrAddress);
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == Constants.SEND_RESULT_SUCCESS) {
- mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
- addTimer(mState, HdmiConfig.TIMEOUT_MS);
- } else {
+ if (error != Constants.SEND_RESULT_SUCCESS) {
// If failed to send <Request ARC Initiation>, start "Disabled"
// ARC transmission action.
disableArcTransmission();
diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
index 1491c72..f5a0115 100644
--- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
+++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java
@@ -35,15 +35,15 @@
@Override
boolean start() {
+ mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
+
HdmiCecMessage command =
HdmiCecMessageBuilder.buildRequestArcTermination(getSourceAddress(), mAvrAddress);
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == Constants.SEND_RESULT_SUCCESS) {
- mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE;
- addTimer(mState, HdmiConfig.TIMEOUT_MS);
- } else {
+ if (error != Constants.SEND_RESULT_SUCCESS) {
// If failed to send <Request ARC Termination>, start "Disabled" ARC
// transmission action.
disableArcTransmission();
diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
index 30519f3..bffa854 100644
--- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
+++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java
@@ -53,6 +53,18 @@
@Override
boolean start() {
if (mEnabled) {
+ // Enable ARC status immediately after sending <Report Arc Initiated>.
+ // If AVR responds with <Feature Abort>, disable ARC status again.
+ // This is different from spec that says that turns ARC status to
+ // "Enabled" if <Report ARC Initiated> is acknowledged and no
+ // <Feature Abort> is received.
+ // But implemented this way to save the time having to wait for
+ // <Feature Abort>.
+ setArcStatus(true);
+ // If succeeds to send <Report ARC Initiated>, wait general timeout
+ // to check whether there is no <Feature Abort> for <Report ARC Initiated>.
+ mState = STATE_WAITING_TIMEOUT;
+ addTimer(mState, HdmiConfig.TIMEOUT_MS);
sendReportArcInitiated();
} else {
setArcStatus(false);
@@ -67,23 +79,11 @@
sendCommand(command, new HdmiControlService.SendMessageCallback() {
@Override
public void onSendCompleted(int error) {
- if (error == Constants.SEND_RESULT_SUCCESS) {
- // Enable ARC status immediately after sending <Report Arc Initiated>.
- // If AVR responds with <Feature Abort>, disable ARC status again.
- // This is different from spec that says that turns ARC status to
- // "Enabled" if <Report ARC Initiated> is acknowledged and no
- // <Feature Abort> is received.
- // But implemented this way to save the time having to wait for
- // <Feature Abort>.
- setArcStatus(true);
- // If succeeds to send <Report ARC Initiated>, wait general timeout
- // to check whether there is no <Feature Abort> for <Report ARC Initiated>.
- mState = STATE_WAITING_TIMEOUT;
- addTimer(mState, HdmiConfig.TIMEOUT_MS);
- } else {
+ if (error != Constants.SEND_RESULT_SUCCESS) {
// If fails to send <Report ARC Initiated>, disable ARC and
// send <Report ARC Terminated> directly.
setArcStatus(false);
+ HdmiLogger.debug("Failed to send <Report Arc Initiated>.");
finish();
}
}
@@ -112,6 +112,7 @@
if (opcode == Constants.MESSAGE_FEATURE_ABORT) {
int originalOpcode = cmd.getParams()[0] & 0xFF;
if (originalOpcode == Constants.MESSAGE_REPORT_ARC_INITIATED) {
+ HdmiLogger.debug("Feature aborted for <Report Arc Initiated>");
setArcStatus(false);
finish();
return true;
diff --git a/services/core/java/com/android/server/hdmi/SystemAudioAction.java b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
index d15ffb0..0871194 100644
--- a/services/core/java/com/android/server/hdmi/SystemAudioAction.java
+++ b/services/core/java/com/android/server/hdmi/SystemAudioAction.java
@@ -98,7 +98,7 @@
@Override
public void onSendCompleted(int error) {
if (error != Constants.SEND_RESULT_SUCCESS) {
- DLOGGER.debug("Failed to send <System Audio Mode Request>:" + error);
+ HdmiLogger.debug("Failed to send <System Audio Mode Request>:" + error);
setSystemAudioMode(false);
finishWithCallback(HdmiControlManager.RESULT_COMMUNICATION_FAILED);
}
@@ -111,7 +111,7 @@
private void handleSendSystemAudioModeRequestTimeout() {
if (!mTargetAudioStatus // Don't retry for Off case.
|| mSendRetryCount++ >= MAX_SEND_RETRY_COUNT) {
- DLOGGER.debug("[T]:wait for <Set System Audio Mode>.");
+ HdmiLogger.debug("[T]:wait for <Set System Audio Mode>.");
setSystemAudioMode(false);
finishWithCallback(HdmiControlManager.RESULT_TIMEOUT);
return;
@@ -130,7 +130,7 @@
if (cmd.getOpcode() == Constants.MESSAGE_FEATURE_ABORT
&& (cmd.getParams()[0] & 0xFF)
== Constants.MESSAGE_SYSTEM_AUDIO_MODE_REQUEST) {
- DLOGGER.debug("Failed to start system audio mode request.");
+ HdmiLogger.debug("Failed to start system audio mode request.");
setSystemAudioMode(false);
finishWithCallback(HdmiControlManager.RESULT_EXCEPTION);
return true;
@@ -145,7 +145,7 @@
startAudioStatusAction();
return true;
} else {
- DLOGGER.debug("Unexpected system audio mode request:" + receivedStatus);
+ HdmiLogger.debug("Unexpected system audio mode request:" + receivedStatus);
// Unexpected response, consider the request is newly initiated by AVR.
// To return 'false' will initiate new SystemAudioActionFromAvr by the control
// service.
diff --git a/services/core/java/com/android/server/hdmi/VolumeControlAction.java b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
index ddc267a..4338fc7 100644
--- a/services/core/java/com/android/server/hdmi/VolumeControlAction.java
+++ b/services/core/java/com/android/server/hdmi/VolumeControlAction.java
@@ -17,66 +17,35 @@
package com.android.server.hdmi;
import static com.android.server.hdmi.Constants.IRT_MS;
+import static com.android.server.hdmi.Constants.MESSAGE_FEATURE_ABORT;
+import static com.android.server.hdmi.Constants.MESSAGE_REPORT_AUDIO_STATUS;
+import static com.android.server.hdmi.Constants.MESSAGE_USER_CONTROL_PRESSED;
-import com.android.internal.util.Preconditions;
+import android.media.AudioManager;
/**
* Feature action that transmits volume change to Audio Receiver.
* <p>
- * This action is created when a user pressed volume up/down. However, Since Android only provides a
- * listener for delta of some volume change, we will set a target volume, and check reported volume
- * from Audio Receiver(AVR). If TV receives no <Report Audio Status> from AVR, this action
- * will be finished in {@link #IRT_MS} * {@link #VOLUME_CHANGE_TIMEOUT_MAX_COUNT} (ms).
+ * This action is created when a user pressed volume up/down. However, Android only provides a
+ * listener for delta of some volume change instead of individual key event. Also it's hard to know
+ * Audio Receiver's number of volume steps for a single volume control key. Because of this, it
+ * sends key-down event until IRT timeout happens, and it will send key-up event if no additional
+ * volume change happens; otherwise, it will send again key-down as press and hold feature does.
*/
final class VolumeControlAction extends HdmiCecFeatureAction {
private static final String TAG = "VolumeControlAction";
- private static final int VOLUME_MUTE = 101;
- private static final int VOLUME_RESTORE = 102;
+ // State that wait for next volume press.
+ private static final int STATE_WAIT_FOR_NEXT_VOLUME_PRESS = 1;
private static final int MAX_VOLUME = 100;
- private static final int MIN_VOLUME = 0;
- // State where to wait for <Report Audio Status>
- private static final int STATE_WAIT_FOR_REPORT_VOLUME_STATUS = 1;
-
- // Maximum count of time out used to finish volume action.
- private static final int VOLUME_CHANGE_TIMEOUT_MAX_COUNT = 2;
+ private static final int UNKNOWN_AVR_VOLUME = -1;
private final int mAvrAddress;
- private final int mTargetVolume;
- private final boolean mIsVolumeUp;
- private int mTimeoutCount;
-
- /**
- * Create a {@link VolumeControlAction} for mute/restore change
- *
- * @param source source device sending volume change
- * @param avrAddress address of audio receiver
- * @param mute whether to mute sound or not. {@code true} for mute on; {@code false} for mute
- * off, i.e restore volume
- * @return newly created {@link VolumeControlAction}
- */
- public static VolumeControlAction ofMute(HdmiCecLocalDevice source, int avrAddress,
- boolean mute) {
- return new VolumeControlAction(source, avrAddress, mute ? VOLUME_MUTE : VOLUME_RESTORE,
- false);
- }
-
- /**
- * Create a {@link VolumeControlAction} for volume up/down change
- *
- * @param source source device sending volume change
- * @param avrAddress address of audio receiver
- * @param targetVolume target volume to be set to AVR. It should be in range of [0-100]
- * @param isVolumeUp whether to volume up or not. {@code true} for volume up; {@code false} for
- * volume down
- * @return newly created {@link VolumeControlAction}
- */
- public static VolumeControlAction ofVolumeChange(HdmiCecLocalDevice source, int avrAddress,
- int targetVolume, boolean isVolumeUp) {
- Preconditions.checkArgumentInRange(targetVolume, MIN_VOLUME, MAX_VOLUME, "volume");
- return new VolumeControlAction(source, avrAddress, targetVolume, isVolumeUp);
- }
+ private boolean mIsVolumeUp;
+ private long mLastKeyUpdateTime;
+ private int mLastAvrVolume;
+ private boolean mSentKeyPressed;
/**
* Scale a custom volume value to cec volume scale.
@@ -94,123 +63,141 @@
*
* @param cecVolume volume value in cec volume scale. It should be in a range of [0-100]
* @param scale scale of custom volume (max volume)
- * @return a volume value scaled to custom volume range
+ * @return a volume scaled to custom volume range
*/
public static int scaleToCustomVolume(int cecVolume, int scale) {
return (cecVolume * scale) / MAX_VOLUME;
}
- private VolumeControlAction(HdmiCecLocalDevice source, int avrAddress, int targetVolume,
- boolean isVolumeUp) {
+ VolumeControlAction(HdmiCecLocalDevice source, int avrAddress, boolean isVolumeUp) {
super(source);
-
mAvrAddress = avrAddress;
- mTargetVolume = targetVolume;
mIsVolumeUp = isVolumeUp;
+ mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+ mSentKeyPressed = false;
+
+ updateLastKeyUpdateTime();
+ }
+
+ private void updateLastKeyUpdateTime() {
+ mLastKeyUpdateTime = System.currentTimeMillis();
}
@Override
boolean start() {
- if (isForMute()) {
- sendMuteChange(mTargetVolume == VOLUME_MUTE);
- finish();
- return true;
- }
-
- startVolumeChange();
+ mState = STATE_WAIT_FOR_NEXT_VOLUME_PRESS;
+ sendVolumeKeyPressed();
+ resetTimer();
return true;
}
-
- private boolean isForMute() {
- return mTargetVolume == VOLUME_MUTE || mTargetVolume == VOLUME_RESTORE;
- }
-
- private void startVolumeChange() {
- mTimeoutCount = 0;
- sendVolumeChange(mIsVolumeUp);
- mState = STATE_WAIT_FOR_REPORT_VOLUME_STATUS;
- addTimer(mState, IRT_MS);
- }
-
- private void sendVolumeChange(boolean up) {
+ private void sendVolumeKeyPressed() {
sendCommand(HdmiCecMessageBuilder.buildUserControlPressed(getSourceAddress(), mAvrAddress,
- up ? HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP
+ mIsVolumeUp ? HdmiCecKeycode.CEC_KEYCODE_VOLUME_UP
: HdmiCecKeycode.CEC_KEYCODE_VOLUME_DOWN));
+ mSentKeyPressed = true;
}
- private void sendMuteChange(boolean mute) {
- sendUserControlPressedAndReleased(mAvrAddress,
- mute ? HdmiCecKeycode.CEC_KEYCODE_MUTE_FUNCTION :
- HdmiCecKeycode.CEC_KEYCODE_RESTORE_VOLUME_FUNCTION);
+ private void resetTimer() {
+ mActionTimer.clearTimerMessage();
+ addTimer(STATE_WAIT_FOR_NEXT_VOLUME_PRESS, IRT_MS);
+ }
+
+ void handleVolumeChange(boolean isVolumeUp) {
+ if (mIsVolumeUp != isVolumeUp) {
+ HdmiLogger.debug("Volume Key Status Changed[old:%b new:%b]", mIsVolumeUp, isVolumeUp);
+ sendVolumeKeyReleased();
+ mIsVolumeUp = isVolumeUp;
+ }
+ updateLastKeyUpdateTime();
+ }
+
+ private void sendVolumeKeyReleased() {
+ sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
+ getSourceAddress(), mAvrAddress));
+ mSentKeyPressed = false;
}
@Override
boolean processCommand(HdmiCecMessage cmd) {
- if (mState != STATE_WAIT_FOR_REPORT_VOLUME_STATUS) {
+ if (mState != STATE_WAIT_FOR_NEXT_VOLUME_PRESS || cmd.getSource() != mAvrAddress) {
return false;
}
switch (cmd.getOpcode()) {
- case Constants.MESSAGE_REPORT_AUDIO_STATUS:
- handleReportAudioStatus(cmd);
- return true;
- case Constants.MESSAGE_FEATURE_ABORT:
- int originalOpcode = cmd.getParams()[0] & 0xFF;
- if (originalOpcode == Constants.MESSAGE_USER_CONTROL_PRESSED
- || originalOpcode == Constants.MESSAGE_USER_CONTROL_RELEASED) {
- // TODO: handle feature abort.
- finish();
- return true;
- }
- default: // fall through
+ case MESSAGE_REPORT_AUDIO_STATUS:
+ return handleReportAudioStatus(cmd);
+ case MESSAGE_FEATURE_ABORT:
+ return handleFeatureAbort(cmd);
+ default:
return false;
}
}
- private void handleReportAudioStatus(HdmiCecMessage cmd) {
- byte[] params = cmd.getParams();
+ private boolean handleReportAudioStatus(HdmiCecMessage cmd) {
+ byte params[] = cmd.getParams();
+ boolean mute = (params[0] & 0x80) == 0x80;
int volume = params[0] & 0x7F;
- // Update volume with new value.
- // Note that it will affect system volume change.
- tv().setAudioStatus(false, volume);
- if (mIsVolumeUp) {
- if (mTargetVolume <= volume) {
- finishWithVolumeChangeRelease();
- return;
- }
- } else {
- if (mTargetVolume >= volume) {
- finishWithVolumeChangeRelease();
- return;
- }
+ mLastAvrVolume = volume;
+ if (shouldUpdateAudioVolume(mute)) {
+ HdmiLogger.debug("Force volume change[mute:%b, volume=%d]", mute, volume);
+ tv().setAudioStatus(mute, volume);
}
-
- // Clear action status and send another volume change command.
- clear();
- startVolumeChange();
+ return true;
}
- private void finishWithVolumeChangeRelease() {
- sendCommand(HdmiCecMessageBuilder.buildUserControlReleased(
- getSourceAddress(), mAvrAddress));
- finish();
+ private boolean shouldUpdateAudioVolume(boolean mute) {
+ // Do nothing if in mute.
+ if (mute) {
+ return true;
+ }
+
+ // Update audio status if current volume position is edge of volume bar,
+ // i.e max or min volume.
+ AudioManager audioManager = tv().getService().getAudioManager();
+ int currentVolume = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
+ if (mIsVolumeUp) {
+ int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
+ return currentVolume == maxVolume;
+ } else {
+ return currentVolume == 0;
+ }
+ }
+
+ private boolean handleFeatureAbort(HdmiCecMessage cmd) {
+ int originalOpcode = cmd.getParams()[0] & 0xFF;
+ // Since it sends <User Control Released> only when it finishes this action,
+ // it takes care of <User Control Pressed> only here.
+ if (originalOpcode == MESSAGE_USER_CONTROL_PRESSED) {
+ finish();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ protected void clear() {
+ super.clear();
+ if (mSentKeyPressed) {
+ sendVolumeKeyReleased();
+ }
+ if (mLastAvrVolume != UNKNOWN_AVR_VOLUME) {
+ tv().setAudioStatus(false, mLastAvrVolume);
+ mLastAvrVolume = UNKNOWN_AVR_VOLUME;
+ }
}
@Override
void handleTimerEvent(int state) {
- if (mState != STATE_WAIT_FOR_REPORT_VOLUME_STATUS) {
+ if (state != STATE_WAIT_FOR_NEXT_VOLUME_PRESS) {
return;
}
- // If no report volume action after IRT * VOLUME_CHANGE_TIMEOUT_MAX_COUNT just stop volume
- // action.
- if (++mTimeoutCount == VOLUME_CHANGE_TIMEOUT_MAX_COUNT) {
- finishWithVolumeChangeRelease();
- return;
+ if (System.currentTimeMillis() - mLastKeyUpdateTime >= IRT_MS) {
+ finish();
+ } else {
+ sendVolumeKeyPressed();
+ resetTimer();
}
-
- sendVolumeChange(mIsVolumeUp);
- addTimer(mState, IRT_MS);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 846efc0..f0f249e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -312,6 +312,12 @@
final PackageHandler mHandler;
+ /**
+ * Messages for {@link #mHandler} that need to wait for system ready before
+ * being dispatched.
+ */
+ private ArrayList<Message> mPostSystemReadyMessages;
+
final int mSdkVersion = Build.VERSION.SDK_INT;
final Context mContext;
@@ -446,9 +452,9 @@
/** Token for keys in mPendingVerification. */
private int mPendingVerificationToken = 0;
- boolean mSystemReady;
- boolean mSafeMode;
- boolean mHasSystemUidErrors;
+ volatile boolean mSystemReady;
+ volatile boolean mSafeMode;
+ volatile boolean mHasSystemUidErrors;
ApplicationInfo mAndroidApplication;
final ActivityInfo mResolveActivity = new ActivityInfo();
@@ -7685,16 +7691,18 @@
}
void schedulePackageCleaning(String packageName, int userId, boolean andCode) {
- if (false) {
- RuntimeException here = new RuntimeException("here");
- here.fillInStackTrace();
- Slog.d(TAG, "Schedule cleaning " + packageName + " user=" + userId
- + " andCode=" + andCode, here);
+ final Message msg = mHandler.obtainMessage(START_CLEANING_PACKAGE,
+ userId, andCode ? 1 : 0, packageName);
+ if (mSystemReady) {
+ msg.sendToTarget();
+ } else {
+ if (mPostSystemReadyMessages == null) {
+ mPostSystemReadyMessages = new ArrayList<>();
+ }
+ mPostSystemReadyMessages.add(msg);
}
- mHandler.sendMessage(mHandler.obtainMessage(START_CLEANING_PACKAGE,
- userId, andCode ? 1 : 0, packageName));
}
-
+
void startCleaningPackages() {
// reader
synchronized (mPackages) {
@@ -12038,6 +12046,14 @@
}
}
sUserManager.systemReady();
+
+ // Kick off any messages waiting for system ready
+ if (mPostSystemReadyMessages != null) {
+ for (Message msg : mPostSystemReadyMessages) {
+ msg.sendToTarget();
+ }
+ mPostSystemReadyMessages = null;
+ }
}
@Override
@@ -13035,6 +13051,9 @@
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
while (psit.hasNext()) {
PackageSetting ps = psit.next();
+ if (ps.pkg == null) {
+ continue;
+ }
final String packageName = ps.pkg.packageName;
// Skip over if system app
if ((ps.pkgFlags & ApplicationInfo.FLAG_SYSTEM) != 0) {
diff --git a/telecomm/java/android/telecomm/TelecommManager.java b/telecomm/java/android/telecomm/TelecommManager.java
index 071b719..5486be1 100644
--- a/telecomm/java/android/telecomm/TelecommManager.java
+++ b/telecomm/java/android/telecomm/TelecommManager.java
@@ -287,16 +287,38 @@
}
/**
+ * Return the {@link PhoneAccount} which is the user-chosen default for making outgoing phone
+ * calls. This {@code PhoneAccount} will always be a member of the list which is returned from
+ * calling {@link #getEnabledPhoneAccounts()}
+ *
+ * Apps must be prepared for this method to return {@code null}, indicating that there currently
+ * exists no user-chosen default {@code PhoneAccount}.
+ *
+ * @return The user outgoing phone account selected by the user.
+ * @hide
+ */
+ public PhoneAccountHandle getUserSelectedOutgoingPhoneAccount() {
+ try {
+ if (isServiceConnected()) {
+ return getTelecommService().getUserSelectedOutgoingPhoneAccount();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelecommService#getUserSelectedOutgoingPhoneAccount", e);
+ }
+ return null;
+ }
+
+ /**
* Sets the default account for making outgoing phone calls.
* @hide
*/
- public void setDefaultOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
+ public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
try {
if (isServiceConnected()) {
- getTelecommService().setDefaultOutgoingPhoneAccount(accountHandle);
+ getTelecommService().setUserSelectedOutgoingPhoneAccount(accountHandle);
}
} catch (RemoteException e) {
- Log.e(TAG, "Error calling ITelecommService#setDefaultOutgoingPhoneAccount");
+ Log.e(TAG, "Error calling ITelecommService#setUserSelectedOutgoingPhoneAccount");
}
}
diff --git a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
index a6ab3ac..6ab78c4 100644
--- a/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
+++ b/telecomm/java/com/android/internal/telecomm/ITelecommService.aidl
@@ -40,9 +40,14 @@
PhoneAccountHandle getDefaultOutgoingPhoneAccount(in String uriScheme);
/**
- * @see TelecommServiceImpl#setDefaultOutgoingPhoneAccount
+ * @see TelecommServiceImpl#getUserSelectedOutgoingPhoneAccount
*/
- void setDefaultOutgoingPhoneAccount(in PhoneAccountHandle account);
+ PhoneAccountHandle getUserSelectedOutgoingPhoneAccount();
+
+ /**
+ * @see TelecommServiceImpl#setUserSelectedOutgoingPhoneAccount
+ */
+ void setUserSelectedOutgoingPhoneAccount(in PhoneAccountHandle account);
/**
* @see TelecommServiceImpl#getOutgoingPhoneAccounts
diff --git a/telephony/java/android/telephony/SubInfoRecord.java b/telephony/java/android/telephony/SubInfoRecord.java
index 55781fa..3a47269 100644
--- a/telephony/java/android/telephony/SubInfoRecord.java
+++ b/telephony/java/android/telephony/SubInfoRecord.java
@@ -36,6 +36,8 @@
public int mDisplayNumberFormat;
public int mDataRoaming;
public int[] mSimIconRes;
+ public int mMcc;
+ public int mMnc;
public SubInfoRecord() {
this.mSubId = SubscriptionManager.INVALID_SUB_ID;
@@ -48,38 +50,45 @@
this.mDisplayNumberFormat = 0;
this.mDataRoaming = 0;
this.mSimIconRes = new int[2];
+ this.mMcc = 0;
+ this.mMnc = 0;
}
- public SubInfoRecord(long subId, String iccId, int slotId, String displayName,
- int nameSource, int mColor, String mNumber, int displayFormat, int roaming, int[] iconRes) {
+ public SubInfoRecord(long subId, String iccId, int slotId, String displayName, int nameSource,
+ int color, String number, int displayFormat, int roaming, int[] iconRes,
+ int mcc, int mnc) {
this.mSubId = subId;
this.mIccId = iccId;
this.mSlotId = slotId;
this.mDisplayName = displayName;
this.mNameSource = nameSource;
- this.mColor = mColor;
- this.mNumber = mNumber;
+ this.mColor = color;
+ this.mNumber = number;
this.mDisplayNumberFormat = displayFormat;
this.mDataRoaming = roaming;
this.mSimIconRes = iconRes;
+ this.mMcc = mcc;
+ this.mMnc = mnc;
}
public static final Parcelable.Creator<SubInfoRecord> CREATOR = new Parcelable.Creator<SubInfoRecord>() {
public SubInfoRecord createFromParcel(Parcel source) {
- long mSubId = source.readLong();
- String mIccId = source.readString();
- int mSlotId = source.readInt();
- String mDisplayName = source.readString();
- int mNameSource = source.readInt();
- int mColor = source.readInt();
- String mNumber = source.readString();
- int mDisplayNumberFormat = source.readInt();
- int mDataRoaming = source.readInt();
+ long subId = source.readLong();
+ String iccId = source.readString();
+ int slotId = source.readInt();
+ String displayName = source.readString();
+ int nameSource = source.readInt();
+ int color = source.readInt();
+ String number = source.readString();
+ int displayNumberFormat = source.readInt();
+ int dataRoaming = source.readInt();
int[] iconRes = new int[2];
source.readIntArray(iconRes);
+ int mcc = source.readInt();
+ int mnc = source.readInt();
- return new SubInfoRecord(mSubId, mIccId, mSlotId, mDisplayName, mNameSource, mColor, mNumber,
- mDisplayNumberFormat, mDataRoaming, iconRes);
+ return new SubInfoRecord(subId, iccId, slotId, displayName, nameSource, color, number,
+ displayNumberFormat, dataRoaming, iconRes, mcc, mnc);
}
public SubInfoRecord[] newArray(int size) {
@@ -98,6 +107,8 @@
dest.writeInt(mDisplayNumberFormat);
dest.writeInt(mDataRoaming);
dest.writeIntArray(mSimIconRes);
+ dest.writeInt(mMcc);
+ dest.writeInt(mMnc);
}
public int describeContents() {
@@ -109,6 +120,6 @@
+ " mDisplayName=" + mDisplayName + " mNameSource=" + mNameSource
+ " mColor=" + mColor + " mNumber=" + mNumber
+ " mDisplayNumberFormat=" + mDisplayNumberFormat + " mDataRoaming=" + mDataRoaming
- + " mSimIconRes=" + mSimIconRes + "}";
+ + " mSimIconRes=" + mSimIconRes + " mMcc " + mMcc + " mMnc " + mMnc + "}";
}
}
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 2bb2404..b5f8847 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -27,6 +27,7 @@
import com.android.internal.telephony.ISub;
import com.android.internal.telephony.PhoneConstants;
+
import java.util.List;
/**
@@ -204,6 +205,19 @@
/** @hide */
public static final int DATA_ROAMING_DEFAULT = DATA_ROAMING_DISABLE;
+ /**
+ * The MCC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MCC = "mcc";
+
+ /**
+ * The MNC associated with a SIM.
+ * <P>Type: INTEGER (int)</P>
+ */
+ public static final String MNC = "mnc";
+
+
private static final int RES_TYPE_BACKGROUND_DARK = 0;
private static final int RES_TYPE_BACKGROUND_LIGHT = 1;
diff --git a/telephony/java/com/android/internal/telephony/IMms.aidl b/telephony/java/com/android/internal/telephony/IMms.aidl
index 63b7a53..4337012 100644
--- a/telephony/java/com/android/internal/telephony/IMms.aidl
+++ b/telephony/java/com/android/internal/telephony/IMms.aidl
@@ -40,7 +40,7 @@
* broadcast when the message is successfully sent, or failed
*/
void sendMessage(long subId, String callingPkg, in Uri contentUri,
- String locationUrl, in ContentValues configOverrides, in PendingIntent sentIntent);
+ String locationUrl, in Bundle configOverrides, in PendingIntent sentIntent);
/**
* Download an MMS message using known location and transaction id
@@ -57,7 +57,7 @@
* broadcast when the message is downloaded, or the download is failed
*/
void downloadMessage(long subId, String callingPkg, String locationUrl,
- in Uri contentUri, in ContentValues configOverrides,
+ in Uri contentUri, in Bundle configOverrides,
in PendingIntent downloadedIntent);
/**
@@ -192,7 +192,7 @@
* broadcast when the message is successfully sent, or failed
*/
void sendStoredMessage(long subId, String callingPkg, in Uri messageUri,
- in ContentValues configOverrides, in PendingIntent sentIntent);
+ in Bundle configOverrides, in PendingIntent sentIntent);
/**
* Turns on/off the flag to automatically write sent/received SMS/MMS messages into system
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index 6bb28e1..393d2ec 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -20,15 +20,20 @@
Usage: apilint.py current.txt
Usage: apilint.py current.txt previous.txt
+
+You can also splice in blame details like this:
+$ git blame api/current.txt -t -e > /tmp/currentblame.txt
+$ apilint.py /tmp/currentblame.txt previous.txt --no-color
"""
-import re, sys, collections
+import re, sys, collections, traceback
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
def format(fg=None, bg=None, bright=False, bold=False, dim=False, reset=False):
# manually derived from http://en.wikipedia.org/wiki/ANSI_escape_code#Codes
+ if "--no-color" in sys.argv: return ""
codes = []
if reset: codes.append("0")
else:
@@ -43,9 +48,10 @@
class Field():
- def __init__(self, clazz, raw):
+ def __init__(self, clazz, raw, blame):
self.clazz = clazz
self.raw = raw.strip(" {;")
+ self.blame = blame
raw = raw.split()
self.split = list(raw)
@@ -60,14 +66,20 @@
else:
self.value = None
+ self.ident = self.raw.replace(" deprecated ", " ")
+
def __repr__(self):
return self.raw
class Method():
- def __init__(self, clazz, raw):
+ def __init__(self, clazz, raw, blame):
self.clazz = clazz
self.raw = raw.strip(" {;")
+ self.blame = blame
+
+ # drop generics for now
+ raw = re.sub("<.+?>", "", raw)
raw = re.split("[\s(),;]+", raw)
for r in ["", ";"]:
@@ -84,14 +96,24 @@
if r == "throws": break
self.args.append(r)
+ # identity for compat purposes
+ ident = self.raw
+ ident = ident.replace(" deprecated ", " ")
+ ident = ident.replace(" synchronized ", " ")
+ ident = re.sub("<.+?>", "", ident)
+ if " throws " in ident:
+ ident = ident[:ident.index(" throws ")]
+ self.ident = ident
+
def __repr__(self):
return self.raw
class Class():
- def __init__(self, pkg, raw):
+ def __init__(self, pkg, raw, blame):
self.pkg = pkg
self.raw = raw.strip(" {;")
+ self.blame = blame
self.ctors = []
self.fields = []
self.methods = []
@@ -102,19 +124,25 @@
self.fullname = raw[raw.index("class")+1]
elif "interface" in raw:
self.fullname = raw[raw.index("interface")+1]
-
- if "." in self.fullname:
- self.name = self.fullname[self.fullname.rindex(".")+1:]
else:
- self.name = self.fullname
+ raise ValueError("Funky class type %s" % (self.raw))
+
+ if "extends" in raw:
+ self.extends = raw[raw.index("extends")+1]
+ else:
+ self.extends = None
+
+ self.fullname = self.pkg.name + "." + self.fullname
+ self.name = self.fullname[self.fullname.rindex(".")+1:]
def __repr__(self):
return self.raw
class Package():
- def __init__(self, raw):
+ def __init__(self, raw, blame):
self.raw = raw.strip(" {;")
+ self.blame = blame
raw = raw.split()
self.name = raw[raw.index("package")+1]
@@ -124,55 +152,68 @@
def parse_api(fn):
- api = []
+ api = {}
pkg = None
clazz = None
+ blame = None
+
+ re_blame = re.compile("^([a-z0-9]{7,}) \(<([^>]+)>.+?\) (.+?)$")
with open(fn) as f:
for raw in f.readlines():
raw = raw.rstrip()
+ match = re_blame.match(raw)
+ if match is not None:
+ blame = match.groups()[0:2]
+ raw = match.groups()[2]
+ else:
+ blame = None
if raw.startswith("package"):
- pkg = Package(raw)
+ pkg = Package(raw, blame)
elif raw.startswith(" ") and raw.endswith("{"):
- clazz = Class(pkg, raw)
- api.append(clazz)
+ clazz = Class(pkg, raw, blame)
+ api[clazz.fullname] = clazz
elif raw.startswith(" ctor"):
- clazz.ctors.append(Method(clazz, raw))
+ clazz.ctors.append(Method(clazz, raw, blame))
elif raw.startswith(" method"):
- clazz.methods.append(Method(clazz, raw))
+ clazz.methods.append(Method(clazz, raw, blame))
elif raw.startswith(" field"):
- clazz.fields.append(Field(clazz, raw))
+ clazz.fields.append(Field(clazz, raw, blame))
return api
-failures = []
-
-def filter_dupe(s):
- return s.replace(" deprecated ", " ")
+failures = {}
def _fail(clazz, detail, msg):
"""Records an API failure to be processed later."""
global failures
+ sig = "%s-%s-%s" % (clazz.fullname, repr(detail), msg)
+ sig = sig.replace(" deprecated ", " ")
+
res = msg
+ blame = clazz.blame
if detail is not None:
res += "\n in " + repr(detail)
+ blame = detail.blame
res += "\n in " + repr(clazz)
res += "\n in " + repr(clazz.pkg)
- failures.append(filter_dupe(res))
+ if blame is not None:
+ res += "\n last modified by %s in %s" % (blame[1], blame[0])
+ failures[sig] = res
def warn(clazz, detail, msg):
- _fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK), format(reset=True), msg))
+ _fail(clazz, detail, "%sWarning:%s %s" % (format(fg=YELLOW, bg=BLACK, bold=True), format(reset=True), msg))
def error(clazz, detail, msg):
- _fail(clazz, detail, "%sError:%s %s" % (format(fg=RED, bg=BLACK), format(reset=True), msg))
+ _fail(clazz, detail, "%sError:%s %s" % (format(fg=RED, bg=BLACK, bold=True), format(reset=True), msg))
def verify_constants(clazz):
"""All static final constants must be FOO_NAME style."""
- if re.match("R\.[a-z]+", clazz.fullname): return
+ if re.match("android\.R\.[a-z]+", clazz.fullname): return
for f in clazz.fields:
if "static" in f.split and "final" in f.split:
@@ -188,6 +229,10 @@
def verify_class_names(clazz):
"""Try catching malformed class names like myMtp or MTPUser."""
+ if clazz.fullname.startswith("android.opengl"): return
+ if clazz.fullname.startswith("android.renderscript"): return
+ if re.match("android\.R\.[a-z]+", clazz.fullname): return
+
if re.search("[A-Z]{2,}", clazz.name) is not None:
warn(clazz, None, "Class name style should be Mtp not MTP")
if re.match("[^A-Z]", clazz.name):
@@ -196,32 +241,35 @@
def verify_method_names(clazz):
"""Try catching malformed method names, like Foo() or getMTU()."""
- if clazz.pkg.name == "android.opengl": return
+ if clazz.fullname.startswith("android.opengl"): return
+ if clazz.fullname.startswith("android.renderscript"): return
+ if clazz.fullname == "android.system.OsConstants": return
for m in clazz.methods:
if re.search("[A-Z]{2,}", m.name) is not None:
warn(clazz, m, "Method name style should be getMtu() instead of getMTU()")
if re.match("[^a-z]", m.name):
- error(clazz, None, "Method name must start with lowercase char")
+ error(clazz, m, "Method name must start with lowercase char")
def verify_callbacks(clazz):
"""Verify Callback classes.
All callback classes must be abstract.
All methods must follow onFoo() naming style."""
+ if clazz.fullname == "android.speech.tts.SynthesisCallback": return
if clazz.name.endswith("Callbacks"):
- error(clazz, None, "Class must be named exactly Callback")
+ error(clazz, None, "Class name must not be plural")
if clazz.name.endswith("Observer"):
- warn(clazz, None, "Class should be named Callback")
+ warn(clazz, None, "Class should be named FooCallback")
if clazz.name.endswith("Callback"):
if "interface" in clazz.split:
- error(clazz, None, "Callback must be abstract class")
+ error(clazz, None, "Callback must be abstract class to enable extension in future API levels")
for m in clazz.methods:
if not re.match("on[A-Z][a-z]*", m.name):
- error(clazz, m, "Callback method names must be onFoo style")
+ error(clazz, m, "Callback method names must be onFoo() style")
def verify_listeners(clazz):
@@ -233,16 +281,16 @@
if clazz.name.endswith("Listener"):
if " abstract class " in clazz.raw:
- error(clazz, None, "Listener should be interface")
+ error(clazz, None, "Listener should be an interface, otherwise renamed Callback")
for m in clazz.methods:
if not re.match("on[A-Z][a-z]*", m.name):
- error(clazz, m, "Listener method names must be onFoo style")
+ error(clazz, m, "Listener method names must be onFoo() style")
if len(clazz.methods) == 1 and clazz.name.startswith("On"):
m = clazz.methods[0]
if (m.name + "Listener").lower() != clazz.name.lower():
- error(clazz, m, "Single method name should match class name")
+ error(clazz, m, "Single listener method name should match class name")
def verify_actions(clazz):
@@ -255,21 +303,24 @@
for f in clazz.fields:
if f.value is None: continue
if f.name.startswith("EXTRA_"): continue
+ if f.name == "SERVICE_INTERFACE" or f.name == "PROVIDER_INTERFACE": continue
if "static" in f.split and "final" in f.split and f.typ == "java.lang.String":
if "_ACTION" in f.name or "ACTION_" in f.name or ".action." in f.value.lower():
if not f.name.startswith("ACTION_"):
- error(clazz, f, "Intent action must be ACTION_FOO")
+ error(clazz, f, "Intent action constant name must be ACTION_FOO")
else:
- if clazz.name == "Intent":
+ if clazz.fullname == "android.content.Intent":
prefix = "android.intent.action"
- elif clazz.name == "Settings":
+ elif clazz.fullname == "android.provider.Settings":
prefix = "android.settings"
+ elif clazz.fullname == "android.app.admin.DevicePolicyManager" or clazz.fullname == "android.app.admin.DeviceAdminReceiver":
+ prefix = "android.app.action"
else:
prefix = clazz.pkg.name + ".action"
expected = prefix + "." + f.name[7:]
if f.value != expected:
- error(clazz, f, "Inconsistent action value")
+ error(clazz, f, "Inconsistent action value; expected %s" % (expected))
def verify_extras(clazz):
@@ -279,6 +330,9 @@
package android.foo {
String EXTRA_BAR = "android.foo.extra.BAR";
}"""
+ if clazz.fullname == "android.app.Notification": return
+ if clazz.fullname == "android.appwidget.AppWidgetManager": return
+
for f in clazz.fields:
if f.value is None: continue
if f.name.startswith("ACTION_"): continue
@@ -288,13 +342,15 @@
if not f.name.startswith("EXTRA_"):
error(clazz, f, "Intent extra must be EXTRA_FOO")
else:
- if clazz.name == "Intent":
+ if clazz.pkg.name == "android.content" and clazz.name == "Intent":
prefix = "android.intent.extra"
+ elif clazz.pkg.name == "android.app.admin":
+ prefix = "android.app.extra"
else:
prefix = clazz.pkg.name + ".extra"
expected = prefix + "." + f.name[6:]
if f.value != expected:
- error(clazz, f, "Inconsistent extra value")
+ error(clazz, f, "Inconsistent extra value; expected %s" % (expected))
def verify_equals(clazz):
@@ -303,7 +359,7 @@
eq = "equals" in methods
hc = "hashCode" in methods
if eq != hc:
- error(clazz, None, "Must override both equals and hashCode")
+ error(clazz, None, "Must override both equals and hashCode; missing one")
def verify_parcelable(clazz):
@@ -314,34 +370,59 @@
describe = [ i for i in clazz.methods if i.name == "describeContents" ]
if len(creator) == 0 or len(write) == 0 or len(describe) == 0:
- error(clazz, None, "Parcelable requires CREATOR, writeToParcel, and describeContents")
+ error(clazz, None, "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
def verify_protected(clazz):
"""Verify that no protected methods are allowed."""
for m in clazz.methods:
if "protected" in m.split:
- error(clazz, m, "Protected method")
+ error(clazz, m, "No protected methods; must be public")
for f in clazz.fields:
if "protected" in f.split:
- error(clazz, f, "Protected field")
+ error(clazz, f, "No protected fields; must be public")
def verify_fields(clazz):
"""Verify that all exposed fields are final.
Exposed fields must follow myName style.
Catch internal mFoo objects being exposed."""
+
+ IGNORE_BARE_FIELDS = [
+ "android.app.ActivityManager.RecentTaskInfo",
+ "android.app.Notification",
+ "android.content.pm.ActivityInfo",
+ "android.content.pm.ApplicationInfo",
+ "android.content.pm.FeatureGroupInfo",
+ "android.content.pm.InstrumentationInfo",
+ "android.content.pm.PackageInfo",
+ "android.content.pm.PackageItemInfo",
+ "android.os.Message",
+ "android.system.StructPollfd",
+ ]
+
for f in clazz.fields:
if not "final" in f.split:
- error(clazz, f, "Bare fields must be final; consider adding accessors")
+ if clazz.fullname in IGNORE_BARE_FIELDS:
+ pass
+ elif clazz.fullname.endswith("LayoutParams"):
+ pass
+ elif clazz.fullname.startswith("android.util.Mutable"):
+ pass
+ else:
+ error(clazz, f, "Bare fields must be marked final; consider adding accessors")
if not "static" in f.split:
if not re.match("[a-z]([a-zA-Z]+)?", f.name):
- error(clazz, f, "Non-static fields must be myName")
+ error(clazz, f, "Non-static fields must be named with myField style")
- if re.match("[m][A-Z]", f.name):
+ if re.match("[ms][A-Z]", f.name):
error(clazz, f, "Don't expose your internal objects")
+ if re.match("[A-Z_]+", f.name):
+ if "static" not in f.split or "final" not in f.split:
+ error(clazz, f, "Constants must be marked static final")
+
def verify_register(clazz):
"""Verify parity of registration methods.
@@ -353,34 +434,34 @@
if m.name.startswith("register"):
other = "unregister" + m.name[8:]
if other not in methods:
- error(clazz, m, "Missing unregister")
+ error(clazz, m, "Missing unregister method")
if m.name.startswith("unregister"):
other = "register" + m.name[10:]
if other not in methods:
- error(clazz, m, "Missing register")
+ error(clazz, m, "Missing register method")
if m.name.startswith("add") or m.name.startswith("remove"):
- error(clazz, m, "Callback should be register/unregister")
+ error(clazz, m, "Callback methods should be named register/unregister")
if "Listener" in m.raw:
if m.name.startswith("add"):
other = "remove" + m.name[3:]
if other not in methods:
- error(clazz, m, "Missing remove")
+ error(clazz, m, "Missing remove method")
if m.name.startswith("remove") and not m.name.startswith("removeAll"):
other = "add" + m.name[6:]
if other not in methods:
- error(clazz, m, "Missing add")
+ error(clazz, m, "Missing add method")
if m.name.startswith("register") or m.name.startswith("unregister"):
- error(clazz, m, "Listener should be add/remove")
+ error(clazz, m, "Listener methods should be named add/remove")
def verify_sync(clazz):
"""Verify synchronized methods aren't exposed."""
for m in clazz.methods:
if "synchronized" in m.split:
- error(clazz, m, "Lock exposed")
+ error(clazz, m, "Internal lock exposed")
def verify_intent_builder(clazz):
@@ -392,7 +473,7 @@
if m.name.startswith("create") and m.name.endswith("Intent"):
pass
else:
- warn(clazz, m, "Should be createFooIntent()")
+ error(clazz, m, "Methods creating an Intent should be named createFooIntent()")
def verify_helper_classes(clazz):
@@ -402,25 +483,57 @@
if "extends android.app.Service" in clazz.raw:
test_methods = True
if not clazz.name.endswith("Service"):
- error(clazz, None, "Inconsistent class name")
+ error(clazz, None, "Inconsistent class name; should be FooService")
+
+ found = False
+ for f in clazz.fields:
+ if f.name == "SERVICE_INTERFACE":
+ found = True
+ if f.value != clazz.fullname:
+ error(clazz, f, "Inconsistent interface constant; expected %s" % (clazz.fullname))
+
+ if not found:
+ warn(clazz, None, "Missing SERVICE_INTERFACE constant")
+
+ if "abstract" in clazz.split and not clazz.fullname.startswith("android.service."):
+ warn(clazz, None, "Services extended by developers should be under android.service")
+
if "extends android.content.ContentProvider" in clazz.raw:
test_methods = True
if not clazz.name.endswith("Provider"):
- error(clazz, None, "Inconsistent class name")
+ error(clazz, None, "Inconsistent class name; should be FooProvider")
+
+ found = False
+ for f in clazz.fields:
+ if f.name == "PROVIDER_INTERFACE":
+ found = True
+ if f.value != clazz.fullname:
+ error(clazz, f, "Inconsistent interface name; expected %s" % (clazz.fullname))
+
+ if not found:
+ warn(clazz, None, "Missing PROVIDER_INTERFACE constant")
+
+ if "abstract" in clazz.split and not clazz.fullname.startswith("android.provider."):
+ warn(clazz, None, "Providers extended by developers should be under android.provider")
+
if "extends android.content.BroadcastReceiver" in clazz.raw:
test_methods = True
if not clazz.name.endswith("Receiver"):
- error(clazz, None, "Inconsistent class name")
+ error(clazz, None, "Inconsistent class name; should be FooReceiver")
+
if "extends android.app.Activity" in clazz.raw:
test_methods = True
if not clazz.name.endswith("Activity"):
- error(clazz, None, "Inconsistent class name")
+ error(clazz, None, "Inconsistent class name; should be FooActivity")
if test_methods:
for m in clazz.methods:
if "final" in m.split: continue
if not re.match("on[A-Z]", m.name):
- error(clazz, m, "Extendable methods should be onFoo() style, otherwise final")
+ if "abstract" in m.split:
+ error(clazz, m, "Methods implemented by developers must be named onFoo()")
+ else:
+ warn(clazz, m, "If implemented by developer, should be named onFoo(); otherwise consider marking final")
def verify_builder(clazz):
@@ -430,7 +543,7 @@
if not clazz.name.endswith("Builder"): return
if clazz.name != "Builder":
- warn(clazz, None, "Should be standalone Builder class")
+ warn(clazz, None, "Builder should be defined as inner class")
has_build = False
for m in clazz.methods:
@@ -442,11 +555,11 @@
if m.name.startswith("clear"): continue
if m.name.startswith("with"):
- error(clazz, m, "Builder methods must be setFoo()")
+ error(clazz, m, "Builder methods names must follow setFoo() style")
if m.name.startswith("set"):
if not m.typ.endswith(clazz.fullname):
- warn(clazz, m, "Should return the builder")
+ warn(clazz, m, "Methods should return the builder")
if not has_build:
warn(clazz, None, "Missing build() method")
@@ -474,7 +587,7 @@
"android.view",
"android.animation",
"android.provider",
- "android.content",
+ ["android.content","android.graphics.drawable"],
"android.database",
"android.graphics",
"android.text",
@@ -508,29 +621,40 @@
warn(clazz, m, "Method argument type violates package layering")
-def verify_boolean(clazz):
+def verify_boolean(clazz, api):
"""Catches people returning boolean from getFoo() style methods.
Ignores when matching setFoo() is present."""
+
methods = [ m.name for m in clazz.methods ]
+
+ builder = clazz.fullname + ".Builder"
+ builder_methods = []
+ if builder in api:
+ builder_methods = [ m.name for m in api[builder].methods ]
+
for m in clazz.methods:
if m.typ == "boolean" and m.name.startswith("get") and m.name != "get" and len(m.args) == 0:
setter = "set" + m.name[3:]
- if setter not in methods:
- error(clazz, m, "Methods returning boolean should be isFoo or hasFoo")
+ if setter in methods:
+ pass
+ elif builder is not None and setter in builder_methods:
+ pass
+ else:
+ warn(clazz, m, "Methods returning boolean should be named isFoo, hasFoo, areFoo")
def verify_collections(clazz):
"""Verifies that collection types are interfaces."""
+ if clazz.fullname == "android.os.Bundle": return
+
bad = ["java.util.Vector", "java.util.LinkedList", "java.util.ArrayList", "java.util.Stack",
"java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"]
for m in clazz.methods:
- filt = re.sub("<.+>", "", m.typ)
- if filt in bad:
- error(clazz, m, "Return type is concrete collection")
+ if m.typ in bad:
+ error(clazz, m, "Return type is concrete collection; should be interface")
for arg in m.args:
- filt = re.sub("<.+>", "", arg)
- if filt in bad:
- error(clazz, m, "Argument is concrete collection")
+ if arg in bad:
+ error(clazz, m, "Argument is concrete collection; should be interface")
def verify_flags(clazz):
@@ -545,15 +669,18 @@
scope = f.name[0:f.name.index("FLAG_")]
if val & known[scope]:
- warn(clazz, f, "Found overlapping flag")
+ warn(clazz, f, "Found overlapping flag constant value")
known[scope] |= val
-def verify_all(api):
+def verify_style(api):
+ """Find all style issues in the given API level."""
global failures
- failures = []
- for clazz in api:
+ failures = {}
+ for key in sorted(api.keys()):
+ clazz = api[key]
+
if clazz.pkg.name.startswith("java"): continue
if clazz.pkg.name.startswith("junit"): continue
if clazz.pkg.name.startswith("org.apache"): continue
@@ -581,26 +708,90 @@
verify_aidl(clazz)
verify_internal(clazz)
verify_layering(clazz)
- verify_boolean(clazz)
+ verify_boolean(clazz, api)
verify_collections(clazz)
verify_flags(clazz)
return failures
+def verify_compat(cur, prev):
+ """Find any incompatible API changes between two levels."""
+ global failures
+
+ def class_exists(api, test):
+ return test.fullname in api
+
+ def ctor_exists(api, clazz, test):
+ for m in clazz.ctors:
+ if m.ident == test.ident: return True
+ return False
+
+ def all_methods(api, clazz):
+ methods = list(clazz.methods)
+ if clazz.extends is not None:
+ methods.extend(all_methods(api, api[clazz.extends]))
+ return methods
+
+ def method_exists(api, clazz, test):
+ methods = all_methods(api, clazz)
+ for m in methods:
+ if m.ident == test.ident: return True
+ return False
+
+ def field_exists(api, clazz, test):
+ for f in clazz.fields:
+ if f.ident == test.ident: return True
+ return False
+
+ failures = {}
+ for key in sorted(prev.keys()):
+ prev_clazz = prev[key]
+
+ if not class_exists(cur, prev_clazz):
+ error(prev_clazz, None, "Class removed or incompatible change")
+ continue
+
+ cur_clazz = cur[key]
+
+ for test in prev_clazz.ctors:
+ if not ctor_exists(cur, cur_clazz, test):
+ error(prev_clazz, prev_ctor, "Constructor removed or incompatible change")
+
+ methods = all_methods(prev, prev_clazz)
+ for test in methods:
+ if not method_exists(cur, cur_clazz, test):
+ error(prev_clazz, test, "Method removed or incompatible change")
+
+ for test in prev_clazz.fields:
+ if not field_exists(cur, cur_clazz, test):
+ error(prev_clazz, test, "Field removed or incompatible change")
+
+ return failures
+
+
cur = parse_api(sys.argv[1])
-cur_fail = verify_all(cur)
+cur_fail = verify_style(cur)
if len(sys.argv) > 2:
prev = parse_api(sys.argv[2])
- prev_fail = verify_all(prev)
+ prev_fail = verify_style(prev)
# ignore errors from previous API level
for p in prev_fail:
if p in cur_fail:
- cur_fail.remove(p)
+ del cur_fail[p]
+
+ # look for compatibility issues
+ compat_fail = verify_compat(cur, prev)
+
+ print "%s API compatibility issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+ for f in sorted(compat_fail):
+ print compat_fail[f]
+ print
-for f in cur_fail:
- print f
+print "%s API style issues %s\n" % ((format(fg=WHITE, bg=BLUE, bold=True), format(reset=True)))
+for f in sorted(cur_fail):
+ print cur_fail[f]
print