Merge "Selected count string needs plurals." into mnc-dev
diff --git a/Android.mk b/Android.mk
index 1752caf..e96a932 100644
--- a/Android.mk
+++ b/Android.mk
@@ -142,6 +142,7 @@
core/java/android/content/pm/IPackageManager.aidl \
core/java/android/content/pm/IPackageMoveObserver.aidl \
core/java/android/content/pm/IPackageStatsObserver.aidl \
+ core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
core/java/android/database/IContentObserver.aidl \
core/java/android/hardware/ICameraService.aidl \
core/java/android/hardware/ICameraServiceListener.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 667ed02..48be749 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -234,6 +234,7 @@
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/lib/libinputflingerhost.so $(PRODUCT_OUT)/obj_arm/lib/libinputflingerhost.so)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/SHARED_LIBRARIES/libinputflingerhost_intermediates $(PRODUCT_OUT)/obj_arm/SHARED_LIBRARIES/libinputflingerhost_intermediates)
$(call add-clean-step, rm -rf $(PRODUCT_OUT)/target/common/obj/framework.aidl)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates)
# ******************************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
diff --git a/api/current.txt b/api/current.txt
index fb60f1c..ec56ce0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17,7 +17,6 @@
field public static final java.lang.String ACCESS_WIFI_STATE = "android.permission.ACCESS_WIFI_STATE";
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
- field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -86,7 +85,6 @@
field public static final java.lang.String INTERNET = "android.permission.INTERNET";
field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
- field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
field public static final java.lang.String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
field public static final java.lang.String MASTER_CLEAR = "android.permission.MASTER_CLEAR";
@@ -145,7 +143,6 @@
field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
- field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
@@ -222,6 +219,12 @@
ctor public R.attr();
field public static final int __reserved0 = 16844020; // 0x10104f4
field public static final int __reserved1 = 16844019; // 0x10104f3
+ field public static final int __reserved2 = 16843999; // 0x10104df
+ field public static final int __reserved3 = 16844000; // 0x10104e0
+ field public static final int __reserved4 = 16844001; // 0x10104e1
+ field public static final int __reserved5 = 16844002; // 0x10104e2
+ field public static final int __reserved6 = 16844003; // 0x10104e3
+ field public static final int __reserved7 = 16844004; // 0x10104e4
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -661,8 +664,6 @@
field public static final int hyphenationFrequency = 16844024; // 0x10104f8
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
- field public static final int iconTint = 16843999; // 0x10104df
- field public static final int iconTintMode = 16844000; // 0x10104e0
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -874,8 +875,6 @@
field public static final int navigationContentDescription = 16843969; // 0x10104c1
field public static final int navigationIcon = 16843968; // 0x10104c0
field public static final int navigationMode = 16843471; // 0x10102cf
- field public static final int navigationTint = 16844003; // 0x10104e3
- field public static final int navigationTintMode = 16844004; // 0x10104e4
field public static final int negativeButtonText = 16843254; // 0x10101f6
field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -907,8 +906,6 @@
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
- field public static final int overflowTint = 16844001; // 0x10104e1
- field public static final int overflowTintMode = 16844002; // 0x10104e2
field public static final int overlapAnchor = 16843874; // 0x1010462
field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
field public static final int packageNames = 16843649; // 0x1010381
@@ -5681,23 +5678,6 @@
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
}
- public class DeviceInitializerStatus {
- field public static final int FLAG_STATUS_CUSTOM = 33554432; // 0x2000000
- field public static final int FLAG_STATUS_ERROR = 16777216; // 0x1000000
- field public static final int FLAG_STATUS_HIGH_PRIORITY = 134217728; // 0x8000000
- field public static final int FLAG_STATUS_RESERVED = 67108864; // 0x4000000
- field public static final int STATUS_ERROR_CONNECT_WIFI = 16777237; // 0x1000015
- field public static final int STATUS_ERROR_DELETE_APPS = 16777242; // 0x100001a
- field public static final int STATUS_ERROR_DOUBLE_BUMP = 16777246; // 0x100001e
- field public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = 16777239; // 0x1000017
- field public static final int STATUS_ERROR_INSTALL_PACKAGE = 16777240; // 0x1000018
- field public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING = 16777238; // 0x1000016
- field public static final int STATUS_ERROR_SET_DEVICE_POLICY = 16777241; // 0x1000019
- field public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = 134217736; // 0x8000008
- field public static final int STATUS_STATE_DEVICE_PROVISIONED = 134217738; // 0x800000a
- field public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = 134217737; // 0x8000009
- }
-
public class DevicePolicyManager {
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -5765,7 +5745,6 @@
method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean resetPassword(java.lang.String, int);
- method public void sendDeviceInitializerStatus(int, java.lang.String);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
method public void setApplicationRestrictions(android.content.ComponentName, java.lang.String, android.os.Bundle);
@@ -5829,10 +5808,6 @@
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_DEVICE_ID = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_MAC_ADDRESS = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_USE_PROXY = "android.app.extra.PROVISIONING_BT_USE_PROXY";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_UUID = "android.app.extra.PROVISIONING_BT_UUID";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
@@ -7721,6 +7696,7 @@
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
method public final T getSystemService(java.lang.Class<T>);
+ method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -17210,7 +17186,7 @@
method public void connect();
method public void disconnect();
method public android.os.Bundle getExtras();
- method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
+ method public void getItem(java.lang.String, android.media.browse.MediaBrowser.ItemCallback);
method public java.lang.String getRoot();
method public android.content.ComponentName getServiceComponent();
method public android.media.session.MediaSession.Token getSessionToken();
@@ -17226,6 +17202,12 @@
method public void onConnectionSuspended();
}
+ public static abstract class MediaBrowser.ItemCallback {
+ ctor public MediaBrowser.ItemCallback();
+ method public void onError(java.lang.String);
+ method public void onItemLoaded(android.media.browse.MediaBrowser.MediaItem);
+ }
+
public static class MediaBrowser.MediaItem implements android.os.Parcelable {
ctor public MediaBrowser.MediaItem(android.media.MediaDescription, int);
method public int describeContents();
@@ -17240,12 +17222,6 @@
field public static final int FLAG_PLAYABLE = 2; // 0x2
}
- public static abstract class MediaBrowser.MediaItemCallback {
- ctor public MediaBrowser.MediaItemCallback();
- method public void onError();
- method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
- }
-
public static abstract class MediaBrowser.SubscriptionCallback {
ctor public MediaBrowser.SubscriptionCallback();
method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -24476,6 +24452,7 @@
method protected abstract void onPrintJobQueued(android.printservice.PrintJob);
method protected abstract void onRequestCancelPrintJob(android.printservice.PrintJob);
field public static final java.lang.String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
+ field public static final java.lang.String EXTRA_PRINT_DOCUMENT_INFO = "android.printservice.extra.PRINT_DOCUMENT_INFO";
field public static final java.lang.String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService";
field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
@@ -28787,12 +28764,12 @@
public abstract class MediaBrowserService extends android.app.Service {
ctor public MediaBrowserService();
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
method public android.media.session.MediaSession.Token getSessionToken();
method public void notifyChildrenChanged(java.lang.String);
method public android.os.IBinder onBind(android.content.Intent);
method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+ method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
method public void setSessionToken(android.media.session.MediaSession.Token);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
}
@@ -30735,7 +30712,7 @@
field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
- field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_BOOL = "voice_privacy_disable_bool";
+ field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -35491,8 +35468,6 @@
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
- method public abstract android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
- method public abstract android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
method public abstract android.view.MenuItem setIntent(android.content.Intent);
method public abstract android.view.MenuItem setNumericShortcut(char);
method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
@@ -39553,14 +39528,14 @@
ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
method public void dismissPopupMenus();
method public android.view.Menu getMenu();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public boolean hideOverflowMenu();
method public boolean isOverflowMenuShowing();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onDetachedFromWindow();
method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
- method public void setOverflowTintList(android.content.res.ColorStateList);
- method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public boolean showOverflowMenu();
}
@@ -41850,6 +41825,7 @@
method public android.view.Menu getMenu();
method public java.lang.CharSequence getNavigationContentDescription();
method public android.graphics.drawable.Drawable getNavigationIcon();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
@@ -41869,11 +41845,8 @@
method public void setNavigationIcon(int);
method public void setNavigationIcon(android.graphics.drawable.Drawable);
method public void setNavigationOnClickListener(android.view.View.OnClickListener);
- method public void setNavigationTintList(android.content.res.ColorStateList);
- method public void setNavigationTintMode(android.graphics.PorterDuff.Mode);
method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
- method public void setOverflowTintList(android.content.res.ColorStateList);
- method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public void setSubtitle(int);
method public void setSubtitle(java.lang.CharSequence);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7816c3f..5ec8a62 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -24,7 +24,6 @@
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
- field public static final java.lang.String AUTHENTICATE_ACCOUNTS = "android.permission.AUTHENTICATE_ACCOUNTS";
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
@@ -117,7 +116,6 @@
field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO";
- field public static final java.lang.String MANAGE_ACCOUNTS = "android.permission.MANAGE_ACCOUNTS";
field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
@@ -217,7 +215,6 @@
field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
- field public static final java.lang.String USE_CREDENTIALS = "android.permission.USE_CREDENTIALS";
field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
field public static final java.lang.String VIBRATE = "android.permission.VIBRATE";
@@ -297,6 +294,12 @@
ctor public R.attr();
field public static final int __reserved0 = 16844020; // 0x10104f4
field public static final int __reserved1 = 16844019; // 0x10104f3
+ field public static final int __reserved2 = 16843999; // 0x10104df
+ field public static final int __reserved3 = 16844000; // 0x10104e0
+ field public static final int __reserved4 = 16844001; // 0x10104e1
+ field public static final int __reserved5 = 16844002; // 0x10104e2
+ field public static final int __reserved6 = 16844003; // 0x10104e3
+ field public static final int __reserved7 = 16844004; // 0x10104e4
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -736,8 +739,6 @@
field public static final int hyphenationFrequency = 16844024; // 0x10104f8
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
- field public static final int iconTint = 16843999; // 0x10104df
- field public static final int iconTintMode = 16844000; // 0x10104e0
field public static final int iconifiedByDefault = 16843514; // 0x10102fa
field public static final int id = 16842960; // 0x10100d0
field public static final int ignoreGravity = 16843263; // 0x10101ff
@@ -949,8 +950,6 @@
field public static final int navigationContentDescription = 16843969; // 0x10104c1
field public static final int navigationIcon = 16843968; // 0x10104c0
field public static final int navigationMode = 16843471; // 0x10102cf
- field public static final int navigationTint = 16844003; // 0x10104e3
- field public static final int navigationTintMode = 16844004; // 0x10104e4
field public static final int negativeButtonText = 16843254; // 0x10101f6
field public static final int nestedScrollingEnabled = 16843830; // 0x1010436
field public static final int nextFocusDown = 16842980; // 0x10100e4
@@ -982,8 +981,6 @@
field public static final int overScrollFooter = 16843459; // 0x10102c3
field public static final int overScrollHeader = 16843458; // 0x10102c2
field public static final int overScrollMode = 16843457; // 0x10102c1
- field public static final int overflowTint = 16844001; // 0x10104e1
- field public static final int overflowTintMode = 16844002; // 0x10104e2
field public static final int overlapAnchor = 16843874; // 0x1010462
field public static final int overridesImplicitlyEnabledSubtype = 16843682; // 0x10103a2
field public static final int packageNames = 16843649; // 0x1010381
@@ -5781,23 +5778,6 @@
field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE";
}
- public class DeviceInitializerStatus {
- field public static final int FLAG_STATUS_CUSTOM = 33554432; // 0x2000000
- field public static final int FLAG_STATUS_ERROR = 16777216; // 0x1000000
- field public static final int FLAG_STATUS_HIGH_PRIORITY = 134217728; // 0x8000000
- field public static final int FLAG_STATUS_RESERVED = 67108864; // 0x4000000
- field public static final int STATUS_ERROR_CONNECT_WIFI = 16777237; // 0x1000015
- field public static final int STATUS_ERROR_DELETE_APPS = 16777242; // 0x100001a
- field public static final int STATUS_ERROR_DOUBLE_BUMP = 16777246; // 0x100001e
- field public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = 16777239; // 0x1000017
- field public static final int STATUS_ERROR_INSTALL_PACKAGE = 16777240; // 0x1000018
- field public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING = 16777238; // 0x1000016
- field public static final int STATUS_ERROR_SET_DEVICE_POLICY = 16777241; // 0x1000019
- field public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = 134217736; // 0x8000008
- field public static final int STATUS_STATE_DEVICE_PROVISIONED = 134217738; // 0x800000a
- field public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = 134217737; // 0x8000009
- }
-
public class DevicePolicyManager {
method public void addCrossProfileIntentFilter(android.content.ComponentName, android.content.IntentFilter, int);
method public boolean addCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
@@ -5874,7 +5854,6 @@
method public boolean removeCrossProfileWidgetProvider(android.content.ComponentName, java.lang.String);
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean resetPassword(java.lang.String, int);
- method public void sendDeviceInitializerStatus(int, java.lang.String);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
@@ -5927,7 +5906,6 @@
field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE";
field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
- field public static final java.lang.String ACTION_SEND_DEVICE_INITIALIZER_STATUS = "android.app.action.SEND_DEVICE_INITIALIZER_STATUS";
field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
@@ -5939,15 +5917,9 @@
field public static final int ENCRYPTION_STATUS_UNSUPPORTED = 0; // 0x0
field public static final java.lang.String EXTRA_ADD_EXPLANATION = "android.app.extra.ADD_EXPLANATION";
field public static final java.lang.String EXTRA_DEVICE_ADMIN = "android.app.extra.DEVICE_ADMIN";
- field public static final java.lang.String EXTRA_DEVICE_INITIALIZER_STATUS_CODE = "android.app.extra.DEVICE_INITIALIZER_STATUS_CODE";
- field public static final java.lang.String EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION = "android.app.extra.DEVICE_INITIALIZER_STATUS_DESCRIPTION";
field public static final java.lang.String EXTRA_PROFILE_OWNER_NAME = "android.app.extra.PROFILE_OWNER_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE = "android.app.extra.PROVISIONING_ACCOUNT_TO_MIGRATE";
field public static final java.lang.String EXTRA_PROVISIONING_ADMIN_EXTRAS_BUNDLE = "android.app.extra.PROVISIONING_ADMIN_EXTRAS_BUNDLE";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_DEVICE_ID = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_MAC_ADDRESS = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_USE_PROXY = "android.app.extra.PROVISIONING_BT_USE_PROXY";
- field public static final java.lang.String EXTRA_PROVISIONING_BT_UUID = "android.app.extra.PROVISIONING_BT_UUID";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_ADMIN_CERTIFICATE_CHECKSUM";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_COMPONENT_NAME";
field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE = "android.app.extra.PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE";
@@ -7944,6 +7916,7 @@
method public final java.lang.String getString(int, java.lang.Object...);
method public abstract java.lang.Object getSystemService(java.lang.String);
method public final T getSystemService(java.lang.Class<T>);
+ method public abstract java.lang.String getSystemServiceName(java.lang.Class<?>);
method public final java.lang.CharSequence getText(int);
method public abstract android.content.res.Resources.Theme getTheme();
method public abstract deprecated android.graphics.drawable.Drawable getWallpaper();
@@ -9521,6 +9494,7 @@
public abstract class PackageManager {
ctor public PackageManager();
+ method public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract deprecated void addPackageToPreferred(java.lang.String);
method public abstract boolean addPermission(android.content.pm.PermissionInfo);
method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
@@ -9594,6 +9568,7 @@
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public abstract deprecated void removePackageFromPreferred(java.lang.String);
method public abstract void removePermission(java.lang.String);
method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
@@ -9769,6 +9744,10 @@
ctor public PackageManager.NameNotFoundException(java.lang.String);
}
+ public static abstract interface PackageManager.OnPermissionsChangedListener {
+ method public abstract void onPermissionsChanged(int);
+ }
+
public static abstract class PackageManager.PermissionFlags implements java.lang.annotation.Annotation {
}
@@ -18522,7 +18501,7 @@
method public void connect();
method public void disconnect();
method public android.os.Bundle getExtras();
- method public void getMediaItem(java.lang.String, android.media.browse.MediaBrowser.MediaItemCallback);
+ method public void getItem(java.lang.String, android.media.browse.MediaBrowser.ItemCallback);
method public java.lang.String getRoot();
method public android.content.ComponentName getServiceComponent();
method public android.media.session.MediaSession.Token getSessionToken();
@@ -18538,6 +18517,12 @@
method public void onConnectionSuspended();
}
+ public static abstract class MediaBrowser.ItemCallback {
+ ctor public MediaBrowser.ItemCallback();
+ method public void onError(java.lang.String);
+ method public void onItemLoaded(android.media.browse.MediaBrowser.MediaItem);
+ }
+
public static class MediaBrowser.MediaItem implements android.os.Parcelable {
ctor public MediaBrowser.MediaItem(android.media.MediaDescription, int);
method public int describeContents();
@@ -18552,12 +18537,6 @@
field public static final int FLAG_PLAYABLE = 2; // 0x2
}
- public static abstract class MediaBrowser.MediaItemCallback {
- ctor public MediaBrowser.MediaItemCallback();
- method public void onError();
- method public void onMediaItemLoaded(android.media.browse.MediaBrowser.MediaItem);
- }
-
public static abstract class MediaBrowser.SubscriptionCallback {
ctor public MediaBrowser.SubscriptionCallback();
method public void onChildrenLoaded(java.lang.String, java.util.List<android.media.browse.MediaBrowser.MediaItem>);
@@ -19194,7 +19173,9 @@
method public android.content.Intent createSettingsIntent();
method public android.content.Intent createSetupIntent();
method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.hardware.hdmi.HdmiDeviceInfo, java.lang.String, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, java.lang.String, android.net.Uri) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+ method public static android.media.tv.TvInputInfo createTvInputInfo(android.content.Context, android.content.pm.ResolveInfo, android.media.tv.TvInputHardwareInfo, int, android.graphics.drawable.Icon) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
method public int describeContents();
method public android.hardware.hdmi.HdmiDeviceInfo getHdmiDeviceInfo();
method public java.lang.String getId();
@@ -26406,6 +26387,7 @@
method protected abstract void onPrintJobQueued(android.printservice.PrintJob);
method protected abstract void onRequestCancelPrintJob(android.printservice.PrintJob);
field public static final java.lang.String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
+ field public static final java.lang.String EXTRA_PRINT_DOCUMENT_INFO = "android.printservice.extra.PRINT_DOCUMENT_INFO";
field public static final java.lang.String EXTRA_PRINT_JOB_INFO = "android.intent.extra.print.PRINT_JOB_INFO";
field public static final java.lang.String SERVICE_INTERFACE = "android.printservice.PrintService";
field public static final java.lang.String SERVICE_META_DATA = "android.printservice";
@@ -30820,12 +30802,12 @@
public abstract class MediaBrowserService extends android.app.Service {
ctor public MediaBrowserService();
method public void dump(java.io.FileDescriptor, java.io.PrintWriter, java.lang.String[]);
- method public void getMediaItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>) throws java.lang.UnsupportedOperationException;
method public android.media.session.MediaSession.Token getSessionToken();
method public void notifyChildrenChanged(java.lang.String);
method public android.os.IBinder onBind(android.content.Intent);
method public abstract android.service.media.MediaBrowserService.BrowserRoot onGetRoot(java.lang.String, int, android.os.Bundle);
method public abstract void onLoadChildren(java.lang.String, android.service.media.MediaBrowserService.Result<java.util.List<android.media.browse.MediaBrowser.MediaItem>>);
+ method public void onLoadItem(java.lang.String, android.service.media.MediaBrowserService.Result<android.media.browse.MediaBrowser.MediaItem>);
method public void setSessionToken(android.media.session.MediaSession.Token);
field public static final java.lang.String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
}
@@ -32951,7 +32933,7 @@
field public static final java.lang.String KEY_USE_HFA_FOR_PROVISIONING_BOOL = "use_hfa_for_provisioning_bool";
field public static final java.lang.String KEY_USE_OTASP_FOR_PROVISIONING_BOOL = "use_otasp_for_provisioning_bool";
field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
- field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_BOOL = "voice_privacy_disable_bool";
+ field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -34157,6 +34139,7 @@
public class MockPackageManager extends android.content.pm.PackageManager {
ctor public MockPackageManager();
+ method public void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void addPackageToPreferred(java.lang.String);
method public boolean addPermission(android.content.pm.PermissionInfo);
method public boolean addPermissionAsync(android.content.pm.PermissionInfo);
@@ -34231,6 +34214,7 @@
method public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
method public java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
method public java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+ method public void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
method public void removePackageFromPreferred(java.lang.String);
method public void removePermission(java.lang.String);
method public android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
@@ -37761,8 +37745,6 @@
method public abstract android.view.MenuItem setEnabled(boolean);
method public abstract android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
method public abstract android.view.MenuItem setIcon(int);
- method public abstract android.view.MenuItem setIconTintList(android.content.res.ColorStateList);
- method public abstract android.view.MenuItem setIconTintMode(android.graphics.PorterDuff.Mode);
method public abstract android.view.MenuItem setIntent(android.content.Intent);
method public abstract android.view.MenuItem setNumericShortcut(char);
method public abstract android.view.MenuItem setOnActionExpandListener(android.view.MenuItem.OnActionExpandListener);
@@ -42137,14 +42119,14 @@
ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
method public void dismissPopupMenus();
method public android.view.Menu getMenu();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public boolean hideOverflowMenu();
method public boolean isOverflowMenuShowing();
method public void onConfigurationChanged(android.content.res.Configuration);
method public void onDetachedFromWindow();
method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
- method public void setOverflowTintList(android.content.res.ColorStateList);
- method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public boolean showOverflowMenu();
}
@@ -44434,6 +44416,7 @@
method public android.view.Menu getMenu();
method public java.lang.CharSequence getNavigationContentDescription();
method public android.graphics.drawable.Drawable getNavigationIcon();
+ method public android.graphics.drawable.Drawable getOverflowIcon();
method public int getPopupTheme();
method public java.lang.CharSequence getSubtitle();
method public java.lang.CharSequence getTitle();
@@ -44453,11 +44436,8 @@
method public void setNavigationIcon(int);
method public void setNavigationIcon(android.graphics.drawable.Drawable);
method public void setNavigationOnClickListener(android.view.View.OnClickListener);
- method public void setNavigationTintList(android.content.res.ColorStateList);
- method public void setNavigationTintMode(android.graphics.PorterDuff.Mode);
method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
- method public void setOverflowTintList(android.content.res.ColorStateList);
- method public void setOverflowTintMode(android.graphics.PorterDuff.Mode);
+ method public void setOverflowIcon(android.graphics.drawable.Drawable);
method public void setPopupTheme(int);
method public void setSubtitle(int);
method public void setSubtitle(java.lang.CharSequence);
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 31e129b..993b53d 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -51,10 +51,7 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
-import static android.Manifest.permission.AUTHENTICATE_ACCOUNTS;
import static android.Manifest.permission.GET_ACCOUNTS;
-import static android.Manifest.permission.MANAGE_ACCOUNTS;
-import static android.Manifest.permission.USE_CREDENTIALS;
/**
* This class provides access to a centralized registry of the user's
@@ -319,14 +316,12 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that owns the specified account.
*
- * @param account The account to query for a password
+ * @param account The account to query for a password. Must not be {@code null}.
* @return The account's password, null if none or if the account doesn't exist
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String getPassword(final Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -345,14 +340,12 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that owns the specified account.
*
* @param account The account to query for user data
* @return The user data, null if the account or key doesn't exist
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String getUserData(final Account account, final String key) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
@@ -662,10 +655,8 @@
* wizards associated with authenticators, not directly by applications.
*
* <p>It is safe to call this method from the main thread.
- *
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the added account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that owns the specified account.
*
* @param account The {@link Account} to add
* @param password The password to associate with the account, null for none
@@ -673,7 +664,6 @@
* @return True if the account was successfully added, false if the account
* already exists, the account is null, or another error occurs.
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean addAccountExplicitly(Account account, String password, Bundle userdata) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -692,14 +682,13 @@
* <p>
* It is not safe to call this method from the main thread. As such, call it
* from another thread.
- * <p>
- * This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and should be
- * called from the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that owns the specified account.
*
* @param account The {@link Account} to be updated.
+ * @return boolean {@code true} if the authentication of the account has been successfully
+ * acknowledged. Otherwise {@code false}.
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean notifyAccountAuthenticated(Account account) {
if (account == null)
throw new IllegalArgumentException("account is null");
@@ -717,9 +706,8 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The {@link Account} to rename
* @param newName String name to be associated with the account.
@@ -731,7 +719,6 @@
* after the name change. If successful the account's name will be the
* specified new name.
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public AccountManagerFuture<Account> renameAccount(
final Account account,
@Size(min = 1) final String newName,
@@ -783,11 +770,8 @@
* The authenticator may have its own policies preventing account
* deletion, in which case the account will not be deleted.
*
- * <p>This method may be called from any thread, but the returned
- * {@link AccountManagerFuture} must not be used on the main thread.
- *
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The {@link Account} to remove
* @param callback Callback to invoke when the request completes,
@@ -800,15 +784,16 @@
* {@link #removeAccount(Account, Activity, AccountManagerCallback, Handler)}
* instead
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
@Deprecated
public AccountManagerFuture<Boolean> removeAccount(final Account account,
AccountManagerCallback<Boolean> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
return new Future2Task<Boolean>(handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.removeAccount(mResponse, account, false);
}
+ @Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
throw new AuthenticatorException("no result in response");
@@ -827,8 +812,8 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The {@link Account} to remove
* @param activity The {@link Activity} context to use for launching a new
@@ -855,11 +840,11 @@
* adding accounts (of this type) has been disabled by policy
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> removeAccount(final Account account,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
if (account == null) throw new IllegalArgumentException("account is null");
return new AmsTask(activity, handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.removeAccount(mResponse, account, activity != null);
}
@@ -880,9 +865,11 @@
if (account == null) throw new IllegalArgumentException("account is null");
if (userHandle == null) throw new IllegalArgumentException("userHandle is null");
return new Future2Task<Boolean>(handler, callback) {
+ @Override
public void doWork() throws RemoteException {
mService.removeAccountAsUser(mResponse, account, false, userHandle.getIdentifier());
}
+ @Override
public Boolean bundleToResult(Bundle bundle) throws AuthenticatorException {
if (!bundle.containsKey(KEY_BOOLEAN_RESULT)) {
throw new AuthenticatorException("no result in response");
@@ -918,17 +905,14 @@
* in which case the account will not be deleted.
* <p>
* It is safe to call this method from the main thread.
- * <p>
- * This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS} and to have the
- * same UID or signature as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The {@link Account} to delete.
* @return True if the account was successfully deleted, false if the
* account did not exist, the account is null, or another error
* occurs.
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public boolean removeAccountExplicitly(Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -948,14 +932,9 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS} or
- * {@link android.Manifest.permission#USE_CREDENTIALS}
- *
* @param accountType The account type of the auth token to invalidate, must not be null
* @param authToken The auth token to invalidate, may be null
*/
- @RequiresPermission(anyOf = {MANAGE_ACCOUNTS, USE_CREDENTIALS})
public void invalidateAuthToken(final String accountType, final String authToken) {
if (accountType == null) throw new IllegalArgumentException("accountType is null");
try {
@@ -976,16 +955,15 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
- * @param account The account to fetch an auth token for
- * @param authTokenType The type of auth token to fetch, see {#getAuthToken}
+ * @param account The account for which an auth token is to be fetched. Cannot be {@code null}.
+ * @param authTokenType The type of auth token to fetch. Cannot be {@code null}.
* @return The cached auth token for this account and type, or null if
* no auth token is cached or the account does not exist.
+ * @see #getAuthToken
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public String peekAuthToken(final Account account, final String authTokenType) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
@@ -1005,14 +983,12 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
- * @param account The account to set a password for
+ * @param account The account whose password is to be set. Cannot be {@code null}.
* @param password The password to set, null to clear the password
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setPassword(final Account account, final String password) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -1030,14 +1006,14 @@
* permissions, and may be used by applications or management interfaces
* to "sign out" from an account.
*
- * <p>It is safe to call this method from the main thread.
+ * <p>This method only successfully clear the account's password when the
+ * caller has the same signature as the authenticator that owns the
+ * specified account. Otherwise, this method will silently fail.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}
+ * <p>It is safe to call this method from the main thread.
*
* @param account The account whose password to clear
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public void clearPassword(final Account account) {
if (account == null) throw new IllegalArgumentException("account is null");
try {
@@ -1055,15 +1031,13 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
- * @param account The account to set the userdata for
- * @param key The userdata key to set. Must not be null
- * @param value The value to set, null to clear this userdata key
+ * @param account Account whose user data is to be set. Must not be {@code null}.
+ * @param key String user data key to set. Must not be null
+ * @param value String value to set, {@code null} to clear this user data key
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setUserData(final Account account, final String key, final String value) {
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
@@ -1083,15 +1057,13 @@
*
* <p>It is safe to call this method from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS}
- * and to have the same UID as the account's authenticator.
+ * <p>This method requires the caller to have a signature match with the
+ * authenticator that manages the specified account.
*
* @param account The account to set an auth token for
* @param authTokenType The type of the auth token, see {#getAuthToken}
* @param authToken The auth token to add to the cache
*/
- @RequiresPermission(AUTHENTICATE_ACCOUNTS)
public void setAuthToken(Account account, final String authTokenType, final String authToken) {
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
@@ -1110,9 +1082,6 @@
* <p>This method may block while a network request completes, and must
* never be made from the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, see {@link #getAuthToken getAuthToken()}
* @param notifyAuthFailure If true, display a notification and return null
@@ -1126,7 +1095,6 @@
* @throws java.io.IOException if the authenticator experienced an I/O problem
* creating a new auth token, usually because of network trouble
*/
- @RequiresPermission(USE_CREDENTIALS)
public String blockingGetAuthToken(Account account, String authTokenType,
boolean notifyAuthFailure)
throws OperationCanceledException, IOException, AuthenticatorException {
@@ -1165,9 +1133,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1201,7 +1166,6 @@
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
*/
- @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle options,
final Activity activity, AccountManagerCallback<Bundle> callback, Handler handler) {
@@ -1253,9 +1217,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1292,7 +1253,6 @@
* boolean, AccountManagerCallback, android.os.Handler)} instead
*/
@Deprecated
- @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType,
final boolean notifyAuthFailure,
@@ -1333,9 +1293,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#USE_CREDENTIALS}.
- *
* @param account The account to fetch an auth token for
* @param authTokenType The auth token type, an authenticator-dependent
* string token, must not be null
@@ -1371,7 +1328,6 @@
* authenticator-dependent. The caller should verify the validity of the
* account before requesting an auth token.
*/
- @RequiresPermission(USE_CREDENTIALS)
public AccountManagerFuture<Bundle> getAuthToken(
final Account account, final String authTokenType, final Bundle options,
final boolean notifyAuthFailure,
@@ -1401,9 +1357,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
* @param accountType The type of account to add; must not be null
* @param authTokenType The type of auth token (see {@link #getAuthToken})
* this account will need to be able to generate, null for none
@@ -1441,7 +1394,6 @@
* creating a new account, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> addAccount(final String accountType,
final String authTokenType, final String[] requiredFeatures,
final Bundle addAccountOptions,
@@ -1586,9 +1538,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
* @param account The account to confirm password knowledge for
* @param options Authenticator-specific options for the request;
* if the {@link #KEY_PASSWORD} string field is present, the
@@ -1615,11 +1564,11 @@
* If no activity or password was specified, the returned Bundle contains
* {@link #KEY_INTENT} with the {@link Intent} needed to launch the
* password prompt.
- *
+ *
* <p>Also the returning Bundle may contain {@link
* #KEY_LAST_AUTHENTICATED_TIME} indicating the last time the
* credential was validated/created.
- *
+ *
* If an error occurred,{@link AccountManagerFuture#getResult()} throws:
* <ul>
* <li> {@link AuthenticatorException} if the authenticator failed to respond
@@ -1629,7 +1578,6 @@
* verifying the password, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> confirmCredentials(final Account account,
final Bundle options,
final Activity activity,
@@ -1668,9 +1616,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
* @param account The account to update credentials for
* @param authTokenType The credentials entered must allow an auth token
* of this type to be created (but no actual auth token is returned);
@@ -1706,7 +1651,6 @@
* verifying the password, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> updateCredentials(final Account account,
final String authTokenType,
final Bundle options, final Activity activity,
@@ -1729,8 +1673,8 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
+ * <p>This method requires the caller to have the same signature as the
+ * authenticator associated with the specified account type.
*
* @param accountType The account type associated with the authenticator
* to adjust
@@ -1758,7 +1702,6 @@
* updating settings, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> editProperties(final String accountType,
final Activity activity, final AccountManagerCallback<Bundle> callback,
final Handler handler) {
@@ -2253,9 +2196,6 @@
* <p>This method may be called from any thread, but the returned
* {@link AccountManagerFuture} must not be used on the main thread.
*
- * <p>This method requires the caller to hold the permission
- * {@link android.Manifest.permission#MANAGE_ACCOUNTS}.
- *
* @param accountType The account type required
* (see {@link #getAccountsByType}), must not be null
* @param authTokenType The desired auth token type
@@ -2292,7 +2232,6 @@
* updating settings, usually because of network trouble
* </ul>
*/
- @RequiresPermission(MANAGE_ACCOUNTS)
public AccountManagerFuture<Bundle> getAuthTokenByFeatures(
final String accountType, final String authTokenType, final String[] features,
final Activity activity, final Bundle addAccountOptions,
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 41e3db8..cb1e7aa 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -31,6 +31,7 @@
import android.content.pm.ComponentInfo;
import android.content.pm.ContainerEncryptionParams;
import android.content.pm.FeatureInfo;
+import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageInstallObserver;
@@ -88,6 +89,7 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Objects;
/*package*/
@@ -1048,6 +1050,38 @@
}
}
+ @Override
+ public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+ synchronized (mPermissionListeners) {
+ if (mPermissionListeners.get(listener) != null) {
+ return;
+ }
+ OnPermissionsChangeListenerDelegate delegate =
+ new OnPermissionsChangeListenerDelegate(listener, Looper.getMainLooper());
+ try {
+ mPM.addOnPermissionsChangeListener(delegate);
+ mPermissionListeners.put(listener, delegate);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+ }
+
+ @Override
+ public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+ synchronized (mPermissionListeners) {
+ IOnPermissionsChangeListener delegate = mPermissionListeners.get(listener);
+ if (delegate != null) {
+ try {
+ mPM.removeOnPermissionsChangeListener(delegate);
+ mPermissionListeners.remove(listener);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Package manager has died", e);
+ }
+ }
+ }
+ }
+
static void configurationChanged() {
synchronized (sSync) {
sIconCache.clear();
@@ -2139,4 +2173,39 @@
= new ArrayMap<ResourceName, WeakReference<Drawable.ConstantState>>();
private static ArrayMap<ResourceName, WeakReference<CharSequence>> sStringCache
= new ArrayMap<ResourceName, WeakReference<CharSequence>>();
+
+ private final Map<OnPermissionsChangedListener, IOnPermissionsChangeListener>
+ mPermissionListeners = new ArrayMap<>();
+
+ public class OnPermissionsChangeListenerDelegate extends IOnPermissionsChangeListener.Stub
+ implements Handler.Callback{
+ private static final int MSG_PERMISSIONS_CHANGED = 1;
+
+ private final OnPermissionsChangedListener mListener;
+ private final Handler mHandler;
+
+
+ public OnPermissionsChangeListenerDelegate(OnPermissionsChangedListener listener,
+ Looper looper) {
+ mListener = listener;
+ mHandler = new Handler(looper, this);
+ }
+
+ @Override
+ public void onPermissionsChanged(int uid) {
+ mHandler.obtainMessage(MSG_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
+ }
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_PERMISSIONS_CHANGED: {
+ final int uid = msg.arg1;
+ mListener.onPermissionsChanged(uid);
+ return true;
+ }
+ }
+ return false;
+ }
+ }
}
diff --git a/core/java/android/app/admin/DeviceInitializerStatus.java b/core/java/android/app/admin/DeviceInitializerStatus.java
deleted file mode 100644
index 7de518b..0000000
--- a/core/java/android/app/admin/DeviceInitializerStatus.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app.admin;
-
-/**
- * Defines constants designating device provisioning status used with {@link
- * android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}.
- *
- * This class contains flag constants that define special status codes:
- * <ul>
- * <li>{@link #FLAG_STATUS_ERROR} is used to define provisioning error status codes
- * <li>{@link #FLAG_STATUS_CUSTOM} is used to define custom status codes
- * <li>{@link #FLAG_STATUS_HIGH_PRIORITY} is used to define high priority status codes
- * </ul>
- *
- * <p>Status codes used by ManagedProvisioning are also defined in this class. These status codes
- * include provisioning errors and status codes.
- * <ul>
- * <li>{@link #STATUS_ERROR_CONNECT_WIFI}
- * <li>{@link #STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING}
- * <li>{@link #STATUS_ERROR_DOWNLOAD_PACKAGE}
- * <li>{@link #STATUS_ERROR_INSTALL_PACKAGE}
- * <li>{@link #STATUS_ERROR_SET_DEVICE_POLICY}
- * <li>{@link #STATUS_ERROR_DELETE_APPS}
- * <li>{@link #STATUS_ERROR_DOUBLE_BUMP}
- * <li>{@link #STATUS_STATE_CONNECTING_BLUETOOTH_PROXY}
- * <li>{@link #STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY}
- * <li>{@link #STATUS_STATE_DEVICE_PROVISIONED}
- * </ul>
- */
-public class DeviceInitializerStatus {
- /**
- * A flag used to designate an error status.
- *
- * <p>This flag is used with {@code statusCode} values sent through
- * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
- * @see #isErrorStatus(int)
- */
- public static final int FLAG_STATUS_ERROR = 0x01000000;
-
- /**
- * A flag used to designate a custom status. Custom status codes will be defined by device
- * initializer agents.
- *
- * <p>This flag is used with {@code statusCode} values sent through
- * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
- * @see #isCustomStatus(int)
- */
- public static final int FLAG_STATUS_CUSTOM = 0x02000000;
-
- /**
- * A bit flag used to designate a reserved status. Reserved status codes will not be defined
- * in AOSP.
- *
- * <p>This flag is used with {@code statusCode} values sent through
- * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
- */
- public static final int FLAG_STATUS_RESERVED = 0x04000000;
-
- /**
- * A flag used to indicate that a status message is high priority.
- *
- * <p>This flag is used with {@code statusCode} values sent through
- * {@link android.app.admin.DevicePolicyManager#sendDeviceInitializerStatus(int,String)}
- * @see #isHighPriority(int)
- */
- public static final int FLAG_STATUS_HIGH_PRIORITY = 0x08000000;
-
- /**
- * Device provisioning status code that indicates that a device is connecting to establish
- * a Bluetooth network proxy.
- */
- public static final int STATUS_STATE_CONNECTING_BLUETOOTH_PROXY = FLAG_STATUS_HIGH_PRIORITY | 8;
-
- /**
- * Device provisioning status code that indicates that a connected Bluetooth network proxy
- * is being shut down.
- */
- public static final int STATUS_STATE_DISCONNECTING_BLUETOOTH_PROXY = FLAG_STATUS_HIGH_PRIORITY | 9;
-
- /**
- * Device provisioning status code that indicates that a device has been successfully
- * provisioned.
- */
- public static final int STATUS_STATE_DEVICE_PROVISIONED = FLAG_STATUS_HIGH_PRIORITY | 10;
-
- /**
- * Device provisioning error status code that indicates that a device could not connect to
- * a Wi-Fi network.
- */
- public static final int STATUS_ERROR_CONNECT_WIFI = FLAG_STATUS_ERROR | 21;
-
- /**
- * Device provisioning error status indicating that factory reset protection is enabled on
- * the provisioned device and cannot be disabled with the provided data.
- */
- public static final int STATUS_ERROR_RESET_PROTECTION_BLOCKING_PROVISIONING =
- FLAG_STATUS_ERROR | 22;
-
- /**
- * Device provisioning error status indicating that device administrator and device initializer
- * packages could not be downloaded and verified successfully.
- */
- public static final int STATUS_ERROR_DOWNLOAD_PACKAGE = FLAG_STATUS_ERROR | 23;
-
- /**
- * Device provisioning error status indicating that device owner and device initializer packages
- * could not be installed.
- */
- public static final int STATUS_ERROR_INSTALL_PACKAGE = FLAG_STATUS_ERROR | 24;
-
- /**
- * Device provisioning error status indicating that the device owner or device initializer
- * components could not be set.
- */
- public static final int STATUS_ERROR_SET_DEVICE_POLICY = FLAG_STATUS_ERROR | 25;
-
- /**
- * Device provisioning error status indicating that deleting non-required applications during
- * provisioning failed.
- */
- public static final int STATUS_ERROR_DELETE_APPS = FLAG_STATUS_ERROR | 26;
-
- /**
- * Device provisioning error status code that indicates that a provisioning attempt has failed
- * because the device has already been provisioned or that provisioning has already started.
- */
- public static final int STATUS_ERROR_DOUBLE_BUMP = FLAG_STATUS_ERROR | 30;
-
- private DeviceInitializerStatus() {}
-}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index bf44746..996748a 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -540,50 +540,6 @@
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_CERTIFICATE_CHECKSUM";
/**
- * A String extra holding the MAC address of the Bluetooth device to connect to with status
- * updates during provisioning.
- *
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
- * provisioning via an NFC bump.
- */
- public static final String EXTRA_PROVISIONING_BT_MAC_ADDRESS
- = "android.app.extra.PROVISIONING_BT_MAC_ADDRESS";
-
- /**
- * A String extra holding the Bluetooth service UUID on the device to connect to with status
- * updates during provisioning.
- *
- * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
- *
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
- * provisioning via an NFC bump.
- */
- public static final String EXTRA_PROVISIONING_BT_UUID
- = "android.app.extra.PROVISIONING_BT_UUID";
-
- /**
- * A String extra holding a unique identifier used to identify the device connecting over
- * Bluetooth. This identifier will be part of every status message sent to the remote device.
- *
- * <p>This value must be specified when {@code #EXTRA_PROVISIONING_BT_MAC_ADDRESS} is present.
- *
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
- * provisioning via an NFC bump.
- */
- public static final String EXTRA_PROVISIONING_BT_DEVICE_ID
- = "android.app.extra.PROVISIONING_BT_DEVICE_ID";
-
- /**
- * A Boolean extra that that will cause a provisioned device to temporarily proxy network
- * traffic over Bluetooth. When a Wi-Fi network is available, the network proxy will stop.
- *
- * <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC_V2} that starts device owner
- * provisioning via an NFC bump.
- */
- public static final String EXTRA_PROVISIONING_BT_USE_PROXY
- = "android.app.extra.PROVISIONING_BT_USE_PROXY";
-
- /**
* A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
* holds data needed by the system to wipe factory reset protection. The data needed to wipe
* the device depend on the installed factory reset protection implementation. For example,
@@ -665,11 +621,7 @@
* Replaces {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}. The value of the property
* should be converted to a String via
* {@link android.content.ComponentName#flattenToString()}</li>
- * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_BT_MAC_ADDRESS}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_BT_UUID}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_BT_DEVICE_ID}, optional</li>
- * <li>{@link #EXTRA_PROVISIONING_BT_USE_PROXY}, optional</li></ul>
+ * <li>{@link #EXTRA_PROVISIONING_DEVICE_ADMIN_MINIMUM_VERSION_CODE}, optional</li></ul>
*
* <p> When device owner provisioning has completed, an intent of the type
* {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
@@ -727,45 +679,6 @@
= "android.app.action.SET_PROFILE_OWNER";
/**
- * Protected broadcast action that will be sent to managed provisioning to notify it that a
- * status update has been reported by the device initializer. The status update will be
- * reported to the remote setup device over Bluetooth.
- *
- * <p>Broadcasts with this action must supply a
- * {@linkplain DeviceInitializerStatus#FLAG_STATUS_CUSTOM custom} status code in the
- * {@link EXTRA_DEVICE_INITIALIZER_STATUS_CODE} extra.
- *
- * <p>Broadcasts may optionally contain a description in the
- * {@link EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION} extra.
- * @hide
- */
- @SystemApi
- public static final String ACTION_SEND_DEVICE_INITIALIZER_STATUS
- = "android.app.action.SEND_DEVICE_INITIALIZER_STATUS";
-
- /**
- * An integer extra that contains the status code that defines a status update. This extra must
- * sent as part of a broadcast with an action of {@code ACTION_SEND_DEVICE_INITIALIZER_STATUS}.
- *
- * <p>The status code sent with this extra must be a custom status code as defined by
- * {@link DeviceInitializerStatus#FLAG_STATUS_CUSTOM}.
- * @hide
- */
- @SystemApi
- public static final String EXTRA_DEVICE_INITIALIZER_STATUS_CODE
- = "android.app.extra.DEVICE_INITIALIZER_STATUS_CODE";
-
- /**
- * A {@code String} extra that contains an optional description accompanying a status update.
- * This extra my be sent as part of a broadcast with an action of
- * {@code ACTION_SEND_DEVICE_INITIALIZER_STATUS}.
- * @hide
- */
- @SystemApi
- public static final String EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION
- = "android.app.extra.DEVICE_INITIALIZER_STATUS_DESCRIPTION";
-
- /**
* @hide
* Name of the profile owner admin that controls the user.
*/
@@ -3975,6 +3888,9 @@
* <p>Any packages that shares uid with an allowed package will also be allowed
* to activate lock task.
*
+ * From {@link android.os.Build.VERSION_CODES#MNC} removing packages from the lock task
+ * package list results in locked tasks belonging to those packages to be finished.
+ *
* This function can only be called by the device owner.
* @param packages The list of packages allowed to enter lock task mode
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -4288,21 +4204,6 @@
}
/**
- * Called by device initializer to send a provisioning status update to the remote setup device.
- *
- * @param statusCode a custom status code value as defined by
- * {@link DeviceInitializerStatus#FLAG_STATUS_CUSTOM}.
- * @param description custom description of the status code sent
- */
- public void sendDeviceInitializerStatus(int statusCode, String description) {
- try {
- mService.sendDeviceInitializerStatus(statusCode, description);
- } catch (RemoteException re) {
- Log.w(TAG, "Could not send device initializer status", re);
- }
- }
-
- /**
* Called by device owners to set a local system update policy. When a new policy is set,
* {@link #ACTION_SYSTEM_UPDATE_POLICY_CHANGED} is broadcasted.
*
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index a700806..376a3d8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -220,7 +220,6 @@
void setUserIcon(in ComponentName admin, in Bitmap icon);
- void sendDeviceInitializerStatus(int statusCode, String description);
void setSystemUpdatePolicy(in ComponentName who, in SystemUpdatePolicy policy);
SystemUpdatePolicy getSystemUpdatePolicy();
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index 49ac062..fd1e24a 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -28,6 +28,11 @@
import java.util.HashMap;
import java.util.Map;
+/**
+ * Represents a single operation to be performed as part of a batch of operations.
+ *
+ * @see ContentProvider#applyBatch(ArrayList)
+ */
public class ContentProviderOperation implements Parcelable {
/** @hide exposed for unit tests */
public final static int TYPE_INSERT = 1;
@@ -195,10 +200,19 @@
return new Builder(TYPE_ASSERT, uri);
}
+ /**
+ * Gets the Uri for the target of the operation.
+ */
public Uri getUri() {
return mUri;
}
+ /**
+ * Returns true if the operation allows yielding the database to other transactions
+ * if the database is contended.
+ *
+ * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely()
+ */
public boolean isYieldAllowed() {
return mYieldAllowed;
}
@@ -208,26 +222,58 @@
return mType;
}
+ /**
+ * Returns true if the operation represents an insertion.
+ *
+ * @see #newInsert
+ */
public boolean isInsert() {
return mType == TYPE_INSERT;
}
+ /**
+ * Returns true if the operation represents a deletion.
+ *
+ * @see #newDelete
+ */
public boolean isDelete() {
return mType == TYPE_DELETE;
}
+ /**
+ * Returns true if the operation represents an update.
+ *
+ * @see #newUpdate
+ */
public boolean isUpdate() {
return mType == TYPE_UPDATE;
}
+ /**
+ * Returns true if the operation represents an assert query.
+ *
+ * @see #newAssertQuery
+ */
public boolean isAssertQuery() {
return mType == TYPE_ASSERT;
}
+ /**
+ * Returns true if the operation represents an insertion, deletion, or update.
+ *
+ * @see #isInsert
+ * @see #isDelete
+ * @see #isUpdate
+ */
public boolean isWriteOperation() {
return mType == TYPE_DELETE || mType == TYPE_INSERT || mType == TYPE_UPDATE;
}
+ /**
+ * Returns true if the operation represents an assert query.
+ *
+ * @see #isAssertQuery
+ */
public boolean isReadOperation() {
return mType == TYPE_ASSERT;
}
@@ -617,7 +663,7 @@
}
/**
- * If set then if the number of rows affected by this operation do not match
+ * If set then if the number of rows affected by this operation does not match
* this count {@link OperationApplicationException} will be throw.
* This can only be used with builders of type update, delete, or assert.
* @return this builder, to allow for chaining.
@@ -631,6 +677,12 @@
return this;
}
+ /**
+ * If set to true then the operation allows yielding the database to other transactions
+ * if the database is contended.
+ * @return this builder, to allow for chaining.
+ * @see android.database.sqlite.SQLiteDatabase#yieldIfContendedSafely()
+ */
public Builder withYieldAllowed(boolean yieldAllowed) {
mYieldAllowed = yieldAllowed;
return this;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a434c7b..970623a 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1256,7 +1256,7 @@
* @param intent The description of the activity to start.
*
* @throws ActivityNotFoundException
- *
+ *`
* @see #startActivity(Intent, Bundle)
* @see PackageManager#resolveActivity
*/
@@ -2443,8 +2443,6 @@
*
* @param serviceClass The class of the desired service.
* @return The service name or null if the class is not a supported system service.
- *
- * @hide
*/
public abstract String getSystemServiceName(Class<?> serviceClass);
diff --git a/core/java/android/content/pm/IOnPermissionsChangeListener.aidl b/core/java/android/content/pm/IOnPermissionsChangeListener.aidl
new file mode 100644
index 0000000..7791b50
--- /dev/null
+++ b/core/java/android/content/pm/IOnPermissionsChangeListener.aidl
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+/**
+ * Listener for changes in the permissions for installed packages.
+ * {@hide}
+ */
+oneway interface IOnPermissionsChangeListener {
+ void onPermissionsChanged(int uid);
+}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 00b8c71..0c07bc3 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -31,6 +31,7 @@
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.IPackageStatsObserver;
+import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IntentFilterVerificationInfo;
import android.content.pm.InstrumentationInfo;
import android.content.pm.KeySet;
@@ -490,4 +491,7 @@
KeySet getSigningKeySet(String packageName);
boolean isPackageSignedByKeySet(String packageName, in KeySet ks);
boolean isPackageSignedByKeySetExactly(String packageName, in KeySet ks);
+
+ void addOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
+ void removeOnPermissionsChangeListener(in IOnPermissionsChangeListener listener);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 68092c8..bd50ca0 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -16,11 +16,13 @@
package android.content.pm;
+import android.Manifest;
import android.annotation.CheckResult;
import android.annotation.DrawableRes;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.StringRes;
@@ -78,6 +80,21 @@
}
/**
+ * Listener for changes in permissions granted to a UID.
+ *
+ * @hide
+ */
+ @SystemApi
+ public interface OnPermissionsChangedListener {
+
+ /**
+ * Called when the permissions for a UID change.
+ * @param uid The UID with a change.
+ */
+ public void onPermissionsChanged(int uid);
+ }
+
+ /**
* {@link PackageInfo} flag: return information about
* activities in the package in {@link PackageInfo#activities}.
*/
@@ -2636,7 +2653,7 @@
/**
* Retrieve the official name associated with a user id. This name is
- * guaranteed to never change, though it is possibly for the underlying
+ * guaranteed to never change, though it is possible for the underlying
* user id to be changed. That is, if you are storing information about
* user ids in persistent storage, you should use the string returned
* by this function instead of the raw user-id.
@@ -4295,6 +4312,27 @@
public abstract boolean isSafeMode();
/**
+ * Adds a listener for permission changes for installed packages.
+ *
+ * @param listener The listener to add.
+ *
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
+ public abstract void addOnPermissionsChangeListener(OnPermissionsChangedListener listener);
+
+ /**
+ * Remvoes a listener for permission changes for installed packages.
+ *
+ * @param listener The listener to remove.
+ *
+ * @hide
+ */
+ @SystemApi
+ public abstract void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener);
+
+ /**
* Return the {@link KeySet} associated with the String alias for this
* application.
*
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index e47220b..5f46c73 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -24,8 +24,13 @@
import android.util.Log;
import android.util.SparseArray;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Protocol;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
/**
* A NetworkFactory is an entity that creates NetworkAgent objects.
* The bearers register with ConnectivityService using {@link #register} and
@@ -157,6 +162,11 @@
this.score = score;
this.requested = false;
}
+
+ @Override
+ public String toString() {
+ return "{" + request + ", score=" + score + ", requested=" + requested + "}";
+ }
}
private void handleAddRequest(NetworkRequest request, int score) {
@@ -176,9 +186,9 @@
private void handleRemoveRequest(NetworkRequest request) {
NetworkRequestInfo n = mNetworkRequests.get(request.requestId);
- if (n != null && n.requested) {
+ if (n != null) {
mNetworkRequests.remove(request.requestId);
- releaseNetworkFor(n.request);
+ if (n.requested) releaseNetworkFor(n.request);
}
}
@@ -273,15 +283,31 @@
sendMessage(obtainMessage(CMD_SET_FILTER, new NetworkCapabilities(netCap)));
}
+ @VisibleForTesting
+ protected int getRequestCount() {
+ return mNetworkRequests.size();
+ }
+
protected void log(String s) {
Log.d(LOG_TAG, s);
}
+ public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
+ final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
+ pw.println(toString());
+ pw.increaseIndent();
+ for (int i = 0; i < mNetworkRequests.size(); i++) {
+ pw.println(mNetworkRequests.valueAt(i));
+ }
+ pw.decreaseIndent();
+ }
+
@Override
public String toString() {
StringBuilder sb = new StringBuilder("{").append(LOG_TAG).append(" - ScoreFilter=").
append(mScore).append(", Filter=").append(mCapabilityFilter).append(", requests=").
- append(mNetworkRequests.size()).append("}");
+ append(mNetworkRequests.size()).append(", refCount=").append(mRefCount).
+ append("}");
return sb.toString();
}
}
diff --git a/core/java/android/os/RemoteCallbackList.java b/core/java/android/os/RemoteCallbackList.java
index d2a9cdc..5849350 100644
--- a/core/java/android/os/RemoteCallbackList.java
+++ b/core/java/android/os/RemoteCallbackList.java
@@ -77,7 +77,6 @@
public boolean register(E callback) {
return register(callback, null);
}
-
/**
* Add a new callback to the list. This callback will remain in the list
* until a corresponding call to {@link #unregister} or its hosting process
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 4bd085f..979c828 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -16,6 +16,7 @@
package android.preference;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -31,6 +32,7 @@
import android.os.Message;
import android.preference.VolumePreference.VolumeStore;
import android.provider.Settings;
+import android.provider.Settings.Global;
import android.provider.Settings.System;
import android.util.Log;
import android.widget.SeekBar;
@@ -46,7 +48,7 @@
public interface Callback {
void onSampleStarting(SeekBarVolumizer sbv);
void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch);
- void onMuted(boolean muted);
+ void onMuted(boolean muted, boolean zenMuted);
}
private final Context mContext;
@@ -54,6 +56,7 @@
private final Callback mCallback;
private final Uri mDefaultUri;
private final AudioManager mAudioManager;
+ private final NotificationManager mNotificationManager;
private final int mStreamType;
private final int mMaxStreamVolume;
private boolean mAffectedByRingerMode;
@@ -63,12 +66,14 @@
private Handler mHandler;
private Observer mVolumeObserver;
private int mOriginalStreamVolume;
+ private int mLastAudibleStreamVolume;
private Ringtone mRingtone;
private int mLastProgress = -1;
private boolean mMuted;
private SeekBar mSeekBar;
private int mVolumeBeforeMute = -1;
private int mRingerMode;
+ private int mZenMode;
private static final int MSG_SET_STREAM_VOLUME = 0;
private static final int MSG_START_SAMPLE = 1;
@@ -78,19 +83,22 @@
public SeekBarVolumizer(Context context, int streamType, Uri defaultUri, Callback callback) {
mContext = context;
- mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager = context.getSystemService(AudioManager.class);
+ mNotificationManager = context.getSystemService(NotificationManager.class);
mStreamType = streamType;
mAffectedByRingerMode = mAudioManager.isStreamAffectedByRingerMode(mStreamType);
mNotificationOrRing = isNotificationOrRing(mStreamType);
if (mNotificationOrRing) {
mRingerMode = mAudioManager.getRingerModeInternal();
}
+ mZenMode = mNotificationManager.getZenMode();
mMaxStreamVolume = mAudioManager.getStreamMaxVolume(mStreamType);
mCallback = callback;
mOriginalStreamVolume = mAudioManager.getStreamVolume(mStreamType);
+ mLastAudibleStreamVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
mMuted = mAudioManager.isStreamMute(mStreamType);
if (mCallback != null) {
- mCallback.onMuted(mMuted);
+ mCallback.onMuted(mMuted, isZenMuted());
}
if (defaultUri == null) {
if (mStreamType == AudioManager.STREAM_RING) {
@@ -119,8 +127,17 @@
mSeekBar.setOnSeekBarChangeListener(this);
}
+ private boolean isZenMuted() {
+ return mNotificationOrRing && mZenMode == Global.ZEN_MODE_ALARMS
+ || mZenMode == Global.ZEN_MODE_NO_INTERRUPTIONS;
+ }
+
protected void updateSeekBar() {
- if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
+ final boolean zenMuted = isZenMuted();
+ mSeekBar.setEnabled(!zenMuted);
+ if (zenMuted) {
+ mSeekBar.setProgress(mLastAudibleStreamVolume);
+ } else if (mNotificationOrRing && mRingerMode == AudioManager.RINGER_MODE_VIBRATE) {
mSeekBar.setProgress(0);
} else if (mMuted) {
mSeekBar.setProgress(0);
@@ -316,11 +333,12 @@
if (msg.what == UPDATE_SLIDER) {
if (mSeekBar != null) {
mLastProgress = msg.arg1;
- final boolean muted = msg.arg2 != 0;
+ mLastAudibleStreamVolume = Math.abs(msg.arg2);
+ final boolean muted = msg.arg2 < 0;
if (muted != mMuted) {
mMuted = muted;
if (mCallback != null) {
- mCallback.onMuted(mMuted);
+ mCallback.onMuted(mMuted, isZenMuted());
}
}
updateSeekBar();
@@ -328,16 +346,18 @@
}
}
- public void postUpdateSlider(int volume, boolean mute) {
- obtainMessage(UPDATE_SLIDER, volume, mute ? 1 : 0).sendToTarget();
+ public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
+ final int arg2 = lastAudibleVolume * (mute ? -1 : 1);
+ obtainMessage(UPDATE_SLIDER, volume, arg2).sendToTarget();
}
}
private void updateSlider() {
if (mSeekBar != null && mAudioManager != null) {
final int volume = mAudioManager.getStreamVolume(mStreamType);
+ final int lastAudibleVolume = mAudioManager.getLastAudibleStreamVolume(mStreamType);
final boolean mute = mAudioManager.isStreamMute(mStreamType);
- mUiHandler.postUpdateSlider(volume, mute);
+ mUiHandler.postUpdateSlider(volume, lastAudibleVolume, mute);
}
}
@@ -362,6 +382,7 @@
if (listening) {
final IntentFilter filter = new IntentFilter(AudioManager.VOLUME_CHANGED_ACTION);
filter.addAction(AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION);
+ filter.addAction(NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED);
mContext.registerReceiver(this, filter);
} else {
mContext.unregisterReceiver(this);
@@ -379,7 +400,7 @@
if (mSeekBar != null && streamMatch && streamValue != -1) {
final boolean muted = mAudioManager.isStreamMute(mStreamType)
|| streamValue == 0;
- mUiHandler.postUpdateSlider(streamValue, muted);
+ mUiHandler.postUpdateSlider(streamValue, mLastAudibleStreamVolume, muted);
}
} else if (AudioManager.INTERNAL_RINGER_MODE_CHANGED_ACTION.equals(action)) {
if (mNotificationOrRing) {
@@ -388,6 +409,9 @@
if (mAffectedByRingerMode) {
updateSlider();
}
+ } else if (NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED.equals(action)) {
+ mZenMode = mNotificationManager.getZenMode();
+ updateSlider();
}
}
}
diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java
index 573499a..8a66c24 100644
--- a/core/java/android/preference/VolumePreference.java
+++ b/core/java/android/preference/VolumePreference.java
@@ -161,7 +161,7 @@
}
@Override
- public void onMuted(boolean muted) {
+ public void onMuted(boolean muted, boolean zenMuted) {
// noop
}
diff --git a/core/java/android/printservice/PrintService.java b/core/java/android/printservice/PrintService.java
index 527c8ae..6295822 100644
--- a/core/java/android/printservice/PrintService.java
+++ b/core/java/android/printservice/PrintService.java
@@ -231,6 +231,19 @@
*/
public static final String EXTRA_PRINTER_INFO = "android.intent.extra.print.EXTRA_PRINTER_INFO";
+ /**
+ * If you declared an optional activity with advanced print options via the
+ * {@link android.R.attr#advancedPrintOptionsActivity advancedPrintOptionsActivity}
+ * attribute, this extra is used to pass in the meta-data for the currently printed
+ * document as a {@link android.print.PrintDocumentInfo} to your activity allowing
+ * you to inspect it.
+ *
+ * @see #EXTRA_PRINT_JOB_INFO
+ * @see #EXTRA_PRINTER_INFO
+ */
+ public static final String EXTRA_PRINT_DOCUMENT_INFO =
+ "android.printservice.extra.PRINT_DOCUMENT_INFO";
+
private Handler mHandler;
private IPrintServiceClient mClient;
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index dc8cadf..1c67ba7 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -25,11 +25,8 @@
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Xml;
@@ -337,11 +334,6 @@
private ActionProvider itemActionProvider;
- private ColorStateList itemIconTintList;
- private boolean itemIconTintListSet;
- private PorterDuff.Mode itemIconTintMode;
- private boolean itemIconTintModeSet;
-
private static final int defaultGroupId = NO_ID;
private static final int defaultItemId = NO_ID;
private static final int defaultItemCategory = 0;
@@ -432,23 +424,6 @@
itemActionProvider = null;
}
- if (a.hasValueOrEmpty(com.android.internal.R.styleable.MenuItem_iconTint)) {
- itemIconTintList = a.getColorStateList(
- com.android.internal.R.styleable.MenuItem_iconTint);
- itemIconTintListSet = true;
- } else {
- itemIconTintList = null;
- itemIconTintListSet = false;
- }
- if (a.hasValueOrEmpty(com.android.internal.R.styleable.MenuItem_iconTintMode)) {
- itemIconTintMode = Drawable.parseTintMode(
- a.getInt(com.android.internal.R.styleable.MenuItem_iconTintMode, -1), null);
- itemIconTintModeSet = true;
- } else {
- itemIconTintMode = null;
- itemIconTintModeSet = false;
- }
-
a.recycle();
itemAdded = false;
@@ -511,13 +486,6 @@
if (itemActionProvider != null) {
item.setActionProvider(itemActionProvider);
}
-
- if (itemIconTintListSet) {
- item.setIconTintList(itemIconTintList);
- }
- if (itemIconTintModeSet) {
- item.setIconTintMode(itemIconTintMode);
- }
}
public MenuItem addItem() {
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index 2948007..9e8b97e 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -21,8 +21,6 @@
import android.annotation.StringRes;
import android.app.Activity;
import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.view.ContextMenu.ContextMenuInfo;
import android.view.View.OnCreateContextMenuListener;
@@ -601,26 +599,4 @@
* @return This menu item instance for call chaining
*/
public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
-
- /**
- * Applies a tint to the icon drawable. Does not modify the current tint
- * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- * <p>
- * Subsequent calls to {@link android.view.MenuItem#setIcon(android.graphics.drawable.Drawable)}
- * will automatically mutate the drawable and apply the specified tint and tint mode.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- * @return This menu item instance for call chaining
- */
- public MenuItem setIconTintList(ColorStateList tint);
-
- /**
- * Specifies the blending mode used to apply the tint specified by {@link
- * #setIconTintList(ColorStateList)} to the icon drawable. The default mode is {@link
- * PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
- * @return This menu item instance for call chaining
- */
- public MenuItem setIconTintMode(PorterDuff.Mode tintMode);
}
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index f08141c..a5696ee 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -21,10 +21,8 @@
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -64,6 +62,8 @@
private static final boolean ACTIONBAR_ANIMATIONS_ENABLED = false;
private OverflowMenuButton mOverflowButton;
+ private Drawable mPendingOverflowIcon;
+ private boolean mPendingOverflowIconSet;
private boolean mReserveOverflow;
private boolean mReserveOverflowSet;
private int mWidthLimit;
@@ -85,8 +85,6 @@
private OpenOverflowRunnable mPostedOpenRunnable;
private ActionMenuPopupCallback mPopupCallback;
- private TintInfo mOverflowTintInfo;
-
final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
int mOpenSubMenuId;
@@ -154,9 +152,13 @@
if (mReserveOverflow) {
if (mOverflowButton == null) {
mOverflowButton = new OverflowMenuButton(mSystemContext);
+ if (mPendingOverflowIconSet) {
+ mOverflowButton.setImageDrawable(mPendingOverflowIcon);
+ mPendingOverflowIcon = null;
+ mPendingOverflowIconSet = false;
+ }
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
mOverflowButton.measure(spec, spec);
- applyOverflowTint();
}
width -= mOverflowButton.getMeasuredWidth();
} else {
@@ -198,6 +200,24 @@
mExpandedActionViewsExclusive = isExclusive;
}
+ public void setOverflowIcon(Drawable icon) {
+ if (mOverflowButton != null) {
+ mOverflowButton.setImageDrawable(icon);
+ } else {
+ mPendingOverflowIconSet = true;
+ mPendingOverflowIcon = icon;
+ }
+ }
+
+ public Drawable getOverflowIcon() {
+ if (mOverflowButton != null) {
+ return mOverflowButton.getDrawable();
+ } else if (mPendingOverflowIconSet) {
+ return mPendingOverflowIcon;
+ }
+ return null;
+ }
+
@Override
public MenuView getMenuView(ViewGroup root) {
MenuView oldMenuView = mMenuView;
@@ -449,7 +469,6 @@
if (hasOverflow) {
if (mOverflowButton == null) {
mOverflowButton = new OverflowMenuButton(mSystemContext);
- applyOverflowTint();
}
ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
if (parent != mMenuView) {
@@ -764,40 +783,6 @@
}
}
- public void setOverflowTintList(ColorStateList tint) {
- if (mOverflowTintInfo == null) {
- mOverflowTintInfo = new TintInfo();
- }
- mOverflowTintInfo.mTintList = tint;
- mOverflowTintInfo.mHasTintList = true;
-
- applyOverflowTint();
- }
-
- public void setOverflowTintMode(PorterDuff.Mode tintMode) {
- if (mOverflowTintInfo == null) {
- mOverflowTintInfo = new TintInfo();
- }
- mOverflowTintInfo.mTintMode = tintMode;
- mOverflowTintInfo.mHasTintMode = true;
-
- applyOverflowTint();
- }
-
- private void applyOverflowTint() {
- final TintInfo tintInfo = mOverflowTintInfo;
- if (tintInfo != null && (tintInfo.mHasTintList || tintInfo.mHasTintMode)) {
- if (mOverflowButton != null) {
- if (tintInfo.mHasTintList) {
- mOverflowButton.setImageTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mOverflowButton.setImageTintMode(tintInfo.mTintMode);
- }
- }
- }
- }
-
private static class SavedState implements Parcelable {
public int openSubMenuId;
@@ -1023,13 +1008,6 @@
}
}
- private static class TintInfo {
- ColorStateList mTintList;
- PorterDuff.Mode mTintMode;
- boolean mHasTintMode;
- boolean mHasTintList;
- }
-
/**
* This class holds layout information for a menu item. This is used to determine
* pre- and post-layout information about menu items, which will then be used to
@@ -1077,5 +1055,4 @@
this.animType = animType;
}
}
-
}
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 278a8fb..1f02c3b 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -16,11 +16,11 @@
package android.widget;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.StyleRes;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.Configuration;
-import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.ContextThemeWrapper;
import android.view.Gravity;
@@ -541,6 +541,27 @@
dismissPopupMenus();
}
+ /**
+ * Set the icon to use for the overflow button.
+ *
+ * @param icon Drawable to set, may be null to clear the icon
+ */
+ public void setOverflowIcon(@Nullable Drawable icon) {
+ getMenu();
+ mPresenter.setOverflowIcon(icon);
+ }
+
+ /**
+ * Return the current drawable used as the overflow icon.
+ *
+ * @return The overflow icon drawable
+ */
+ @Nullable
+ public Drawable getOverflowIcon() {
+ getMenu();
+ return mPresenter.getOverflowIcon();
+ }
+
/** @hide */
public boolean isOverflowReserved() {
return mReserveOverflow;
@@ -551,31 +572,6 @@
mReserveOverflow = reserveOverflow;
}
- /**
- * Applies a tint to the overflow drawable. Does not modify the current tint
- * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- */
- public void setOverflowTintList(ColorStateList tint) {
- if (mPresenter != null) {
- mPresenter.setOverflowTintList(tint);
- }
- }
-
- /**
- * Specifies the blending mode used to apply the tint specified by {@link
- * #setOverflowTintList(ColorStateList)} to the overflow drawable.
- * The default mode is {@link PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
- */
- public void setOverflowTintMode(PorterDuff.Mode tintMode) {
- if (mPresenter != null) {
- mPresenter.setOverflowTintMode(tintMode);
- }
- }
-
@Override
protected LayoutParams generateDefaultLayoutParams() {
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index 62d948d..8ace0f3 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -25,9 +25,8 @@
import android.annotation.StyleRes;
import android.app.ActionBar;
import android.content.Context;
-import android.content.res.ColorStateList;
import android.content.res.TypedArray;
-import android.graphics.PorterDuff;
+import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Parcel;
import android.os.Parcelable;
@@ -110,9 +109,6 @@
private ImageButton mNavButtonView;
private ImageView mLogoView;
- private TintInfo mOverflowTintInfo;
- private TintInfo mNavTintInfo;
-
private Drawable mCollapseIcon;
private CharSequence mCollapseDescription;
private ImageButton mCollapseButtonView;
@@ -275,21 +271,6 @@
if (!TextUtils.isEmpty(navDesc)) {
setNavigationContentDescription(navDesc);
}
-
- if (a.hasValue(R.styleable.Toolbar_overflowTint)) {
- setOverflowTintList(a.getColorStateList(R.styleable.Toolbar_overflowTint));
- }
- if (a.hasValue(R.styleable.Toolbar_overflowTintMode)) {
- setOverflowTintMode(Drawable.parseTintMode(
- a.getInt(R.styleable.Toolbar_overflowTintMode, -1), null));
- }
- if (a.hasValue(R.styleable.Toolbar_navigationTint)) {
- setNavigationTintList(a.getColorStateList(R.styleable.Toolbar_navigationTint));
- }
- if (a.hasValue(R.styleable.Toolbar_navigationTintMode)) {
- setNavigationTintMode(Drawable.parseTintMode(
- a.getInt(R.styleable.Toolbar_navigationTintMode, -1), null));
- }
a.recycle();
}
@@ -830,91 +811,6 @@
}
/**
- * Applies a tint to the icon drawable. Does not modify the current tint
- * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- * <p>
- * Subsequent calls to {@link #setNavigationIcon(Drawable)} will automatically mutate
- * the drawable and apply the specified tint and tint mode.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#Toolbar_navigationTint
- */
- public void setNavigationTintList(ColorStateList tint) {
- if (mNavTintInfo == null) {
- mNavTintInfo = new TintInfo();
- }
- mNavTintInfo.mTintList = tint;
- mNavTintInfo.mHasTintList = true;
-
- applyNavigationTint();
- }
-
- /**
- * Specifies the blending mode used to apply the tint specified by {@link
- * #setNavigationTintList(ColorStateList)} to the navigation drawable.
- * The default mode is {@link PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#Toolbar_navigationTintMode
- */
- public void setNavigationTintMode(PorterDuff.Mode tintMode) {
- if (mNavTintInfo == null) {
- mNavTintInfo = new TintInfo();
- }
- mNavTintInfo.mTintMode = tintMode;
- mNavTintInfo.mHasTintMode = true;
-
- applyNavigationTint();
- }
-
- /**
- * Applies a tint to the overflow drawable. Does not modify the current tint
- * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
- *
- * @param tint the tint to apply, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#Toolbar_overflowTint
- */
- public void setOverflowTintList(ColorStateList tint) {
- if (mMenuView != null) {
- // If the menu view is available, directly set the tint
- mMenuView.setOverflowTintList(tint);
- } else {
- // Otherwise we will record the value
- if (mOverflowTintInfo == null) {
- mOverflowTintInfo = new TintInfo();
- }
- mOverflowTintInfo.mTintList = tint;
- mOverflowTintInfo.mHasTintList = true;
- }
- }
-
- /**
- * Specifies the blending mode used to apply the tint specified by {@link
- * #setOverflowTintList(ColorStateList)} to the overflow drawable.
- * The default mode is {@link PorterDuff.Mode#SRC_IN}.
- *
- * @param tintMode the blending mode used to apply the tint, may be {@code null} to clear tint
- *
- * @attr ref android.R.styleable#Toolbar_overflowTintMode
- */
- public void setOverflowTintMode(PorterDuff.Mode tintMode) {
- if (mMenuView != null) {
- // If the menu view is available, directly set the tint mode
- mMenuView.setOverflowTintMode(tintMode);
- } else {
- // Otherwise we will record the value
- if (mOverflowTintInfo == null) {
- mOverflowTintInfo = new TintInfo();
- }
- mOverflowTintInfo.mTintMode = tintMode;
- mOverflowTintInfo.mHasTintMode = true;
- }
- }
-
- /**
* Return the Menu shown in the toolbar.
*
* <p>Applications that wish to populate the toolbar's menu can do so from here. To use
@@ -927,6 +823,27 @@
return mMenuView.getMenu();
}
+ /**
+ * Set the icon to use for the overflow button.
+ *
+ * @param icon Drawable to set, may be null to clear the icon
+ */
+ public void setOverflowIcon(@Nullable Drawable icon) {
+ ensureMenu();
+ mMenuView.setOverflowIcon(icon);
+ }
+
+ /**
+ * Return the current drawable used as the overflow icon.
+ *
+ * @return The overflow icon drawable
+ */
+ @Nullable
+ public Drawable getOverflowIcon() {
+ ensureMenu();
+ return mMenuView.getOverflowIcon();
+ }
+
private void ensureMenu() {
ensureMenuView();
if (mMenuView.peekMenu() == null) {
@@ -950,17 +867,6 @@
lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
mMenuView.setLayoutParams(lp);
addSystemView(mMenuView);
-
- if (mOverflowTintInfo != null) {
- // If we have tint info for the overflow, set it on the menu view now
- if (mOverflowTintInfo.mHasTintList) {
- mMenuView.setOverflowTintList(mOverflowTintInfo.mTintList);
- }
- if (mOverflowTintInfo.mHasTintMode) {
- mMenuView.setOverflowTintMode(mOverflowTintInfo.mTintMode);
- }
- mOverflowTintInfo = null;
- }
}
}
@@ -1114,7 +1020,6 @@
final LayoutParams lp = generateDefaultLayoutParams();
lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
mNavButtonView.setLayoutParams(lp);
- applyNavigationTint();
}
}
@@ -1133,7 +1038,6 @@
collapseActionView();
}
});
- applyNavigationTint();
}
}
@@ -1885,30 +1789,6 @@
return mPopupContext;
}
- private void applyNavigationTint() {
- final TintInfo tintInfo = mNavTintInfo;
- if (tintInfo != null && (tintInfo.mHasTintList || tintInfo.mHasTintMode)) {
- if (mNavButtonView != null) {
- if (tintInfo.mHasTintList) {
- mNavButtonView.setImageTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mNavButtonView.setImageTintMode(tintInfo.mTintMode);
- }
- }
-
- if (mCollapseButtonView != null) {
- // We will use the same tint for the collapse button
- if (tintInfo.mHasTintList) {
- mCollapseButtonView.setImageTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mCollapseButtonView.setImageTintMode(tintInfo.mTintMode);
- }
- }
- }
- }
-
/**
* Interface responsible for receiving menu item click events if the items themselves
* do not have individual item click listeners.
@@ -2136,11 +2016,4 @@
public void onRestoreInstanceState(Parcelable state) {
}
}
-
- private static class TintInfo {
- ColorStateList mTintList;
- PorterDuff.Mode mTintMode;
- boolean mHasTintMode;
- boolean mHasTintList;
- }
}
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ba4af89..39c86f9 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -18,8 +18,6 @@
import android.app.Activity;
import android.app.ActivityThread;
-import android.app.usage.UsageStats;
-import android.app.usage.UsageStatsManager;
import android.os.AsyncTask;
import android.provider.Settings;
import android.text.TextUtils;
@@ -64,14 +62,11 @@
import android.widget.Toast;
import com.android.internal.widget.ResolverDrawerLayout;
-import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import static android.view.WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR;
@@ -100,10 +95,7 @@
private boolean mResolvingHome = false;
private int mProfileSwitchMessageId = -1;
private final ArrayList<Intent> mIntents = new ArrayList<>();
-
- private UsageStatsManager mUsm;
- private Map<String, UsageStats> mStats;
- private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
+ private ResolverComparator mResolverComparator;
private boolean mRegistered;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -222,10 +214,6 @@
}
mPm = getPackageManager();
- mUsm = (UsageStatsManager) getSystemService(Context.USAGE_STATS_SERVICE);
-
- final long sinceTime = System.currentTimeMillis() - USAGE_STATS_PERIOD;
- mStats = mUsm.queryAndAggregateUsageStats(sinceTime, System.currentTimeMillis());
mPackageMonitor.register(this, getMainLooper(), false);
mRegistered = true;
@@ -236,6 +224,10 @@
// Add our initial intent as the first item, regardless of what else has already been added.
mIntents.add(0, new Intent(intent));
+ final String referrerPackage = getReferrerPackageName();
+
+ mResolverComparator = new ResolverComparator(this, getTargetIntent(), referrerPackage);
+
configureContentView(mIntents, initialIntents, rList, alwaysUseOption);
// Prevent the Resolver window from becoming the top fullscreen window and thus from taking
@@ -265,7 +257,6 @@
// Try to initialize the title icon if we have a view for it and a title to match
final ImageView titleIcon = (ImageView) findViewById(R.id.title_icon);
if (titleIcon != null) {
- final String referrerPackage = getReferrerPackageName();
ApplicationInfo ai = null;
try {
if (!TextUtils.isEmpty(referrerPackage)) {
@@ -1175,8 +1166,8 @@
}
}
if (N > 1) {
- Collections.sort(currentResolveList,
- new ResolverComparator(ResolverActivity.this, getTargetIntent()));
+ mResolverComparator.compute(currentResolveList);
+ Collections.sort(currentResolveList, mResolverComparator);
}
// First put the initial items at the top.
if (mInitialIntents != null) {
@@ -1651,63 +1642,4 @@
&& match <= IntentFilter.MATCH_CATEGORY_PATH;
}
- class ResolverComparator implements Comparator<ResolvedComponentInfo> {
- private final Collator mCollator;
- private final boolean mHttp;
-
- public ResolverComparator(Context context, Intent intent) {
- mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
- String scheme = intent.getScheme();
- mHttp = "http".equals(scheme) || "https".equals(scheme);
- }
-
- @Override
- public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) {
- final ResolveInfo lhs = lhsp.getResolveInfoAt(0);
- final ResolveInfo rhs = rhsp.getResolveInfoAt(0);
-
- // We want to put the one targeted to another user at the end of the dialog.
- if (lhs.targetUserId != UserHandle.USER_CURRENT) {
- return 1;
- }
-
- if (mHttp) {
- // Special case: we want filters that match URI paths/schemes to be
- // ordered before others. This is for the case when opening URIs,
- // to make native apps go above browsers.
- final boolean lhsSpecific = isSpecificUriMatch(lhs.match);
- final boolean rhsSpecific = isSpecificUriMatch(rhs.match);
- if (lhsSpecific != rhsSpecific) {
- return lhsSpecific ? -1 : 1;
- }
- }
-
- if (mStats != null) {
- final long timeDiff =
- getPackageTimeSpent(rhs.activityInfo.packageName) -
- getPackageTimeSpent(lhs.activityInfo.packageName);
-
- if (timeDiff != 0) {
- return timeDiff > 0 ? 1 : -1;
- }
- }
-
- CharSequence sa = lhs.loadLabel(mPm);
- if (sa == null) sa = lhs.activityInfo.name;
- CharSequence sb = rhs.loadLabel(mPm);
- if (sb == null) sb = rhs.activityInfo.name;
-
- return mCollator.compare(sa.toString(), sb.toString());
- }
-
- private long getPackageTimeSpent(String packageName) {
- if (mStats != null) {
- final UsageStats stats = mStats.get(packageName);
- if (stats != null) {
- return stats.getTotalTimeInForeground();
- }
- }
- return 0;
- }
- }
}
diff --git a/core/java/com/android/internal/app/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
new file mode 100644
index 0000000..585cdf1
--- /dev/null
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package com.android.internal.app;
+
+import android.app.usage.UsageStats;
+import android.app.usage.UsageStatsManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.ComponentInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.UserHandle;
+import android.text.TextUtils;
+import android.util.Log;
+import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+
+import java.text.Collator;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Ranks and compares packages based on usage stats.
+ */
+class ResolverComparator implements Comparator<ResolvedComponentInfo> {
+ private static final String TAG = "ResolverComparator";
+
+ private static final boolean DEBUG = false;
+
+ // Two weeks
+ private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
+
+ private static final long RECENCY_TIME_PERIOD = 1000 * 60 * 60 * 12;
+
+ private static final float RECENCY_MULTIPLIER = 3.f;
+
+ private final Collator mCollator;
+ private final boolean mHttp;
+ private final PackageManager mPm;
+ private final UsageStatsManager mUsm;
+ private final Map<String, UsageStats> mStats;
+ private final long mCurrentTime;
+ private final long mSinceTime;
+ private final LinkedHashMap<ComponentName, ScoredTarget> mScoredTargets = new LinkedHashMap<>();
+ private final String mReferrerPackage;
+
+ public ResolverComparator(Context context, Intent intent, String referrerPackage) {
+ mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
+ String scheme = intent.getScheme();
+ mHttp = "http".equals(scheme) || "https".equals(scheme);
+ mReferrerPackage = referrerPackage;
+
+ mPm = context.getPackageManager();
+ mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);
+
+ mCurrentTime = System.currentTimeMillis();
+ mSinceTime = mCurrentTime - USAGE_STATS_PERIOD;
+ mStats = mUsm.queryAndAggregateUsageStats(mSinceTime, mCurrentTime);
+ }
+
+ public void compute(List<ResolvedComponentInfo> targets) {
+ mScoredTargets.clear();
+
+ final long recentSinceTime = mCurrentTime - RECENCY_TIME_PERIOD;
+
+ long mostRecentlyUsedTime = recentSinceTime + 1;
+ long mostTimeSpent = 1;
+ int mostLaunched = 1;
+
+ for (ResolvedComponentInfo target : targets) {
+ final ScoredTarget scoredTarget
+ = new ScoredTarget(target.getResolveInfoAt(0).activityInfo);
+ mScoredTargets.put(target.name, scoredTarget);
+ final UsageStats pkStats = mStats.get(target.name.getPackageName());
+ if (pkStats != null) {
+ // Only count recency for apps that weren't the caller
+ // since the caller is always the most recent.
+ // Persistent processes muck this up, so omit them too.
+ if (!target.name.getPackageName().equals(mReferrerPackage)
+ && !isPersistentProcess(target)) {
+ final long lastTimeUsed = pkStats.getLastTimeUsed();
+ scoredTarget.lastTimeUsed = lastTimeUsed;
+ if (lastTimeUsed > mostRecentlyUsedTime) {
+ mostRecentlyUsedTime = lastTimeUsed;
+ }
+ }
+ final long timeSpent = pkStats.getTotalTimeInForeground();
+ scoredTarget.timeSpent = timeSpent;
+ if (timeSpent > mostTimeSpent) {
+ mostTimeSpent = timeSpent;
+ }
+ final int launched = pkStats.mLaunchCount;
+ scoredTarget.launchCount = launched;
+ if (launched > mostLaunched) {
+ mostLaunched = launched;
+ }
+ }
+ }
+
+
+ if (DEBUG) {
+ Log.d(TAG, "compute - mostRecentlyUsedTime: " + mostRecentlyUsedTime
+ + " mostTimeSpent: " + mostTimeSpent
+ + " recentSinceTime: " + recentSinceTime
+ + " mostLaunched: " + mostLaunched);
+ }
+
+ for (ScoredTarget target : mScoredTargets.values()) {
+ final float recency = (float) Math.max(target.lastTimeUsed - recentSinceTime, 0)
+ / (mostRecentlyUsedTime - recentSinceTime);
+ final float recencyScore = recency * recency * RECENCY_MULTIPLIER;
+ final float usageTimeScore = (float) target.timeSpent / mostTimeSpent;
+ final float launchCountScore = (float) target.launchCount / mostLaunched;
+
+ target.score = recencyScore + usageTimeScore + launchCountScore;
+ if (DEBUG) {
+ Log.d(TAG, "Scores: recencyScore: " + recencyScore
+ + " usageTimeScore: " + usageTimeScore
+ + " launchCountScore: " + launchCountScore
+ + " - " + target);
+ }
+ }
+ }
+
+ static boolean isPersistentProcess(ResolvedComponentInfo rci) {
+ if (rci != null && rci.getCount() > 0) {
+ return (rci.getResolveInfoAt(0).activityInfo.applicationInfo.flags &
+ ApplicationInfo.FLAG_PERSISTENT) != 0;
+ }
+ return false;
+ }
+
+ @Override
+ public int compare(ResolvedComponentInfo lhsp, ResolvedComponentInfo rhsp) {
+ final ResolveInfo lhs = lhsp.getResolveInfoAt(0);
+ final ResolveInfo rhs = rhsp.getResolveInfoAt(0);
+
+ // We want to put the one targeted to another user at the end of the dialog.
+ if (lhs.targetUserId != UserHandle.USER_CURRENT) {
+ return 1;
+ }
+
+ if (mHttp) {
+ // Special case: we want filters that match URI paths/schemes to be
+ // ordered before others. This is for the case when opening URIs,
+ // to make native apps go above browsers.
+ final boolean lhsSpecific = ResolverActivity.isSpecificUriMatch(lhs.match);
+ final boolean rhsSpecific = ResolverActivity.isSpecificUriMatch(rhs.match);
+ if (lhsSpecific != rhsSpecific) {
+ return lhsSpecific ? -1 : 1;
+ }
+ }
+
+ if (mStats != null) {
+ final ScoredTarget lhsTarget = mScoredTargets.get(new ComponentName(
+ lhs.activityInfo.packageName, lhs.activityInfo.name));
+ final ScoredTarget rhsTarget = mScoredTargets.get(new ComponentName(
+ rhs.activityInfo.packageName, rhs.activityInfo.name));
+ final float diff = rhsTarget.score - lhsTarget.score;
+
+ if (diff != 0) {
+ return diff > 0 ? 1 : -1;
+ }
+ }
+
+ CharSequence sa = lhs.loadLabel(mPm);
+ if (sa == null) sa = lhs.activityInfo.name;
+ CharSequence sb = rhs.loadLabel(mPm);
+ if (sb == null) sb = rhs.activityInfo.name;
+
+ return mCollator.compare(sa.toString().trim(), sb.toString().trim());
+ }
+
+ static class ScoredTarget {
+ public final ComponentInfo componentInfo;
+ public float score;
+ public long lastTimeUsed;
+ public long timeSpent;
+ public long launchCount;
+
+ public ScoredTarget(ComponentInfo ci) {
+ componentInfo = ci;
+ }
+
+ @Override
+ public String toString() {
+ return "ScoredTarget{" + componentInfo
+ + " score: " + score
+ + " lastTimeUsed: " + lastTimeUsed
+ + " timeSpent: " + timeSpent
+ + " launchCount: " + launchCount
+ + "}";
+ }
+ }
+}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
index 00af401..ed676bb 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItem.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -18,8 +18,6 @@
import android.content.Context;
import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.view.ActionProvider;
import android.view.ContextMenu.ContextMenuInfo;
@@ -44,7 +42,6 @@
private Drawable mIconDrawable;
private int mIconResId = NO_ICON;
- private TintInfo mIconTintInfo;
private Context mContext;
@@ -161,14 +158,12 @@
public MenuItem setIcon(Drawable icon) {
mIconDrawable = icon;
mIconResId = NO_ICON;
- applyIconTint();
return this;
}
public MenuItem setIcon(int iconRes) {
mIconResId = iconRes;
mIconDrawable = mContext.getDrawable(iconRes);
- applyIconTint();
return this;
}
@@ -279,48 +274,4 @@
// No need to save the listener; ActionMenuItem does not support collapsing items.
return this;
}
-
- @Override
- public MenuItem setIconTintList(ColorStateList tintList) {
- if (mIconTintInfo == null) {
- mIconTintInfo = new TintInfo();
- }
- mIconTintInfo.mTintList = tintList;
- mIconTintInfo.mHasTintList = true;
- applyIconTint();
- return this;
- }
-
- @Override
- public MenuItem setIconTintMode(PorterDuff.Mode tintMode) {
- if (mIconTintInfo == null) {
- mIconTintInfo = new TintInfo();
- }
- mIconTintInfo.mTintMode = tintMode;
- mIconTintInfo.mHasTintMode = true;
- applyIconTint();
- return this;
- }
-
- private void applyIconTint() {
- final TintInfo tintInfo = mIconTintInfo;
- if (mIconDrawable != null && tintInfo != null) {
- if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
- mIconDrawable = mIconDrawable.mutate();
- if (tintInfo.mHasTintList) {
- mIconDrawable.setTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mIconDrawable.setTintMode(tintInfo.mTintMode);
- }
- }
- }
- }
-
- private static class TintInfo {
- ColorStateList mTintList;
- PorterDuff.Mode mTintMode;
- boolean mHasTintMode;
- boolean mHasTintList;
- }
}
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index ef4e546..3b1f20d 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -21,8 +21,6 @@
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
-import android.content.res.ColorStateList;
-import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.ActionProvider;
@@ -62,11 +60,6 @@
* needed).
*/
private int mIconResId = NO_ICON;
-
- /**
- * Tint info for the icon
- */
- private TintInfo mIconTintInfo;
/** The menu to which this item belongs */
private MenuBuilder mMenu;
@@ -392,10 +385,10 @@
}
if (mIconResId != NO_ICON) {
- mIconDrawable = mMenu.getContext().getDrawable(mIconResId);
+ Drawable icon = mMenu.getContext().getDrawable(mIconResId);
mIconResId = NO_ICON;
- applyIconTint();
- return mIconDrawable;
+ mIconDrawable = icon;
+ return icon;
}
return null;
@@ -404,7 +397,6 @@
public MenuItem setIcon(Drawable icon) {
mIconResId = NO_ICON;
mIconDrawable = icon;
- applyIconTint();
mMenu.onItemsChanged(false);
return this;
@@ -678,48 +670,4 @@
public boolean isActionViewExpanded() {
return mIsActionViewExpanded;
}
-
- @Override
- public MenuItem setIconTintList(ColorStateList tintList) {
- if (mIconTintInfo == null) {
- mIconTintInfo = new TintInfo();
- }
- mIconTintInfo.mTintList = tintList;
- mIconTintInfo.mHasTintList = true;
- applyIconTint();
- return this;
- }
-
- @Override
- public MenuItem setIconTintMode(PorterDuff.Mode tintMode) {
- if (mIconTintInfo == null) {
- mIconTintInfo = new TintInfo();
- }
- mIconTintInfo.mTintMode = tintMode;
- mIconTintInfo.mHasTintMode = true;
- applyIconTint();
- return this;
- }
-
- private void applyIconTint() {
- final TintInfo tintInfo = mIconTintInfo;
- if (mIconDrawable != null && tintInfo != null) {
- if (tintInfo.mHasTintList || tintInfo.mHasTintMode) {
- mIconDrawable = mIconDrawable.mutate();
- if (tintInfo.mHasTintList) {
- mIconDrawable.setTintList(tintInfo.mTintList);
- }
- if (tintInfo.mHasTintMode) {
- mIconDrawable.setTintMode(tintInfo.mTintMode);
- }
- }
- }
- }
-
- private static class TintInfo {
- ColorStateList mTintList;
- PorterDuff.Mode mTintMode;
- boolean mHasTintMode;
- boolean mHasTintList;
- }
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 709de9e..5526a3c 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -90,7 +90,6 @@
<protected-broadcast android:name="android.app.action.ENTER_DESK_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_DESK_MODE" />
<protected-broadcast android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
- <protected-broadcast android:name="android.app.action.SEND_DEVICE_INITIALIZER_STATUS" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_UPDATE_OPTIONS" />
<protected-broadcast android:name="android.appwidget.action.APPWIDGET_DELETED" />
@@ -981,33 +980,11 @@
<!-- Allows access to the list of accounts in the Accounts Service -->
<permission android:name="android.permission.GET_ACCOUNTS"
- android:permissionGroup="android.permission-group.ACCOUNTS"
+ android:permissionGroup="android.permission-group.CONTACTS"
android:protectionLevel="normal"
android:description="@string/permdesc_getAccounts"
android:label="@string/permlab_getAccounts" />
- <!-- Allows an application to act as an AccountAuthenticator for
- the AccountManager -->
- <permission android:name="android.permission.AUTHENTICATE_ACCOUNTS"
- android:permissionGroup="android.permission-group.ACCOUNTS"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_authenticateAccounts"
- android:description="@string/permdesc_authenticateAccounts" />
-
- <!-- Allows an application to request authtokens from the AccountManager -->
- <permission android:name="android.permission.USE_CREDENTIALS"
- android:permissionGroup="android.permission-group.ACCOUNTS"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_useCredentials"
- android:description="@string/permdesc_useCredentials" />
-
- <!-- Allows an application to manage the list of accounts in the AccountManager -->
- <permission android:name="android.permission.MANAGE_ACCOUNTS"
- android:permissionGroup="android.permission-group.ACCOUNTS"
- android:protectionLevel="dangerous"
- android:label="@string/permlab_manageAccounts"
- android:description="@string/permdesc_manageAccounts" />
-
<!-- @SystemApi Allows applications to call into AccountAuthenticators.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCOUNT_MANAGER"
@@ -1979,6 +1956,10 @@
<permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS"
android:protectionLevel="signature" />
+ <!-- @hide Allows an application to observe permission changes. -->
+ <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
+ android:protectionLevel="signatureOrSystem" />
+
<!-- Allows an application to use SurfaceFlinger's low level features.
<p>Not for use by third-party applications. -->
<permission android:name="android.permission.ACCESS_SURFACE_FLINGER"
@@ -2446,11 +2427,6 @@
<permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
android:protectionLevel="signature" />
- <!-- Allows receiving status updates from a device initializer.
- @hide Not for use by third-party applications. -->
- <permission android:name="android.permission.RECEIVE_DEVICE_INITIALIZER_STATUS"
- android:protectionLevel="signature" />
-
<!-- The system process that is allowed to bind to services in carrier apps will
have this permission. Carrier apps should use this permission to protect
their services that only the system is allowed to bind to. -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index bb442eb..52e2cf0 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -6651,33 +6651,6 @@
for more info. -->
<attr name="actionProviderClass" format="string" />
- <!-- An optional tint for the item's icon.
- See {@link android.view.MenuItem#setIconTintList(android.content.res.ColorStateList)}
- for more info. -->
- <attr name="iconTint" format="color" />
-
- <!-- The blending mode used for tinting the item's icon
- See {@link android.view.MenuItem#setIconTintMode(android.graphics.PorterDuff.Mode)}
- for more info. -->
- <attr name="iconTintMode">
- <!-- The tint is drawn on top of the drawable.
- [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
- <enum name="src_over" value="3" />
- <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
- color channels are thrown out. [Sa * Da, Sc * Da] -->
- <enum name="src_in" value="5" />
- <!-- The tint is drawn above the drawable, but with the drawable’s alpha
- channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="9" />
- <!-- Multiplies the color and alpha channels of the drawable with those of
- the tint. [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="14" />
- <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="15" />
- <!-- Combines the tint and drawable color and alpha channels, clamping the
- result to valid color values. Saturate(S + D) -->
- <enum name="add" value="16" />
- </attr>
</declare-styleable>
<!-- Attrbitutes for a ActvityChooserView. -->
@@ -7791,52 +7764,6 @@
<!-- Text to set as the content description for the navigation button
located at the start of the toolbar. -->
<attr name="navigationContentDescription" format="string" />
-
- <!-- Tint used for the navigation button -->
- <attr name="navigationTint" format="color" />
- <!-- The blending mode used for tinting the navigation button -->
- <attr name="navigationTintMode">
- <!-- The tint is drawn on top of the drawable.
- [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
- <enum name="src_over" value="3" />
- <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
- color channels are thrown out. [Sa * Da, Sc * Da] -->
- <enum name="src_in" value="5" />
- <!-- The tint is drawn above the drawable, but with the drawable’s alpha
- channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="9" />
- <!-- Multiplies the color and alpha channels of the drawable with those of
- the tint. [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="14" />
- <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="15" />
- <!-- Combines the tint and drawable color and alpha channels, clamping the
- result to valid color values. Saturate(S + D). Only works on APIv 11+ -->
- <enum name="add" value="16" />
- </attr>
-
- <!-- Tint used for the overflow button -->
- <attr name="overflowTint" format="color" />
- <!-- The blending mode used for tinting the overflow button -->
- <attr name="overflowTintMode">
- <!-- The tint is drawn on top of the drawable.
- [Sa + (1 - Sa)*Da, Rc = Sc + (1 - Sa)*Dc] -->
- <enum name="src_over" value="3" />
- <!-- The tint is masked by the alpha channel of the drawable. The drawable’s
- color channels are thrown out. [Sa * Da, Sc * Da] -->
- <enum name="src_in" value="5" />
- <!-- The tint is drawn above the drawable, but with the drawable’s alpha
- channel masking the result. [Da, Sc * Da + (1 - Sa) * Dc] -->
- <enum name="src_atop" value="9" />
- <!-- Multiplies the color and alpha channels of the drawable with those of
- the tint. [Sa * Da, Sc * Dc] -->
- <enum name="multiply" value="14" />
- <!-- [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] -->
- <enum name="screen" value="15" />
- <!-- Combines the tint and drawable color and alpha channels, clamping the
- result to valid color values. Saturate(S + D). Only works on APIv 11+ -->
- <enum name="add" value="16" />
- </attr>
</declare-styleable>
<declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 470e345..f31c1d6 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1058,18 +1058,20 @@
lockTask mode is disabled.
<p>While in lockTask mode with multiple permitted tasks running, each launched task is
permitted to finish, transitioning to the previous locked task, until there is only one
- task remaining. At that point the last task running is not permitted to finish. -->
+ task remaining. At that point the last task running is not permitted to finish, unless it
+ uses the value always. -->
<attr name="lockTaskMode">
<!-- This is the default value. Tasks will not launch into lockTask mode but can be
placed there by calling {@link android.app.Activity#startLockTask}. If a task with
this mode has been whitelisted using {@link
- android.app.admin.DevicePolicyManager#setLockTaskPackages} then calling startLockTask
- will enter lockTask mode immediately, otherwise the user will be presented with a
- dialog to approve entering lockTask mode.
+ android.app.admin.DevicePolicyManager#setLockTaskPackages} then calling
+ {@link android.app.Activity#startLockTask} will enter lockTask mode immediately,
+ otherwise the user will be presented with a dialog to approve entering pinned mode.
<p>If the system is already in lockTask mode when a new task rooted at this activity
is launched that task will or will not start depending on whether the package of this
activity has been whitelisted.
- <p>Tasks rooted at this activity can only exit lockTask mode using stopLockTask(). -->
+ <p>Tasks rooted at this activity can only exit lockTask mode using
+ {@link android.app.Activity#stopLockTask}. -->
<enum name="normal" value="0"/>
<!-- Tasks will not launch into lockTask mode and cannot be placed there using
{@link android.app.Activity#startLockTask} or be pinned from the Overview screen.
@@ -1082,16 +1084,17 @@
<!-- Tasks rooted at this activity will always launch into lockTask mode. If the system is
already in lockTask mode when this task is launched then the new task will be launched
on top of the current task. Tasks launched in this mode are capable of exiting
- lockTask mode using finish(), whereas tasks entering lockTask mode using
- startLockTask() must use stopLockTask() to exit.
+ lockTask mode using {@link android.app.Activity#finish()}.
<p>Note: This mode is only available to system and privileged applications.
Non-privileged apps with this value will be treated as normal.
-->
<enum name="always" value="2"/>
<!-- If the DevicePolicyManager (DPM) authorizes this package ({@link
android.app.admin.DevicePolicyManager#setLockTaskPackages}) then this mode is
- identical to always. If the DPM does not authorize this package then this
- mode is identical to normal. -->
+ identical to always, except that the activity needs to call
+ {@link android.app.Activity#stopLockTask} before being able to finish if it is the last
+ locked task.
+ If the DPM does not authorize this package then this mode is identical to normal. -->
<enum name="if_whitelisted" value="3"/>
</attr>
<!-- When set installer will extract native libraries. If set to false
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 54cfa03..bbe27a4 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2614,12 +2614,20 @@
<public type="attr" name="end" />
<public type="attr" name="windowLightStatusBar" />
<public type="attr" name="numbersInnerTextColor" />
- <public type="attr" name="iconTint" />
- <public type="attr" name="iconTintMode" />
- <public type="attr" name="overflowTint" />
- <public type="attr" name="overflowTintMode" />
- <public type="attr" name="navigationTint" />
- <public type="attr" name="navigationTintMode" />
+
+ <attr name="__reserved2" format="boolean" />
+ <public type="attr" name="__reserved2" />
+ <attr name="__reserved3" format="boolean" />
+ <public type="attr" name="__reserved3" />
+ <attr name="__reserved4" format="boolean" />
+ <public type="attr" name="__reserved4" />
+ <attr name="__reserved5" format="boolean" />
+ <public type="attr" name="__reserved5" />
+ <attr name="__reserved6" format="boolean" />
+ <public type="attr" name="__reserved6" />
+ <attr name="__reserved7" format="boolean" />
+ <public type="attr" name="__reserved7" />
+
<public type="attr" name="fullBackupContent" />
<public type="style" name="Widget.Material.Button.Colored" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 0d87b19..9ad4be2 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1113,27 +1113,6 @@
the list of accounts known by the phone. This may include any accounts
created by applications you have installed.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_authenticateAccounts">create accounts and set passwords</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_authenticateAccounts">Allows the app
- to use the account authenticator capabilities of the
- AccountManager, including creating accounts and getting and
- setting their passwords.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_manageAccounts">add or remove accounts</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_manageAccounts">Allows the app to
- perform operations like adding and removing accounts, and deleting
- their password.</string>
-
- <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permlab_useCredentials">use accounts on the device</string>
- <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
- <string name="permdesc_useCredentials">Allows the app to request authentication tokens.</string>
-
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_accessNetworkState">view network connections</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
diff --git a/docs/html/robots.txt b/docs/html/robots.txt
index ab379bb..f522220 100644
--- a/docs/html/robots.txt
+++ b/docs/html/robots.txt
@@ -15,5 +15,4 @@
Disallow: /guide/tutorials/
Disallow: /guide/samples/
Disallow: /community/
-Disallow: /preview/
Sitemap: http://developer.android.com/sitemap.txt
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index bdc60a2..fed3f47 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -5,28 +5,28 @@
header.hide=1
page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more.
-studio.version=1.2.1.1
+studio.version=1.2.2.0
-studio.linux_bundle_download=android-studio-ide-141.1903250-linux.zip
-studio.linux_bundle_bytes=258634089
-studio.linux_bundle_checksum=61f576a24ac9aa00d498bb62942c028ef4a8905b
+studio.linux_bundle_download=android-studio-ide-141.1980579-linux.zip
+studio.linux_bundle_bytes=258628239
+studio.linux_bundle_checksum=1fcb226bcf71760296b07dc0db74216563ce83f7
-studio.mac_bundle_download=android-studio-ide-141.1903250-mac.dmg
-studio.mac_bundle_bytes=260877150
-studio.mac_bundle_checksum=a5a6ba50e3590de0973230a238d17726a1d9395c
+studio.mac_bundle_download=android-studio-ide-141.1980579-mac.dmg
+studio.mac_bundle_bytes=260363204
+studio.mac_bundle_checksum=811a868958f8799a1c86a3acfab0fc5dc8de2f41
-studio.win_bundle_download=android-studio-ide-141.1903250-windows.zip
-studio.win_bundle_bytes=261042465
-studio.win_bundle_checksum=ce924e0e4cff4b7f24df3f7ce0c1ce2379347d72
+studio.win_bundle_download=android-studio-ide-141.1980579-windows.zip
+studio.win_bundle_bytes=261036618
+studio.win_bundle_checksum=e61c9c27a92eff943f6bfdcdec3827199dd0c63d
-studio.win_bundle_exe_download=android-studio-bundle-141.1903250-windows.exe
-studio.win_bundle_exe_bytes=930462136
-studio.win_bundle_exe_checksum=680668b6b4a51c519efda814b96c2b61541a50f2
+studio.win_bundle_exe_download=android-studio-bundle-141.1980579-windows.exe
+studio.win_bundle_exe_bytes=930456592
+studio.win_bundle_exe_checksum=964959e5165e90aaf693e868d5d1c2f7b38e8754
-studio.win_notools_exe_download=android-studio-ide-141.1903250-windows.exe
-studio.win_notools_exe_bytes=243747312
-studio.win_notools_exe_checksum=d89917dd044e0559c87d6a05d49780ab110269f7
+studio.win_notools_exe_download=android-studio-ide-141.1980579-windows.exe
+studio.win_notools_exe_bytes=243741776
+studio.win_notools_exe_checksum=ae09797db2537afb572a00b7eacc292bb66d539e
diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd
index 7138efe..b727d96 100644
--- a/docs/html/tools/revisions/studio.jd
+++ b/docs/html/tools/revisions/studio.jd
@@ -43,10 +43,24 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt=""/>Android Studio v1.2.2</a> <em>(June 2015)</em>
+ </p>
+ <div class="toggle-content-toggleme">
+ <p>Fixes and enhancements:</p>
+ <ul>
+ <li>Fixed build issues that were blocking builds from completing. </li>
+ </ul>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt=""/>Android Studio v1.2.1</a> <em>(May 2015)</em>
</p>
<div class="toggle-content-toggleme">
- <p>Various fixes and enhancements:</p>
+ <p>Fixes and enhancements:</p>
<ul>
<li>Fixed minor performance and feature issues. </li>
</ul>
@@ -62,7 +76,7 @@
</p>
<div class="toggle-content-toggleme">
- <p>Various fixes and enhancements:</p>
+ <p>Fixes and enhancements:</p>
<ul>
<li>Updated the Android runtime window to include the
<a href="{@docRoot}tools/studio/index.html#mem-cpu">Memory Monitor</a> tool
diff --git a/docs/html/training/sync-adapters/creating-sync-adapter.jd b/docs/html/training/sync-adapters/creating-sync-adapter.jd
index b13ce07..9bd17ba 100644
--- a/docs/html/training/sync-adapters/creating-sync-adapter.jd
+++ b/docs/html/training/sync-adapters/creating-sync-adapter.jd
@@ -583,13 +583,6 @@
running the sync adapter, see <a href="running-sync-adapter.html"
>Running A Sync Adapter</a>.
</dd>
- <dt>
-{@link android.Manifest.permission#AUTHENTICATE_ACCOUNTS android.permission.AUTHENTICATE_ACCOUNTS}
- </dt>
- <dd>
- Allows you to use the authenticator component you created in the lesson
- <a href="creating-authenticator.html">Creating a Stub Authenticator</a>.
- </dd>
</dl>
<p>
The following snippet shows how to add the permissions:
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 059d8e6..f482bf0 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -29,15 +29,14 @@
import android.os.Process;
import android.os.RemoteException;
import android.os.UserHandle;
-import android.security.keystore.KeyInfo;
+import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
import java.io.ByteArrayInputStream;
import java.io.Closeable;
-import java.security.InvalidKeyException;
-import java.security.KeyFactory;
import java.security.Principal;
import java.security.PrivateKey;
+import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
@@ -47,7 +46,6 @@
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
-import com.android.org.conscrypt.OpenSSLEngine;
import com.android.org.conscrypt.TrustedCertificateStore;
/**
@@ -90,8 +88,6 @@
// TODO reference intent for credential installation when public
public final class KeyChain {
- private static final String TAG = "KeyChain";
-
/**
* @hide Also used by KeyChainService implementation
*/
@@ -372,15 +368,14 @@
if (keyId == null) {
throw new KeyChainException("keystore had a problem");
}
-
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
- return engine.getPrivateKeyById(keyId);
+ return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+ KeyStore.getInstance(), keyId);
} catch (RemoteException e) {
throw new KeyChainException(e);
} catch (RuntimeException e) {
// only certain RuntimeExceptions can be propagated across the IKeyChainService call
throw new KeyChainException(e);
- } catch (InvalidKeyException e) {
+ } catch (UnrecoverableKeyException e) {
throw new KeyChainException(e);
} finally {
keyChainConnection.close();
diff --git a/keystore/java/android/security/KeyPairGeneratorSpec.java b/keystore/java/android/security/KeyPairGeneratorSpec.java
index efbce41..d849317 100644
--- a/keystore/java/android/security/KeyPairGeneratorSpec.java
+++ b/keystore/java/android/security/KeyPairGeneratorSpec.java
@@ -331,7 +331,9 @@
if (keyType == null) {
throw new NullPointerException("keyType == null");
} else {
- if (KeyStore.getKeyTypeForAlgorithm(keyType) == -1) {
+ try {
+ KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(keyType);
+ } catch (IllegalArgumentException e) {
throw new NoSuchAlgorithmException("Unsupported key type: " + keyType);
}
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 893771a..35fcda6 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -19,7 +19,6 @@
import android.app.ActivityThread;
import android.app.Application;
import android.app.KeyguardManager;
-import com.android.org.conscrypt.NativeConstants;
import android.content.Context;
import android.hardware.fingerprint.FingerprintManager;
@@ -38,7 +37,6 @@
import android.security.keystore.KeyExpiredException;
import android.security.keystore.KeyNotYetValidException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;
@@ -136,16 +134,6 @@
return mToken;
}
- public static int getKeyTypeForAlgorithm(@KeyProperties.KeyAlgorithmEnum String keyType) {
- if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyType)) {
- return NativeConstants.EVP_PKEY_RSA;
- } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyType)) {
- return NativeConstants.EVP_PKEY_EC;
- } else {
- return -1;
- }
- }
-
public State state(int userId) {
final int ret;
try {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
new file mode 100644
index 0000000..5dbcd68
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.security.PrivateKey;
+import java.security.interfaces.ECKey;
+import java.security.spec.ECParameterSpec;
+
+/**
+ * EC private key (instance of {@link PrivateKey} and {@link ECKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
+ private final ECParameterSpec mParams;
+
+ public AndroidKeyStoreECPrivateKey(String alias, ECParameterSpec params) {
+ super(alias, KeyProperties.KEY_ALGORITHM_EC);
+ mParams = params;
+ }
+
+ @Override
+ public ECParameterSpec getParams() {
+ return mParams;
+ }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
index 1751aa5..e76802f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
@@ -52,4 +52,42 @@
// This key does not export its key material
return null;
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
+ result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AndroidKeyStoreKey other = (AndroidKeyStoreKey) obj;
+ if (mAlgorithm == null) {
+ if (other.mAlgorithm != null) {
+ return false;
+ }
+ } else if (!mAlgorithm.equals(other.mAlgorithm)) {
+ return false;
+ }
+ if (mAlias == null) {
+ if (other.mAlias != null) {
+ return false;
+ }
+ } else if (!mAlias.equals(other.mAlias)) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 69155a8..35af34f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -20,7 +20,6 @@
import android.security.Credentials;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStore;
-import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
@@ -44,29 +43,24 @@
import com.android.org.bouncycastle.jce.X509Principal;
import com.android.org.bouncycastle.jce.provider.X509CertificateObject;
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
-import com.android.org.conscrypt.OpenSSLEngine;
import libcore.util.EmptyArray;
import java.math.BigInteger;
import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyPairGeneratorSpi;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.ProviderException;
import java.security.PublicKey;
import java.security.SecureRandom;
+import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateEncodingException;
import java.security.cert.X509Certificate;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.ECGenParameterSpec;
-import java.security.spec.InvalidKeySpecException;
import java.security.spec.RSAKeyGenParameterSpec;
-import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -147,6 +141,7 @@
SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
}
+
private final int mOriginalKeymasterAlgorithm;
private KeyStore mKeyStore;
@@ -431,24 +426,6 @@
args.addInts(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
args.addInts(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- // TODO: Remove the digest and padding NONE workaround below once Android Keystore returns
- // keys which are backed by AndroidKeyStoreBCWorkaround provider instead of Conscrypt. The
- // workaround is needed because Conscrypt (via keystore-engine) uses old KeyStore API which
- // translates into digest NONE and padding NONE in the new API. keystore-engine cannot be
- // updated to pass in the correct padding and digest values because it uses
- // OpenSSL/BoringSSL engine which performs digesting and padding prior before invoking
- // KeyStore API.
- if (!com.android.internal.util.ArrayUtils.contains(
- mKeymasterDigests, KeymasterDefs.KM_DIGEST_NONE)) {
- args.addInt(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
- }
- if ((!com.android.internal.util.ArrayUtils.contains(
- mKeymasterSignaturePaddings, KeymasterDefs.KM_PAD_NONE))
- && (!com.android.internal.util.ArrayUtils.contains(
- mKeymasterEncryptionPaddings, KeymasterDefs.KM_PAD_NONE))) {
- args.addInt(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
- }
-
KeymasterUtils.addUserAuthArgs(args,
mSpec.isUserAuthenticationRequired(),
mSpec.getUserAuthenticationValidityDurationSeconds());
@@ -483,40 +460,23 @@
"Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
}
- final PrivateKey privKey;
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
+ KeyPair result;
try {
- privKey = engine.getPrivateKeyById(privateKeyAlias);
- } catch (InvalidKeyException e) {
- throw new ProviderException("Failed to obtain generated private key", e);
+ result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+ mKeyStore, privateKeyAlias);
+ } catch (UnrecoverableKeyException e) {
+ throw new ProviderException("Failed to load generated key pair from keystore", e);
}
- ExportResult exportResult =
- mKeyStore.exportKey(
- privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
- if (exportResult == null) {
- throw new KeyStoreConnectException();
- } else if (exportResult.resultCode != KeyStore.NO_ERROR) {
+ if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
throw new ProviderException(
- "Failed to obtain X.509 form of generated public key",
- KeyStore.getKeyStoreException(exportResult.resultCode));
- }
- final byte[] pubKeyBytes = exportResult.exportData;
-
- final PublicKey pubKey;
- try {
- final KeyFactory keyFact = KeyFactory.getInstance(mJcaKeyAlgorithm);
- pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain " + mJcaKeyAlgorithm + " KeyFactory", e);
- } catch (InvalidKeySpecException e) {
- throw new ProviderException("Invalid X.509 encoding of generated public key", e);
+ "Generated key pair algorithm does not match requested algorithm: "
+ + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
}
final X509Certificate cert;
try {
- cert = generateSelfSignedCertificate(privKey, pubKey);
+ cert = generateSelfSignedCertificate(result.getPrivate(), result.getPublic());
} catch (Exception e) {
throw new ProviderException("Failed to generate self-signed certificate", e);
}
@@ -539,7 +499,6 @@
KeyStore.getKeyStoreException(insertErrorCode));
}
- KeyPair result = new KeyPair(pubKey, privKey);
success = true;
return result;
} finally {
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index cb270bb..967319a 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -16,11 +16,28 @@
package android.security.keystore;
+import android.annotation.NonNull;
import android.security.KeyStore;
+import android.security.keymaster.ExportResult;
+import android.security.keymaster.KeyCharacteristics;
+import android.security.keymaster.KeymasterDefs;
+import java.security.KeyFactory;
+import java.security.KeyPair;
+import java.security.NoSuchAlgorithmException;
import java.security.Provider;
+import java.security.ProviderException;
+import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
+import java.security.UnrecoverableKeyException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAKey;
+import java.security.interfaces.RSAPublicKey;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -146,4 +163,145 @@
}
return ((KeyStoreCryptoOperation) spi).getOperationHandle();
}
+
+ @NonNull
+ public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
+ @NonNull String alias,
+ @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
+ @NonNull byte[] x509EncodedForm) {
+ PublicKey publicKey;
+ try {
+ KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
+ publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedForm));
+ } catch (NoSuchAlgorithmException e) {
+ throw new ProviderException(
+ "Failed to obtain " + keyAlgorithm + " KeyFactory", e);
+ } catch (InvalidKeySpecException e) {
+ throw new ProviderException("Invalid X.509 encoding of public key", e);
+ }
+ if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
+ return new AndroidKeyStoreECPublicKey(alias, (ECPublicKey) publicKey);
+ } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
+ return new AndroidKeyStoreRSAPublicKey(alias, (RSAPublicKey) publicKey);
+ } else {
+ throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+ + keyAlgorithm);
+ }
+ }
+
+ @NonNull
+ public static AndroidKeyStorePrivateKey getAndroidKeyStorePrivateKey(
+ @NonNull AndroidKeyStorePublicKey publicKey) {
+ String keyAlgorithm = publicKey.getAlgorithm();
+ if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
+ return new AndroidKeyStoreECPrivateKey(
+ publicKey.getAlias(), ((ECKey) publicKey).getParams());
+ } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
+ return new AndroidKeyStoreRSAPrivateKey(
+ publicKey.getAlias(), ((RSAKey) publicKey).getModulus());
+ } else {
+ throw new ProviderException("Unsupported Android Keystore public key algorithm: "
+ + keyAlgorithm);
+ }
+ }
+
+ @NonNull
+ public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
+ @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+ throws UnrecoverableKeyException {
+ KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+ int errorCode = keyStore.getKeyCharacteristics(
+ privateKeyAlias, null, null, keyCharacteristics);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to obtain information about private key")
+ .initCause(KeyStore.getKeyStoreException(errorCode));
+ }
+ ExportResult exportResult = keyStore.exportKey(
+ privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
+ if (exportResult.resultCode != KeyStore.NO_ERROR) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
+ .initCause(KeyStore.getKeyStoreException(errorCode));
+ }
+ final byte[] x509EncodedPublicKey = exportResult.exportData;
+
+ int keymasterAlgorithm = keyCharacteristics.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
+ if (keymasterAlgorithm == -1) {
+ throw new UnrecoverableKeyException("Key algorithm unknown");
+ }
+
+ String jcaKeyAlgorithm;
+ try {
+ jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
+ keymasterAlgorithm);
+ } catch (IllegalArgumentException e) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to load private key")
+ .initCause(e);
+ }
+
+ return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+ privateKeyAlias, jcaKeyAlgorithm, x509EncodedPublicKey);
+ }
+
+ @NonNull
+ public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
+ @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+ throws UnrecoverableKeyException {
+ AndroidKeyStorePublicKey publicKey =
+ loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias);
+ AndroidKeyStorePrivateKey privateKey =
+ AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
+ return new KeyPair(publicKey, privateKey);
+ }
+
+ @NonNull
+ public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
+ @NonNull KeyStore keyStore, @NonNull String privateKeyAlias)
+ throws UnrecoverableKeyException {
+ KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias);
+ return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
+ }
+
+ @NonNull
+ public static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
+ @NonNull KeyStore keyStore, @NonNull String secretKeyAlias)
+ throws UnrecoverableKeyException {
+ KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
+ int errorCode = keyStore.getKeyCharacteristics(
+ secretKeyAlias, null, null, keyCharacteristics);
+ if (errorCode != KeyStore.NO_ERROR) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Failed to obtain information about key")
+ .initCause(KeyStore.getKeyStoreException(errorCode));
+ }
+
+ int keymasterAlgorithm = keyCharacteristics.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
+ if (keymasterAlgorithm == -1) {
+ throw new UnrecoverableKeyException("Key algorithm unknown");
+ }
+
+ List<Integer> keymasterDigests =
+ keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST);
+ int keymasterDigest;
+ if (keymasterDigests.isEmpty()) {
+ keymasterDigest = -1;
+ } else {
+ // More than one digest can be permitted for this key. Use the first one to form the
+ // JCA key algorithm name.
+ keymasterDigest = keymasterDigests.get(0);
+ }
+
+ @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
+ try {
+ keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
+ keymasterAlgorithm, keymasterDigest);
+ } catch (IllegalArgumentException e) {
+ throw (UnrecoverableKeyException)
+ new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
+ }
+
+ return new AndroidKeyStoreSecretKey(secretKeyAlias, keyAlgorithmString);
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
index 8133d46..9fea30d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
@@ -17,6 +17,7 @@
package android.security.keystore;
import java.security.PublicKey;
+import java.util.Arrays;
/**
* {@link PublicKey} backed by Android Keystore.
@@ -41,4 +42,30 @@
public byte[] getEncoded() {
return ArrayUtils.cloneIfNotEmpty(mEncoded);
}
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = super.hashCode();
+ result = prime * result + Arrays.hashCode(mEncoded);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (!super.equals(obj)) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
+ if (!Arrays.equals(mEncoded, other.mEncoded)) {
+ return false;
+ }
+ return true;
+ }
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
new file mode 100644
index 0000000..179ffd8
--- /dev/null
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.math.BigInteger;
+import java.security.PrivateKey;
+import java.security.interfaces.RSAKey;
+
+/**
+ * RSA private key (instance of {@link PrivateKey} and {@link RSAKey}) backed by keystore.
+ *
+ * @hide
+ */
+public class AndroidKeyStoreRSAPrivateKey extends AndroidKeyStorePrivateKey implements RSAKey {
+
+ private final BigInteger mModulus;
+
+ public AndroidKeyStoreRSAPrivateKey(String alias, BigInteger modulus) {
+ super(alias, KeyProperties.KEY_ALGORITHM_RSA);
+ mModulus = modulus;
+ }
+
+ @Override
+ public BigInteger getModulus() {
+ return mModulus;
+ }
+}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
index 4c4062f..f072ae7 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
@@ -25,7 +25,7 @@
import android.security.keymaster.KeymasterDefs;
import android.security.keymaster.OperationResult;
-import com.android.org.conscrypt.util.EmptyArray;
+import libcore.util.EmptyArray;
import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index c03be63..831a106 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -16,9 +16,6 @@
package android.security.keystore;
-import com.android.org.conscrypt.OpenSSLEngine;
-import com.android.org.conscrypt.OpenSSLKeyHolder;
-
import libcore.util.EmptyArray;
import android.security.Credentials;
@@ -35,7 +32,6 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
-import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
@@ -45,6 +41,7 @@
import java.security.KeyStoreSpi;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
+import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
@@ -59,7 +56,6 @@
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.List;
import java.util.Set;
import javax.crypto.SecretKey;
@@ -92,59 +88,17 @@
public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
UnrecoverableKeyException {
if (isPrivateKeyEntry(alias)) {
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
- try {
- return engine.getPrivateKeyById(Credentials.USER_PRIVATE_KEY + alias);
- } catch (InvalidKeyException e) {
- UnrecoverableKeyException t = new UnrecoverableKeyException("Can't get key");
- t.initCause(e);
- throw t;
- }
+ String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
+ return AndroidKeyStoreProvider.loadAndroidKeyStorePrivateKeyFromKeystore(
+ mKeyStore, privateKeyAlias);
} else if (isSecretKeyEntry(alias)) {
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- String keyAliasInKeystore = Credentials.USER_SECRET_KEY + alias;
- int errorCode = mKeyStore.getKeyCharacteristics(
- keyAliasInKeystore, null, null, keyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to load information about key")
- .initCause(mKeyStore.getInvalidKeyException(alias, errorCode));
- }
-
- int keymasterAlgorithm =
- keyCharacteristics.hwEnforced.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
- if (keymasterAlgorithm == -1) {
- keymasterAlgorithm =
- keyCharacteristics.swEnforced.getInt(KeymasterDefs.KM_TAG_ALGORITHM, -1);
- }
- if (keymasterAlgorithm == -1) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- List<Integer> keymasterDigests =
- keyCharacteristics.getInts(KeymasterDefs.KM_TAG_DIGEST);
- int keymasterDigest;
- if (keymasterDigests.isEmpty()) {
- keymasterDigest = -1;
- } else {
- // More than one digest can be permitted for this key. Use the first one to form the
- // JCA key algorithm name.
- keymasterDigest = keymasterDigests.get(0);
- }
-
- @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
- try {
- keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
- keymasterAlgorithm, keymasterDigest);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
- }
-
- return new AndroidKeyStoreSecretKey(keyAliasInKeystore, keyAlgorithmString);
+ String secretKeyAlias = Credentials.USER_SECRET_KEY + alias;
+ return AndroidKeyStoreProvider.loadAndroidKeyStoreSecretKeyFromKeystore(
+ mKeyStore, secretKeyAlias);
+ } else {
+ // Key not found
+ return null;
}
-
- return null;
}
@Override
@@ -188,22 +142,36 @@
byte[] certificate = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
if (certificate != null) {
- return toCertificate(certificate);
+ return wrapIntoKeyStoreCertificate(
+ Credentials.USER_PRIVATE_KEY + alias, toCertificate(certificate));
}
certificate = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
if (certificate != null) {
- return toCertificate(certificate);
+ return wrapIntoKeyStoreCertificate(
+ Credentials.USER_PRIVATE_KEY + alias, toCertificate(certificate));
}
return null;
}
+ /**
+ * Wraps the provided cerificate into {@link KeyStoreX509Certificate} so that the public key
+ * returned by the certificate contains information about the alias of the private key in
+ * keystore. This is needed so that Android Keystore crypto operations using public keys can
+ * find out which key alias to use. These operations cannot work without an alias.
+ */
+ private static KeyStoreX509Certificate wrapIntoKeyStoreCertificate(
+ String privateKeyAlias, X509Certificate certificate) {
+ return (certificate != null)
+ ? new KeyStoreX509Certificate(privateKeyAlias, certificate) : null;
+ }
+
private static X509Certificate toCertificate(byte[] bytes) {
try {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return (X509Certificate) certFactory
- .generateCertificate(new ByteArrayInputStream(bytes));
+ return (X509Certificate) certFactory.generateCertificate(
+ new ByteArrayInputStream(bytes));
} catch (CertificateException e) {
Log.w(NAME, "Couldn't parse certificate in keystore", e);
return null;
@@ -214,8 +182,8 @@
private static Collection<X509Certificate> toCertificates(byte[] bytes) {
try {
final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return (Collection<X509Certificate>) certFactory
- .generateCertificates(new ByteArrayInputStream(bytes));
+ return (Collection<X509Certificate>) certFactory.generateCertificates(
+ new ByteArrayInputStream(bytes));
} catch (CertificateException e) {
Log.w(NAME, "Couldn't parse certificates in keystore", e);
return new ArrayList<X509Certificate>();
@@ -406,9 +374,7 @@
}
final String pkeyAlias;
- if (key instanceof OpenSSLKeyHolder) {
- pkeyAlias = ((OpenSSLKeyHolder) key).getOpenSSLKey().getAlias();
- } else if (key instanceof AndroidKeyStorePrivateKey) {
+ if (key instanceof AndroidKeyStorePrivateKey) {
pkeyAlias = ((AndroidKeyStoreKey) key).getAlias();
} else {
pkeyAlias = null;
@@ -851,6 +817,19 @@
if (cert == null) {
return null;
}
+ if (!"X.509".equalsIgnoreCase(cert.getType())) {
+ // Only X.509 certificates supported
+ return null;
+ }
+ byte[] targetCertBytes;
+ try {
+ targetCertBytes = cert.getEncoded();
+ } catch (CertificateEncodingException e) {
+ return null;
+ }
+ if (targetCertBytes == null) {
+ return null;
+ }
final Set<String> nonCaEntries = new HashSet<String>();
@@ -868,10 +847,9 @@
continue;
}
- final Certificate c = toCertificate(certBytes);
nonCaEntries.add(alias);
- if (cert.equals(c)) {
+ if (Arrays.equals(certBytes, targetCertBytes)) {
return alias;
}
}
@@ -893,9 +871,7 @@
continue;
}
- final Certificate c =
- toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
- if (cert.equals(c)) {
+ if (Arrays.equals(certBytes, targetCertBytes)) {
return alias;
}
}
@@ -954,4 +930,25 @@
}
}
+ /**
+ * {@link X509Certificate} which returns {@link AndroidKeyStorePublicKey} from
+ * {@link #getPublicKey()}. This is so that crypto operations on these public keys contain
+ * can find out which keystore private key entry to use. This is needed so that Android Keystore
+ * crypto operations using public keys can find out which key alias to use. These operations
+ * require an alias.
+ */
+ static class KeyStoreX509Certificate extends DelegatingX509Certificate {
+ private final String mPrivateKeyAlias;
+ KeyStoreX509Certificate(String privateKeyAlias, X509Certificate delegate) {
+ super(delegate);
+ mPrivateKeyAlias = privateKeyAlias;
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ PublicKey original = super.getPublicKey();
+ return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+ mPrivateKeyAlias, original.getAlgorithm(), original.getEncoded());
+ }
+ }
}
diff --git a/keystore/java/android/security/keystore/DelegatingX509Certificate.java b/keystore/java/android/security/keystore/DelegatingX509Certificate.java
new file mode 100644
index 0000000..03d202f
--- /dev/null
+++ b/keystore/java/android/security/keystore/DelegatingX509Certificate.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.keystore;
+
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import javax.security.auth.x500.X500Principal;
+
+class DelegatingX509Certificate extends X509Certificate {
+ private final X509Certificate mDelegate;
+
+ DelegatingX509Certificate(X509Certificate delegate) {
+ mDelegate = delegate;
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ return mDelegate.getCriticalExtensionOIDs();
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return mDelegate.getExtensionValue(oid);
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ return mDelegate.getNonCriticalExtensionOIDs();
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ return mDelegate.hasUnsupportedCriticalExtension();
+ }
+
+ @Override
+ public void checkValidity() throws CertificateExpiredException,
+ CertificateNotYetValidException {
+ mDelegate.checkValidity();
+ }
+
+ @Override
+ public void checkValidity(Date date) throws CertificateExpiredException,
+ CertificateNotYetValidException {
+ mDelegate.checkValidity(date);
+ }
+
+ @Override
+ public int getBasicConstraints() {
+ return mDelegate.getBasicConstraints();
+ }
+
+ @Override
+ public Principal getIssuerDN() {
+ return mDelegate.getIssuerDN();
+ }
+
+ @Override
+ public boolean[] getIssuerUniqueID() {
+ return mDelegate.getIssuerUniqueID();
+ }
+
+ @Override
+ public boolean[] getKeyUsage() {
+ return mDelegate.getKeyUsage();
+ }
+
+ @Override
+ public Date getNotAfter() {
+ return mDelegate.getNotAfter();
+ }
+
+ @Override
+ public Date getNotBefore() {
+ return mDelegate.getNotBefore();
+ }
+
+ @Override
+ public BigInteger getSerialNumber() {
+ return mDelegate.getSerialNumber();
+ }
+
+ @Override
+ public String getSigAlgName() {
+ return mDelegate.getSigAlgName();
+ }
+
+ @Override
+ public String getSigAlgOID() {
+ return mDelegate.getSigAlgOID();
+ }
+
+ @Override
+ public byte[] getSigAlgParams() {
+ return mDelegate.getSigAlgParams();
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return mDelegate.getSignature();
+ }
+
+ @Override
+ public Principal getSubjectDN() {
+ return mDelegate.getSubjectDN();
+ }
+
+ @Override
+ public boolean[] getSubjectUniqueID() {
+ return mDelegate.getSubjectUniqueID();
+ }
+
+ @Override
+ public byte[] getTBSCertificate() throws CertificateEncodingException {
+ return mDelegate.getTBSCertificate();
+ }
+
+ @Override
+ public int getVersion() {
+ return mDelegate.getVersion();
+ }
+
+ @Override
+ public byte[] getEncoded() throws CertificateEncodingException {
+ return mDelegate.getEncoded();
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ return mDelegate.getPublicKey();
+ }
+
+ @Override
+ public String toString() {
+ return mDelegate.toString();
+ }
+
+ @Override
+ public void verify(PublicKey key)
+ throws CertificateException,
+ NoSuchAlgorithmException,
+ InvalidKeyException,
+ NoSuchProviderException,
+ SignatureException {
+ mDelegate.verify(key);
+ }
+
+ @Override
+ public void verify(PublicKey key, String sigProvider)
+ throws CertificateException,
+ NoSuchAlgorithmException,
+ InvalidKeyException,
+ NoSuchProviderException,
+ SignatureException {
+ mDelegate.verify(key, sigProvider);
+ }
+
+ @Override
+ public List<String> getExtendedKeyUsage() throws CertificateParsingException {
+ return mDelegate.getExtendedKeyUsage();
+ }
+
+ @Override
+ public Collection<List<?>> getIssuerAlternativeNames() throws CertificateParsingException {
+ return mDelegate.getIssuerAlternativeNames();
+ }
+
+ @Override
+ public X500Principal getIssuerX500Principal() {
+ return mDelegate.getIssuerX500Principal();
+ }
+
+ @Override
+ public Collection<List<?>> getSubjectAlternativeNames() throws CertificateParsingException {
+ return mDelegate.getSubjectAlternativeNames();
+ }
+
+ @Override
+ public X500Principal getSubjectX500Principal() {
+ return mDelegate.getSubjectX500Principal();
+ }
+}
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 44fb826..0b60c62 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -20,7 +20,6 @@
import android.os.Binder;
import android.os.IBinder;
import android.os.Process;
-import android.os.ServiceManager;
import android.security.keymaster.ExportResult;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterArguments;
@@ -34,13 +33,9 @@
import com.android.org.conscrypt.NativeConstants;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
-import java.util.Date;
import java.util.HashSet;
import java.security.spec.RSAKeyGenParameterSpec;
-import android.util.Log;
-import android.util.Base64;
-
/**
* Junit / Instrumentation test case for KeyStore class
*
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
index 8488acd..e5c15c5 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
@@ -26,17 +26,21 @@
import java.io.ByteArrayInputStream;
import java.math.BigInteger;
import java.security.KeyPair;
+import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
+import java.security.interfaces.ECKey;
import java.security.interfaces.ECPublicKey;
+import java.security.interfaces.RSAKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.RSAKeyGenParameterSpec;
import java.text.SimpleDateFormat;
+import java.util.Arrays;
import java.util.Date;
import javax.security.auth.x500.X500Principal;
@@ -158,6 +162,26 @@
}
public void testKeyPairGenerator_GenerateKeyPair_EC_Unencrypted_Success() throws Exception {
+ KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
+ generator.initialize(new KeyGenParameterSpec.Builder(
+ TEST_ALIAS_1,
+ KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
+ .setCertificateSubject(TEST_DN_1)
+ .setCertificateSerialNumber(TEST_SERIAL_1)
+ .setCertificateNotBefore(NOW)
+ .setCertificateNotAfter(NOW_PLUS_10_YEARS)
+ .setDigests(KeyProperties.DIGEST_SHA256)
+ .build());
+
+ final KeyPair pair = generator.generateKeyPair();
+ assertNotNull("The KeyPair returned should not be null", pair);
+
+ assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW,
+ NOW_PLUS_10_YEARS);
+ }
+
+ public void testKeyPairGenerator_Legacy_GenerateKeyPair_EC_Unencrypted_Success()
+ throws Exception {
mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
.setAlias(TEST_ALIAS_1)
.setKeyType("EC")
@@ -328,19 +352,40 @@
assertNotNull("The PrivateKey for the KeyPair should be not null", privKey);
assertEquals(keyType, privKey.getAlgorithm());
+ if ("EC".equalsIgnoreCase(keyType)) {
+ assertTrue("EC private key must be instanceof ECKey: " + privKey.getClass().getName(),
+ privKey instanceof ECKey);
+ assertEquals("Private and public key must have the same EC parameters",
+ ((ECKey) pubKey).getParams(), ((ECKey) privKey).getParams());
+ } else if ("RSA".equalsIgnoreCase(keyType)) {
+ assertTrue("RSA private key must be instance of RSAKey: "
+ + privKey.getClass().getName(),
+ privKey instanceof RSAKey);
+ assertEquals("Private and public key must have the same RSA modulus",
+ ((RSAKey) pubKey).getModulus(), ((RSAKey) privKey).getModulus());
+ }
+
final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias);
assertNotNull("The user certificate should exist for the generated entry", userCertBytes);
final CertificateFactory cf = CertificateFactory.getInstance("X.509");
- final Certificate userCert = cf
- .generateCertificate(new ByteArrayInputStream(userCertBytes));
+ final Certificate userCert =
+ cf.generateCertificate(new ByteArrayInputStream(userCertBytes));
assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate);
final X509Certificate x509userCert = (X509Certificate) userCert;
+ assertEquals(
+ "Public key used to sign certificate should have the same algorithm as in KeyPair",
+ pubKey.getAlgorithm(), x509userCert.getPublicKey().getAlgorithm());
+
assertEquals("PublicKey used to sign certificate should match one returned in KeyPair",
- pubKey, x509userCert.getPublicKey());
+ pubKey,
+ AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
+ Credentials.USER_PRIVATE_KEY + alias,
+ x509userCert.getPublicKey().getAlgorithm(),
+ x509userCert.getPublicKey().getEncoded()));
assertEquals("The Subject DN should be the one passed into the params", dn,
x509userCert.getSubjectDN());
@@ -357,7 +402,10 @@
assertDateEquals("The notAfter date should be the one passed into the params", end,
x509userCert.getNotAfter());
+ // Assert that the cert's signature verifies using the public key from generated KeyPair
x509userCert.verify(pubKey);
+ // Assert that the cert's signature verifies using the public key from the cert itself.
+ x509userCert.verify(x509userCert.getPublicKey());
final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
@@ -368,6 +416,8 @@
final byte[] pubKeyBytes = exportResult.exportData;
assertNotNull("The keystore should return the public key for the generated key",
pubKeyBytes);
+ assertTrue("Public key X.509 format should be as expected",
+ Arrays.equals(pubKey.getEncoded(), pubKeyBytes));
}
private static void assertDateEquals(String message, Date date1, Date date2) throws Exception {
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
index 336fa40..c3b731b 100644
--- a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
+++ b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
@@ -19,38 +19,31 @@
import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
import com.android.org.conscrypt.NativeConstants;
-import com.android.org.conscrypt.OpenSSLEngine;
import android.security.Credentials;
import android.security.KeyStore;
import android.security.KeyStoreParameter;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeymasterDefs;
import android.test.AndroidTestCase;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.math.BigInteger;
-import java.security.InvalidKeyException;
import java.security.Key;
import java.security.KeyFactory;
+import java.security.KeyPair;
import java.security.KeyStore.Entry;
import java.security.KeyStore.PrivateKeyEntry;
import java.security.KeyStore.TrustedCertificateEntry;
import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAPrivateKey;
-import java.security.spec.InvalidKeySpecException;
+import java.security.interfaces.ECKey;
+import java.security.interfaces.RSAKey;
import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
@@ -1203,14 +1196,14 @@
private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
- if (expectedKey instanceof ECPrivateKey) {
+ if (expectedKey instanceof ECKey) {
assertEquals("Returned PrivateKey should be what we inserted",
- ((ECPrivateKey) expectedKey).getParams().getCurve(),
- ((ECPublicKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
- } else if (expectedKey instanceof RSAPrivateKey) {
+ ((ECKey) expectedKey).getParams().getCurve(),
+ ((ECKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
+ } else if (expectedKey instanceof RSAKey) {
assertEquals("Returned PrivateKey should be what we inserted",
- ((RSAPrivateKey) expectedKey).getModulus(),
- ((RSAPrivateKey) keyEntry.getPrivateKey()).getModulus());
+ ((RSAKey) expectedKey).getModulus(),
+ ((RSAKey) keyEntry.getPrivateKey()).getModulus());
}
assertEquals("Returned Certificate should be what we inserted", expectedCert,
@@ -1263,15 +1256,14 @@
Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
assertNotNull("Key should exist", key);
- assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
-
- RSAPrivateKey actualKey = (RSAPrivateKey) key;
+ assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+ assertTrue("Should be a RSAKey", key instanceof RSAKey);
KeyFactory keyFact = KeyFactory.getInstance("RSA");
PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
assertEquals("Inserted key should be same as retrieved key",
- ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+ ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
}
public void testKeyStore_GetKey_NoPassword_Unencrypted_Success() throws Exception {
@@ -1287,15 +1279,14 @@
Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
assertNotNull("Key should exist", key);
- assertTrue("Should be a RSAPrivateKey", key instanceof RSAPrivateKey);
-
- RSAPrivateKey actualKey = (RSAPrivateKey) key;
+ assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
+ assertTrue("Should be a RSAKey", key instanceof RSAKey);
KeyFactory keyFact = KeyFactory.getInstance("RSA");
PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
assertEquals("Inserted key should be same as retrieved key",
- ((RSAPrivateKey) expectedKey).getModulus(), actualKey.getModulus());
+ ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
}
public void testKeyStore_GetKey_Certificate_Encrypted_Failure() throws Exception {
@@ -1926,31 +1917,11 @@
Date notAfter) throws Exception {
final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
- final PrivateKey privKey;
- final OpenSSLEngine engine = OpenSSLEngine.getInstance("keystore");
- try {
- privKey = engine.getPrivateKeyById(privateKeyAlias);
- } catch (InvalidKeyException e) {
- throw new RuntimeException("Can't get key", e);
- }
-
- ExportResult exportResult =
- keyStore.exportKey(privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
- assertEquals(KeyStore.NO_ERROR, exportResult.resultCode);
- final byte[] pubKeyBytes = exportResult.exportData;
-
- final PublicKey pubKey;
- try {
- final KeyFactory keyFact = KeyFactory.getInstance("RSA");
- pubKey = keyFact.generatePublic(new X509EncodedKeySpec(pubKeyBytes));
- } catch (NoSuchAlgorithmException e) {
- throw new IllegalStateException("Can't instantiate RSA key generator", e);
- } catch (InvalidKeySpecException e) {
- throw new IllegalStateException("keystore returned invalid key encoding", e);
- }
+ KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
+ keyStore, privateKeyAlias);
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
- certGen.setPublicKey(pubKey);
+ certGen.setPublicKey(keyPair.getPublic());
certGen.setSerialNumber(serialNumber);
certGen.setSubjectDN(subjectDN);
certGen.setIssuerDN(subjectDN);
@@ -1958,7 +1929,7 @@
certGen.setNotAfter(notAfter);
certGen.setSignatureAlgorithm("sha1WithRSA");
- final X509Certificate cert = certGen.generate(privKey);
+ final X509Certificate cert = certGen.generate(keyPair.getPrivate());
return cert;
}
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 89d419a..6c26220 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1382,7 +1382,7 @@
// upper limit.
// for now we are keeping the profile specific "width/height
// in macroblocks" limits.
- if (Integer.valueOf(1).equals(map.get("feature-can-swap-width-height"))) {
+ if (map.containsKey("feature-can-swap-width-height")) {
if (widths != null) {
mSmallerDimensionUpperLimit =
Math.min(widths.getUpper(), heights.getUpper());
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index ef8d169..ba867e1 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -375,7 +375,7 @@
* @param mediaId The id of the item to retrieve.
* @param cb The callback to receive the result on.
*/
- public void getMediaItem(@NonNull String mediaId, @NonNull final MediaItemCallback cb) {
+ public void getItem(final @NonNull String mediaId, @NonNull final ItemCallback cb) {
if (TextUtils.isEmpty(mediaId)) {
throw new IllegalArgumentException("mediaId is empty.");
}
@@ -387,7 +387,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- cb.onError();
+ cb.onError(mediaId);
}
});
return;
@@ -397,15 +397,15 @@
protected void onReceiveResult(int resultCode, Bundle resultData) {
if (resultCode != 0 || resultData == null
|| !resultData.containsKey(MediaBrowserService.KEY_MEDIA_ITEM)) {
- cb.onError();
+ cb.onError(mediaId);
return;
}
Parcelable item = resultData.getParcelable(MediaBrowserService.KEY_MEDIA_ITEM);
if (!(item instanceof MediaItem)) {
- cb.onError();
+ cb.onError(mediaId);
+ return;
}
- cb.onMediaItemLoaded((MediaItem) resultData.getParcelable(
- MediaBrowserService.KEY_MEDIA_ITEM));
+ cb.onItemLoaded((MediaItem)item);
}
};
try {
@@ -415,7 +415,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- cb.onError();
+ cb.onError(mediaId);
}
});
}
@@ -728,6 +728,9 @@
public static abstract class SubscriptionCallback {
/**
* Called when the list of children is loaded or updated.
+ *
+ * @param parentId The media id of the parent media item.
+ * @param children The children which were loaded.
*/
public void onChildrenLoaded(@NonNull String parentId,
@NonNull List<MediaItem> children) {
@@ -739,29 +742,32 @@
* If this is called, the subscription remains until {@link MediaBrowser#unsubscribe}
* called, because some errors may heal themselves.
* </p>
+ *
+ * @param parentId The media id of the parent media item whose children could
+ * not be loaded.
*/
- public void onError(@NonNull String id) {
+ public void onError(@NonNull String parentId) {
}
}
/**
- * Callback for receiving the result of {@link #getMediaItem}.
+ * Callback for receiving the result of {@link #getItem}.
*/
- public static abstract class MediaItemCallback {
-
+ public static abstract class ItemCallback {
/**
* Called when the item has been returned by the browser service.
*
* @param item The item that was returned or null if it doesn't exist.
*/
- public void onMediaItemLoaded(MediaItem item) {
+ public void onItemLoaded(MediaItem item) {
}
/**
- * Called when the id doesn't exist or there was an error retrieving the
- * item.
+ * Called when the item doesn't exist or there was an error retrieving it.
+ *
+ * @param itemId The media id of the media item which could not be loaded.
*/
- public void onError() {
+ public void onError(@NonNull String itemId) {
}
}
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index c537dd6..5d1aa14 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -29,6 +29,7 @@
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.Icon;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.net.Uri;
import android.os.Parcel;
@@ -125,7 +126,9 @@
private String mSettingsActivity;
private HdmiDeviceInfo mHdmiDeviceInfo;
+ private int mLabelRes;
private String mLabel;
+ private Icon mIcon;
private Uri mIconUri;
private boolean mIsConnectedToHdmiSwitch;
@@ -155,7 +158,7 @@
throws XmlPullParserException, IOException {
return createTvInputInfo(context, service, generateInputIdForComponentName(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name)),
- null, TYPE_TUNER, false, null, null, false);
+ null, TYPE_TUNER, false, 0, null, null, null, false);
}
/**
@@ -165,11 +168,11 @@
* @param service The ResolveInfo returned from the package manager about this TV input service.
* @param hdmiDeviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
* @param parentId The ID of this TV input's parent input. {@code null} if none exists.
+ * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
+ * label will be loaded.
* @param iconUri The {@link android.net.Uri} to load the icon image. See
* {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
* the application icon of {@code service} will be loaded.
- * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
- * label will be loaded.
* @hide
*/
@SystemApi
@@ -179,7 +182,34 @@
boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
- hdmiDeviceInfo), parentId, TYPE_HDMI, true, label, iconUri, isConnectedToHdmiSwitch);
+ hdmiDeviceInfo), parentId, TYPE_HDMI, true, 0, label, null, iconUri,
+ isConnectedToHdmiSwitch);
+ input.mHdmiDeviceInfo = hdmiDeviceInfo;
+ return input;
+ }
+
+ /**
+ * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
+ * ResolveInfo, and HdmiDeviceInfo.
+ *
+ * @param service The ResolveInfo returned from the package manager about this TV input service.
+ * @param hdmiDeviceInfo The HdmiDeviceInfo for a HDMI CEC logical device.
+ * @param parentId The ID of this TV input's parent input. {@code null} if none exists.
+ * @param labelRes The label resource ID of this TvInputInfo. If it is {@code 0},
+ * {@code service} label will be loaded.
+ * @param icon The {@link android.graphics.drawable.Icon} to load the icon image. If it is
+ * {@code null}, the application icon of {@code service} will be loaded.
+ * @hide
+ */
+ @SystemApi
+ public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
+ HdmiDeviceInfo hdmiDeviceInfo, String parentId, int labelRes, Icon icon)
+ throws XmlPullParserException, IOException {
+ boolean isConnectedToHdmiSwitch = (hdmiDeviceInfo.getPhysicalAddress() & 0x0FFF) != 0;
+ TvInputInfo input = createTvInputInfo(context, service, generateInputIdForHdmiDevice(
+ new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
+ hdmiDeviceInfo), parentId, TYPE_HDMI, true, labelRes, null, icon, null,
+ isConnectedToHdmiSwitch);
input.mHdmiDeviceInfo = hdmiDeviceInfo;
return input;
}
@@ -190,11 +220,11 @@
*
* @param service The ResolveInfo returned from the package manager about this TV input service.
* @param hardwareInfo The TvInputHardwareInfo for a TV input hardware device.
+ * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
+ * label will be loaded.
* @param iconUri The {@link android.net.Uri} to load the icon image. See
* {@link android.content.ContentResolver#openInputStream}. If it is {@code null},
* the application icon of {@code service} will be loaded.
- * @param label The label of this TvInputInfo. If it is {@code null} or empty, {@code service}
- * label will be loaded.
* @hide
*/
@SystemApi
@@ -204,12 +234,34 @@
int inputType = sHardwareTypeToTvInputType.get(hardwareInfo.getType(), TYPE_TUNER);
return createTvInputInfo(context, service, generateInputIdForHardware(
new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
- hardwareInfo), null, inputType, true, label, iconUri, false);
+ hardwareInfo), null, inputType, true, 0, label, null, iconUri, false);
}
- private static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
- String id, String parentId, int inputType, boolean isHardwareInput, String label,
- Uri iconUri, boolean isConnectedToHdmiSwitch)
+ /**
+ * Create a new instance of the TvInputInfo class, instantiating it from the given Context,
+ * ResolveInfo, and TvInputHardwareInfo.
+ *
+ * @param service The ResolveInfo returned from the package manager about this TV input service.
+ * @param hardwareInfo The TvInputHardwareInfo for a TV input hardware device.
+ * @param labelRes The label resource ID of this TvInputInfo. If it is {@code 0},
+ * {@code service} label will be loaded.
+ * @param icon The {@link android.graphics.drawable.Icon} to load the icon image. If it is
+ * {@code null}, the application icon of {@code service} will be loaded.
+ * @hide
+ */
+ @SystemApi
+ public static TvInputInfo createTvInputInfo(Context context, ResolveInfo service,
+ TvInputHardwareInfo hardwareInfo, int labelRes, Icon icon)
+ throws XmlPullParserException, IOException {
+ int inputType = sHardwareTypeToTvInputType.get(hardwareInfo.getType(), TYPE_TUNER);
+ return createTvInputInfo(context, service, generateInputIdForHardware(
+ new ComponentName(service.serviceInfo.packageName, service.serviceInfo.name),
+ hardwareInfo), null, inputType, true, labelRes, null, icon, null, false);
+ }
+
+ private static TvInputInfo createTvInputInfo(Context context, ResolveInfo service, String id,
+ String parentId, int inputType, boolean isHardwareInput, int labelRes, String label,
+ Icon icon, Uri iconUri, boolean isConnectedToHdmiSwitch)
throws XmlPullParserException, IOException {
ServiceInfo si = service.serviceInfo;
PackageManager pm = context.getPackageManager();
@@ -254,7 +306,9 @@
}
sa.recycle();
+ input.mLabelRes = labelRes;
input.mLabel = label;
+ input.mIcon = icon;
input.mIconUri = iconUri;
input.mIsConnectedToHdmiSwitch = isConnectedToHdmiSwitch;
return input;
@@ -426,11 +480,13 @@
* a label, its name is returned.
*/
public CharSequence loadLabel(@NonNull Context context) {
- if (TextUtils.isEmpty(mLabel)) {
- return mService.loadLabel(context.getPackageManager());
- } else {
+ if (mLabelRes != 0) {
+ return context.getPackageManager().getText(mService.serviceInfo.packageName, mLabelRes,
+ null);
+ } else if (!TextUtils.isEmpty(mLabel)) {
return mLabel;
}
+ return mService.loadLabel(context.getPackageManager());
}
/**
@@ -454,19 +510,20 @@
* application's icon is returned. If it's unavailable too, {@code null} is returned.
*/
public Drawable loadIcon(@NonNull Context context) {
- if (mIconUri == null) {
- return loadServiceIcon(context);
- }
- try (InputStream is = context.getContentResolver().openInputStream(mIconUri)) {
- Drawable drawable = Drawable.createFromStream(is, null);
- if (drawable == null) {
- return loadServiceIcon(context);
+ if (mIcon != null) {
+ return mIcon.loadDrawable(context);
+ } else if (mIconUri != null) {
+ try (InputStream is = context.getContentResolver().openInputStream(mIconUri)) {
+ Drawable drawable = Drawable.createFromStream(is, null);
+ if (drawable != null) {
+ return drawable;
+ }
+ } catch (IOException e) {
+ Log.w(TAG, "Loading the default icon due to a failure on loading " + mIconUri, e);
+ // Falls back.
}
- return drawable;
- } catch (IOException e) {
- Log.w(TAG, "Loading the default icon due to a failure on loading " + mIconUri, e);
- return loadServiceIcon(context);
}
+ return loadServiceIcon(context);
}
@Override
@@ -516,7 +573,9 @@
dest.writeInt(mType);
dest.writeByte(mIsHardwareInput ? (byte) 1 : 0);
dest.writeParcelable(mHdmiDeviceInfo, flags);
+ dest.writeParcelable(mIcon, flags);
dest.writeParcelable(mIconUri, flags);
+ dest.writeInt(mLabelRes);
dest.writeString(mLabel);
dest.writeByte(mIsConnectedToHdmiSwitch ? (byte) 1 : 0);
}
@@ -591,7 +650,9 @@
mType = in.readInt();
mIsHardwareInput = in.readByte() == 1 ? true : false;
mHdmiDeviceInfo = in.readParcelable(null);
+ mIcon = in.readParcelable(null);
mIconUri = in.readParcelable(null);
+ mLabelRes = in.readInt();
mLabel = in.readString();
mIsConnectedToHdmiSwitch = in.readByte() == 1 ? true : false;
}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 41156cb..1bb99ff 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -76,7 +76,7 @@
public static final String SERVICE_INTERFACE = "android.media.browse.MediaBrowserService";
/**
- * A key for passing the MediaItem to the ResultReceiver in getMediaItem.
+ * A key for passing the MediaItem to the ResultReceiver in getItem.
*
* @hide
*/
@@ -109,6 +109,7 @@
* be thrown.
*
* @see MediaBrowserService#onLoadChildren
+ * @see MediaBrowserService#onGetMediaItem
*/
public class Result<T> {
private Object mDebug;
@@ -279,20 +280,7 @@
mHandler.post(new Runnable() {
@Override
public void run() {
- final Result<MediaBrowser.MediaItem> result
- = new Result<MediaBrowser.MediaItem>(mediaId) {
- @Override
- void onResultSent(MediaBrowser.MediaItem item) {
- Bundle bundle = new Bundle();
- bundle.putParcelable(KEY_MEDIA_ITEM, item);
- receiver.send(0, bundle);
- }
- };
- try {
- MediaBrowserService.this.getMediaItem(mediaId, result);
- } catch (UnsupportedOperationException e) {
- receiver.send(-1, null);
- }
+ performLoadItem(mediaId, receiver);
}
});
}
@@ -357,8 +345,7 @@
@NonNull Result<List<MediaBrowser.MediaItem>> result);
/**
- * Called to get a specific media item. The mediaId should be the same id
- * that would be returned for this item when it is in a list of child items.
+ * Called to get information about a specific media item.
* <p>
* Implementations must call {@link Result#sendResult result.sendResult}. If
* loading the item will be an expensive operation {@link Result#detach
@@ -366,17 +353,15 @@
* then {@link Result#sendResult result.sendResult} called when the item has
* been loaded.
* <p>
- * The default implementation throws an exception.
+ * The default implementation sends a null result.
*
- * @param mediaId The id for the specific
+ * @param itemId The id for the specific
* {@link android.media.browse.MediaBrowser.MediaItem}.
* @param result The Result to send the item to, or null if the id is
* invalid.
- * @throws UnsupportedOperationException
*/
- public void getMediaItem(String mediaId, Result<MediaBrowser.MediaItem> result)
- throws UnsupportedOperationException {
- throw new UnsupportedOperationException("getMediaItem is not supported.");
+ public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
+ result.sendResult(null);
}
/**
@@ -515,6 +500,25 @@
}
}
+ private void performLoadItem(String itemId, final ResultReceiver receiver) {
+ final Result<MediaBrowser.MediaItem> result =
+ new Result<MediaBrowser.MediaItem>(itemId) {
+ @Override
+ void onResultSent(MediaBrowser.MediaItem item) {
+ Bundle bundle = new Bundle();
+ bundle.putParcelable(KEY_MEDIA_ITEM, item);
+ receiver.send(0, bundle);
+ }
+ };
+
+ MediaBrowserService.this.onLoadItem(itemId, result);
+
+ if (!result.isDone()) {
+ throw new IllegalStateException("onLoadItem must call detach() or sendResult()"
+ + " before returning for id=" + itemId);
+ }
+ }
+
/**
* Contains information that the browser service needs to send to the client
* when first connected.
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 294cd84..634ba64 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -293,7 +293,8 @@
res = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
if (res != OK) {
ALOGE("%s: Configure usage %08x for format %08x failed: %s (%d)",
- __FUNCTION__, GRALLOC_USAGE_SW_WRITE_OFTEN, format, strerror(-res), res);
+ __FUNCTION__, static_cast<unsigned int>(GRALLOC_USAGE_SW_WRITE_OFTEN),
+ format, strerror(-res), res);
jniThrowRuntimeException(env, "Failed to SW_WRITE_OFTEN configure usage");
return 0;
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
index bcfcbf3..8f7d6ac 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
@@ -60,6 +60,7 @@
private static boolean onPrepareSuccess = false;
public static boolean onCompleteSuccess = false;
public static boolean mPlaybackError = false;
+ public static boolean mFailedToCompleteWithNoError = true;
public static int mMediaInfoUnknownCount = 0;
public static int mMediaInfoVideoTrackLaggingCount = 0;
public static int mMediaInfoBadInterleavingCount = 0;
@@ -801,6 +802,7 @@
mMediaInfoNotSeekableCount = 0;
mMediaInfoMetdataUpdateCount = 0;
mPlaybackError = false;
+ mFailedToCompleteWithNoError = true;
String testResult;
initializeMessageLooper();
@@ -843,6 +845,9 @@
} catch (Exception e) {
Log.v(TAG, "playMediaSamples:" + e.getMessage());
}
+ // Check if playback state is unknown (neither completed nor erroneous) unless
+ // it's not interrupted in the middle. If true, that is an exceptional case to investigate.
+ mFailedToCompleteWithNoError = !(onCompleteSuccess || mPlaybackError);
return onCompleteSuccess;
}
}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
index e289812..4221f1b 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/stress/MediaPlayerStressTest.java
@@ -65,6 +65,7 @@
private int mTotalBadInterleaving = 0;
private int mTotalNotSeekable = 0;
private int mTotalMetaDataUpdate = 0;
+ private int mTotalFailedToCompleteWithNoError = 0;
//Test result output file
private static final String PLAYBACK_RESULT = "PlaybackTestResult.txt";
@@ -78,6 +79,8 @@
output.write(" Bad Interleaving: " + CodecTest.mMediaInfoBadInterleavingCount);
output.write(" Not Seekable: " + CodecTest.mMediaInfoNotSeekableCount);
output.write(" Info Meta data update: " + CodecTest.mMediaInfoMetdataUpdateCount);
+ output.write(" Failed To Complete With No Error: " +
+ CodecTest.mFailedToCompleteWithNoError);
output.write("\n");
}
@@ -90,16 +93,21 @@
output.write("Total Bad Interleaving: " + mTotalBadInterleaving + "\n");
output.write("Total Not Seekable: " + mTotalNotSeekable + "\n");
output.write("Total Info Meta data update: " + mTotalMetaDataUpdate + "\n");
+ output.write("Total Failed To Complete With No Error: " +
+ mTotalFailedToCompleteWithNoError);
output.write("\n");
}
private void updateTestResult(){
- if (CodecTest.onCompleteSuccess){
+ if (CodecTest.onCompleteSuccess) {
mTotalComplete++;
}
- else if (CodecTest.mPlaybackError){
+ else if (CodecTest.mPlaybackError) {
mTotalPlaybackError++;
}
+ else if (CodecTest.mFailedToCompleteWithNoError) {
+ mTotalFailedToCompleteWithNoError++;
+ }
mTotalInfoUnknown += CodecTest.mMediaInfoUnknownCount;
mTotalVideoTrackLagging += CodecTest.mMediaInfoVideoTrackLaggingCount;
mTotalBadInterleaving += CodecTest.mMediaInfoBadInterleavingCount;
@@ -149,4 +157,4 @@
assertTrue("testMediaSamples", testResult);
}
}
-}
\ No newline at end of file
+}
diff --git a/packages/DocumentsUI/res/layout-sw720dp/activity.xml b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
index a9f1b3c..2a273f4 100644
--- a/packages/DocumentsUI/res/layout-sw720dp/activity.xml
+++ b/packages/DocumentsUI/res/layout-sw720dp/activity.xml
@@ -19,7 +19,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <Toolbar
+ <com.android.documentsui.DocumentsToolBar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
@@ -34,7 +34,7 @@
android:layout_marginStart="4dp"
android:overlapAnchor="true" />
- </Toolbar>
+ </com.android.documentsui.DocumentsToolBar>
<LinearLayout
android:layout_width="match_parent"
diff --git a/packages/DocumentsUI/res/layout/activity.xml b/packages/DocumentsUI/res/layout/activity.xml
index b549cd3..43fdaf2 100644
--- a/packages/DocumentsUI/res/layout/activity.xml
+++ b/packages/DocumentsUI/res/layout/activity.xml
@@ -24,7 +24,7 @@
android:layout_height="match_parent"
android:orientation="vertical">
- <Toolbar
+ <com.android.documentsui.DocumentsToolBar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?android:attr/actionBarSize"
@@ -39,7 +39,7 @@
android:layout_marginStart="4dp"
android:overlapAnchor="true" />
- </Toolbar>
+ </com.android.documentsui.DocumentsToolBar>
<com.android.documentsui.DirectoryContainerView
android:id="@+id/container_directory"
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 8ea5816..bba33be 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -101,7 +101,7 @@
boolean showMenu = super.onCreateOptionsMenu(menu);
getMenuInflater().inflate(R.menu.activity, menu);
- mSearchManager.install(menu.findItem(R.id.menu_search));
+ mSearchManager.install((DocumentsToolBar) findViewById(R.id.toolbar));
return showMenu;
}
@@ -666,20 +666,24 @@
* Facade over the various search parts in the menu.
*/
final class SearchManager implements
- SearchView.OnCloseListener, OnActionExpandListener, OnQueryTextListener {
+ SearchView.OnCloseListener, OnActionExpandListener, OnQueryTextListener,
+ DocumentsToolBar.OnActionViewCollapsedListener {
private boolean mSearchExpanded;
private boolean mIgnoreNextClose;
private boolean mIgnoreNextCollapse;
+ private DocumentsToolBar mActionBar;
private MenuItem mMenu;
private SearchView mView;
- public void install(MenuItem menu) {
- assert(mMenu == null);
- mMenu = menu;
- mView = (SearchView) menu.getActionView();
+ public void install(DocumentsToolBar actionBar) {
+ assert(mActionBar == null);
+ mActionBar = actionBar;
+ mMenu = actionBar.getSearchMenu();
+ mView = (SearchView) mMenu.getActionView();
+ mActionBar.setOnActionViewCollapsedListener(this);
mMenu.setOnActionExpandListener(this);
mView.setOnQueryTextListener(this);
mView.setOnCloseListener(this);
@@ -730,6 +734,19 @@
}
}
+ /**
+ * Cancels current search operation.
+ * @return True if it cancels search. False if it does not operate
+ * search currently.
+ */
+ boolean cancelSearch() {
+ if (mActionBar.hasExpandedActionView()) {
+ mActionBar.collapseActionView();
+ return true;
+ }
+ return false;
+ }
+
boolean isSearching() {
return getDisplayState().currentSearch != null;
}
@@ -765,7 +782,6 @@
mIgnoreNextCollapse = false;
return true;
}
-
getDisplayState().currentSearch = null;
onCurrentDirectoryChanged(ANIM_NONE);
return true;
@@ -784,5 +800,10 @@
public boolean onQueryTextChange(String newText) {
return false;
}
+
+ @Override
+ public void onActionViewCollapsed() {
+ updateActionBar();
+ }
}
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 69ae34e..90ccf91 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -31,6 +31,7 @@
import java.util.Arrays;
import java.util.List;
+import android.app.ActionBar;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
@@ -508,6 +509,11 @@
@Override
public void onBackPressed() {
+ // While action bar is expanded, the state stack UI is hidden.
+ if (mSearchManager.cancelSearch()) {
+ return;
+ }
+
if (!mState.stackTouched) {
super.onBackPressed();
return;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolBar.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolBar.java
new file mode 100644
index 0000000..36b7646
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsToolBar.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MenuItem;
+import android.widget.Toolbar;
+
+/**
+ * ToolBar of Documents UI.
+ */
+public class DocumentsToolBar extends Toolbar {
+ interface OnActionViewCollapsedListener {
+ void onActionViewCollapsed();
+ }
+
+ private OnActionViewCollapsedListener mOnActionViewCollapsedListener;
+
+ public DocumentsToolBar(Context context, AttributeSet attrs,
+ int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ }
+
+ public DocumentsToolBar(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ public DocumentsToolBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public DocumentsToolBar(Context context) {
+ super(context);
+ }
+
+ @Override
+ public void collapseActionView() {
+ super.collapseActionView();
+ if (mOnActionViewCollapsedListener != null) {
+ mOnActionViewCollapsedListener.onActionViewCollapsed();
+ }
+ }
+
+ /**
+ * Adds a listener that is invoked after collapsing the action view.
+ * @param listener
+ */
+ public void setOnActionViewCollapsedListener(
+ OnActionViewCollapsedListener listener) {
+ mOnActionViewCollapsedListener = listener;
+ }
+
+ public MenuItem getSearchMenu() {
+ return getMenu().findItem(R.id.menu_search);
+ }
+}
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 49ce427..748129c 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -299,6 +299,42 @@
<!-- Description of airplane mode -->
<string name="airplane_mode">Airplane mode</string>
+ <!-- An explanation text that the pattern needs to be solved since the device has just been restarted. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_restart_pattern">Pattern required when you restart device.</string>
+
+ <!-- An explanation text that the pin needs to be entered since the device has just been restarted. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_restart_pin">PIN required when you restart device.</string>
+
+ <!-- An explanation text that the password needs to be entered since the device has just been restarted. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_restart_password">Password required when you restart device.</string>
+
+ <!-- An explanation text that the pattern needs to be solved since profiles have just been switched. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_switch_profiles_pattern">Pattern required when you switch profiles.</string>
+
+ <!-- An explanation text that the pin needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_switch_profiles_pin">PIN required when you switch profiles.</string>
+
+ <!-- An explanation text that the password needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
+ <string name="kg_prompt_reason_switch_profiles_password">Password required when you switch profiles.</string>
+
+ <!-- An explanation text that the pattern needs to be solved since it hasn't been solved in a while. [CHAR LIMIT=80]-->
+ <plurals name="kg_prompt_reason_time_pattern">
+ <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm pattern.</item>
+ <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm pattern.</item>
+ </plurals>
+
+ <!-- An explanation text that the pin needs to be entered since it hasn't been entered in a while. [CHAR LIMIT=80]-->
+ <plurals name="kg_prompt_reason_time_pin">
+ <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm PIN.</item>
+ <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm PIN.</item>
+ </plurals>
+
+ <!-- An explanation text that the password needs to be entered since it hasn't been entered in a while. [CHAR LIMIT=80]-->
+ <plurals name="kg_prompt_reason_time_password">
+ <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm password.</item>
+ <item quantity="other">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hours. Confirm password.</item>
+ </plurals>
+
<!-- Fingerprint hint message when finger was not recognized.-->
<string name="fingerprint_not_recognized">Not recognized</string>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index ed0d4afe..23834a3 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -150,13 +150,6 @@
// Set selected property on so the view can send accessibility events.
mPasswordEntry.setSelected(true);
- // Poke the wakelock any time the text is selected or modified
- mPasswordEntry.setOnClickListener(new OnClickListener() {
- public void onClick(View v) {
- onUserInput();
- }
- });
-
mPasswordEntry.setUserActivityListener(new PasswordTextView.UserActivityListener() {
@Override
public void onUserActivity() {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index 4ba04e5..3c5dae3 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -679,6 +679,8 @@
if (resolvedActivities.get(0).activityInfo.exported) {
intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, mPrintJob);
intent.putExtra(PrintService.EXTRA_PRINTER_INFO, printer);
+ intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO,
+ mPrintedDocument.getDocumentInfo().info);
// This is external activity and may not be there.
try {
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
index 3b59fd6..fe9b99a 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/AbstractStatementRetriever.java
@@ -90,7 +90,7 @@
* Creates a new StatementRetriever that directly retrieves statements from the asset.
*
* <p> For web assets, {@link AbstractStatementRetriever} will try to retrieve the statement
- * file from URL: {@code [webAsset.site]/.well-known/statements.json"} where {@code
+ * file from URL: {@code [webAsset.site]/.well-known/assetlinks.json"} where {@code
* [webAsset.site]} is in the form {@code http{s}://[hostname]:[optional_port]}. The file
* should contain one JSON array of statements.
*
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
index 2ca85e9..e4feb90 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/DirectStatementRetriever.java
@@ -38,7 +38,7 @@
private static final int HTTP_CONNECTION_TIMEOUT_MILLIS = 5000;
private static final long HTTP_CONTENT_SIZE_LIMIT_IN_BYTES = 1024 * 1024;
private static final int MAX_INCLUDE_LEVEL = 1;
- private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/statements.json";
+ private static final String WELL_KNOWN_STATEMENT_PATH = "/.well-known/assetlinks.json";
private final URLFetcher mUrlFetcher;
private final AndroidPackageInfoFetcher mAndroidFetcher;
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
index da3c355..0f40a62 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/Statement.java
@@ -21,7 +21,7 @@
/**
* An immutable value type representing a statement, consisting of a source, target, and relation.
* This reflects an assertion that the relation holds for the source, target pair. For example, if a
- * web site has the following in its statements.json file:
+ * web site has the following in its assetlinks.json file:
*
* <pre>
* {
diff --git a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
index 969aa88..225e26c 100644
--- a/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
+++ b/packages/StatementService/src/com/android/statementservice/retriever/URLFetcher.java
@@ -60,33 +60,36 @@
throw new IllegalArgumentException("The url protocol should be on http or https.");
}
- HttpURLConnection connection;
- connection = (HttpURLConnection) url.openConnection();
- connection.setInstanceFollowRedirects(true);
- connection.setConnectTimeout(connectionTimeoutMillis);
- connection.setReadTimeout(connectionTimeoutMillis);
- connection.setUseCaches(true);
- connection.setInstanceFollowRedirects(false);
- connection.addRequestProperty("Cache-Control", "max-stale=60");
-
- if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
- Log.e(TAG, "The responses code is not 200 but " + connection.getResponseCode());
- return new WebContent("", DO_NOT_CACHE_RESULT);
- }
-
- if (connection.getContentLength() > fileSizeLimit) {
- Log.e(TAG, "The content size of the url is larger than " + fileSizeLimit);
- return new WebContent("", DO_NOT_CACHE_RESULT);
- }
-
- Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(connection.getHeaderFields());
-
+ HttpURLConnection connection = null;
try {
+ connection = (HttpURLConnection) url.openConnection();
+ connection.setInstanceFollowRedirects(true);
+ connection.setConnectTimeout(connectionTimeoutMillis);
+ connection.setReadTimeout(connectionTimeoutMillis);
+ connection.setUseCaches(true);
+ connection.setInstanceFollowRedirects(false);
+ connection.addRequestProperty("Cache-Control", "max-stale=60");
+
+ if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) {
+ Log.e(TAG, "The responses code is not 200 but " + connection.getResponseCode());
+ return new WebContent("", DO_NOT_CACHE_RESULT);
+ }
+
+ if (connection.getContentLength() > fileSizeLimit) {
+ Log.e(TAG, "The content size of the url is larger than " + fileSizeLimit);
+ return new WebContent("", DO_NOT_CACHE_RESULT);
+ }
+
+ Long expireTimeMillis = getExpirationTimeMillisFromHTTPHeader(
+ connection.getHeaderFields());
+
return new WebContent(inputStreamToString(
connection.getInputStream(), connection.getContentLength(), fileSizeLimit),
expireTimeMillis);
} finally {
- connection.disconnect();
+ if (connection != null) {
+ connection.disconnect();
+ }
}
}
diff --git a/packages/SystemUI/res/drawable/managed_profile_toast_background.xml b/packages/SystemUI/res/drawable/managed_profile_toast_background.xml
new file mode 100644
index 0000000..5c77b9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/managed_profile_toast_background.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <corners android:radius="2dp" />
+ <solid android:color="@color/managed_profile_toast_background" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
index 3c4c646..2bfa39d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_managed_profile_status.xml
@@ -20,10 +20,10 @@
android:viewportHeight="17.0">
<group android:translateX="2.0">
<path
- android:fillColor="#FF000000"
+ android:fillColor="@android:color/white"
android:pathData="M9.9,11.6H7v-1.1H2.1v2.8c0,0.8,0.6,1.4,1.4,1.4h9.9c0.8,0,1.4,-0.6,1.4,-1.4v-2.8H9.9V11.6z"/>
<path
- android:fillColor="#FF000000"
+ android:fillColor="@android:color/white"
android:pathData="M14.1,4.2h-2.5V3.2l-1.1,-1.1H6.3L5.3,3.2v1H2.8C2,4.2,1.4,4.9,1.4,5.6v2.8c0,0.8,0.6,1.4,1.4,1.4H7V8.8h2.8v1.1h4.2 c0.8,0,1.4,-0.6,1.4,-1.4V5.6C15.5,4.9,14.8,4.2,14.1,4.2z M10.6,4.2H6.3V3.2h4.2V4.2z"/>
</group>
</vector>
diff --git a/packages/SystemUI/res/layout/managed_profile_toast.xml b/packages/SystemUI/res/layout/managed_profile_toast.xml
new file mode 100644
index 0000000..5a01ca7
--- /dev/null
+++ b/packages/SystemUI/res/layout/managed_profile_toast.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:paddingTop="16dp"
+ android:paddingBottom="16dp"
+ android:paddingLeft="32dp"
+ android:paddingRight="32dp"
+ android:background="@drawable/managed_profile_toast_background">
+ <ImageView
+ android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:layout_gravity="center_horizontal"
+ android:layout_marginBottom="16dp"
+ android:src="@drawable/stat_sys_managed_profile_status"/>
+ <TextView android:text="@string/managed_profile_foreground_toast"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textColor="@android:color/white"
+ android:textSize="14sp"
+ android:layout_gravity="center_horizontal" />
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index a996260..38ea6e1 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -35,6 +35,7 @@
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_weight="1"
+ android:contentDescription="@string/accessibility_brightness"
systemui:text="@string/status_bar_settings_auto_brightness_label" />
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
index a5bf68e..062e6cb 100644
--- a/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
+++ b/packages/SystemUI/res/layout/status_bar_toggle_slider.xml
@@ -45,7 +45,6 @@
android:paddingBottom="16dp"
android:thumb="@drawable/ic_brightness_thumb"
android:splitTrack="false"
- android:contentDescription="@string/accessibility_brightness"
/>
<TextView
android:id="@+id/label"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 0dcbe88..9a96939 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -143,4 +143,6 @@
<color name="volume_icon_color">#ffffffff</color>
<color name="volume_settings_icon_color">#7fffffff</color>
<color name="volume_slider_inactive">#FFB0BEC5</color><!-- blue grey 200 -->
+
+ <color name="managed_profile_toast_background">#E5000000</color><!-- 90% black -->
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index a2a2e5f..a0b70f0 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1012,7 +1012,7 @@
<string name="volumeui_notification_text">Touch to restore the original.</string>
<!-- Toast shown when user unlocks screen and managed profile activity is in the foreground -->
- <string name="managed_profile_foreground_toast">You are in the work profile</string>
+ <string name="managed_profile_foreground_toast">You\'re using your work profile</string>
<string-array name="volume_stream_titles" translatable="false">
<item>Voice calls</item> <!-- STREAM_VOICE_CALL -->
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 3e122da..1e7ee98 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -116,7 +116,6 @@
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
WindowManager.LayoutParams lp = getLayoutParams();
mWindowManager.addView(mView, lp);
- mBar.getNavigationBarView().setDelegateView(mView);
if (visible) {
mView.show(true /* show */, false /* animate */);
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 7c378f0..915867b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -73,6 +73,10 @@
: mController.isRotationLocked();
final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
state.visible = mController.isRotationLockAffordanceVisible();
+ if (state.value == rotationLocked) {
+ // No change, no need to update all the values.
+ return;
+ }
state.value = rotationLocked;
final boolean portrait = mContext.getResources().getConfiguration().orientation
!= Configuration.ORIENTATION_LANDSCAPE;
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index 8abfe03..cdb8e69 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -74,6 +74,8 @@
mLabel = (TextView) findViewById(R.id.label);
mLabel.setText(a.getString(R.styleable.ToggleSlider_text));
+ setLabelFor(R.id.slider); // use our a11y text to annotate, not replace, the slider's
+
a.recycle();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index ef8c5db..85b4a64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -65,6 +65,7 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.Display;
+import android.view.Gravity;
import android.view.IWindowManager;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -395,8 +396,14 @@
if (recentTask != null && recentTask.size() > 0) {
UserInfo user = mUserManager.getUserInfo(recentTask.get(0).userId);
if (user != null && user.isManagedProfile()) {
- Toast.makeText(mContext, R.string.managed_profile_foreground_toast,
- Toast.LENGTH_SHORT).show();
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ View layout = inflater.inflate(R.layout.managed_profile_toast, null);
+ Toast toast = new Toast(mContext);
+ toast.setGravity(Gravity.CENTER_VERTICAL, 0, 0);
+ toast.setDuration(Toast.LENGTH_SHORT);
+ toast.setView(layout);
+ toast.show();
}
}
} else if (BANNER_ACTION_CANCEL.equals(action) || BANNER_ACTION_SETUP.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
deleted file mode 100644
index 2dc521e..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.statusbar;
-
-import android.app.StatusBarManager;
-import android.content.res.Resources;
-import android.graphics.RectF;
-import android.view.MotionEvent;
-import android.view.View;
-import com.android.systemui.R;
-import com.android.systemui.statusbar.phone.PhoneStatusBar;
-
-public class DelegateViewHelper {
- private View mDelegateView;
- private View mSourceView;
- private PhoneStatusBar mBar;
- private int[] mTempPoint = new int[2];
- private float[] mDownPoint = new float[2];
- private float mTriggerThreshhold;
- private boolean mPanelShowing;
-
- RectF mInitialTouch = new RectF();
- private boolean mStarted;
- private boolean mSwapXY = false;
- private boolean mDisabled;
-
- public DelegateViewHelper(View sourceView) {
- setSourceView(sourceView);
- }
-
- public void setDelegateView(View view) {
- mDelegateView = view;
- }
-
- public void setBar(PhoneStatusBar phoneStatusBar) {
- mBar = phoneStatusBar;
- }
-
- public boolean onInterceptTouchEvent(MotionEvent event) {
- if (mSourceView == null || mDelegateView == null || mBar.shouldDisableNavbarGestures()) {
- return false;
- }
-
- mSourceView.getLocationOnScreen(mTempPoint);
- final float sourceX = mTempPoint[0];
- final float sourceY = mTempPoint[1];
-
- final int action = event.getAction();
- switch (action) {
- case MotionEvent.ACTION_DOWN:
- mPanelShowing = mDelegateView.getVisibility() == View.VISIBLE;
- mDownPoint[0] = event.getX();
- mDownPoint[1] = event.getY();
- mStarted = mInitialTouch.contains(mDownPoint[0] + sourceX, mDownPoint[1] + sourceY);
- break;
- }
-
- if (!mStarted) {
- return false;
- }
-
- if (!mDisabled && !mPanelShowing && action == MotionEvent.ACTION_MOVE) {
- final int historySize = event.getHistorySize();
- for (int k = 0; k < historySize + 1; k++) {
- float x = k < historySize ? event.getHistoricalX(k) : event.getX();
- float y = k < historySize ? event.getHistoricalY(k) : event.getY();
- final float distance = mSwapXY ? (mDownPoint[0] - x) : (mDownPoint[1] - y);
- if (distance > mTriggerThreshhold) {
- mBar.invokeAssistGesture(false /* vibrate */);
- mPanelShowing = true;
- break;
- }
- }
- }
-
- if (action == MotionEvent.ACTION_DOWN) {
- mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, true);
- } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
- mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, false);
- }
-
- mDelegateView.getLocationOnScreen(mTempPoint);
- final float delegateX = mTempPoint[0];
- final float delegateY = mTempPoint[1];
-
- float deltaX = sourceX - delegateX;
- float deltaY = sourceY - delegateY;
- event.offsetLocation(deltaX, deltaY);
- mDelegateView.dispatchTouchEvent(event);
- event.offsetLocation(-deltaX, -deltaY);
- return mPanelShowing;
- }
-
- public void abortCurrentGesture() {
- if (mStarted) {
- mStarted = false;
- mBar.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, false);
- }
- }
-
- public void setSourceView(View view) {
- mSourceView = view;
- if (mSourceView != null) {
- Resources r = mSourceView.getContext().getResources();
- mTriggerThreshhold = r.getDimensionPixelSize(R.dimen.navigation_bar_min_swipe_distance);
- }
- }
-
- /**
- * Selects the initial touch region based on a list of views. This is meant to be called by
- * a container widget on children over which the initial touch should be detected. Note this
- * will compute a minimum bound that contains all specified views.
- *
- * @param views
- */
- public void setInitialTouchRegion(View ... views) {
- RectF bounds = new RectF();
- int p[] = new int[2];
- for (int i = 0; i < views.length; i++) {
- View view = views[i];
- if (view == null) continue;
- view.getLocationOnScreen(p);
- if (i == 0) {
- bounds.set(p[0], p[1], p[0] + view.getWidth(), p[1] + view.getHeight());
- } else {
- bounds.union(p[0], p[1], p[0] + view.getWidth(), p[1] + view.getHeight());
- }
- }
- mInitialTouch.set(bounds);
- }
-
- /**
- * When rotation is set to NO_SENSOR, then this allows swapping x/y for gesture detection
- * @param swap
- */
- public void setSwapXY(boolean swap) {
- mSwapXY = swap;
- }
-
- public void setDisabled(boolean disabled) {
- mDisabled = disabled;
- }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 8c03350..296538c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -134,6 +134,14 @@
}
@Override
+ public boolean dispatchGenericMotionEvent(MotionEvent ev) {
+ if (filterMotionEvent(ev)) {
+ return super.dispatchGenericMotionEvent(ev);
+ }
+ return false;
+ }
+
+ @Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (filterMotionEvent(ev)) {
return super.dispatchTouchEvent(ev);
@@ -143,6 +151,8 @@
protected boolean filterMotionEvent(MotionEvent event) {
return event.getActionMasked() != MotionEvent.ACTION_DOWN
+ && event.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER
+ && event.getActionMasked() != MotionEvent.ACTION_HOVER_MOVE
|| event.getY() > mClipTopAmount && event.getY() < mActualHeight;
}
@@ -340,6 +350,13 @@
outRect.top += getTranslationY() + getClipTopAmount();
}
+ @Override
+ public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
+ super.getBoundsOnScreen(outRect, clipToParent);
+ outRect.bottom = (int) (outRect.top + getActualHeight());
+ outRect.top += getClipTopAmount();
+ }
+
public int getContentHeight() {
return mActualHeight - getBottomDecorHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 636c511..f40f5016 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -47,7 +47,6 @@
import android.widget.LinearLayout;
import com.android.systemui.R;
-import com.android.systemui.statusbar.DelegateViewHelper;
import com.android.systemui.statusbar.policy.DeadZone;
import com.android.systemui.statusbar.policy.KeyButtonView;
@@ -79,7 +78,6 @@
private Drawable mRecentLandIcon;
private NavigationBarViewTaskSwitchHelper mTaskSwitchHelper;
- private DelegateViewHelper mDelegateHelper;
private DeadZone mDeadZone;
private final NavigationBarTransitions mBarTransitions;
@@ -92,7 +90,6 @@
private OnVerticalChangedListener mOnVerticalChangedListener;
private boolean mIsLayoutRtl;
- private boolean mDelegateIntercepted;
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
@@ -180,7 +177,6 @@
mBarSize = res.getDimensionPixelSize(R.dimen.navigation_bar_size);
mVertical = false;
mShowMenu = false;
- mDelegateHelper = new DelegateViewHelper(this);
mTaskSwitchHelper = new NavigationBarViewTaskSwitchHelper(context);
getIcons(res);
@@ -192,13 +188,8 @@
return mBarTransitions;
}
- public void setDelegateView(View view) {
- mDelegateHelper.setDelegateView(view);
- }
-
public void setBar(PhoneStatusBar phoneStatusBar) {
mTaskSwitchHelper.setBar(phoneStatusBar);
- mDelegateHelper.setBar(phoneStatusBar);
}
public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
@@ -208,44 +199,21 @@
@Override
public boolean onTouchEvent(MotionEvent event) {
- initDownStates(event);
- if (!mDelegateIntercepted && mTaskSwitchHelper.onTouchEvent(event)) {
+ if (mTaskSwitchHelper.onTouchEvent(event)) {
return true;
}
if (mDeadZone != null && event.getAction() == MotionEvent.ACTION_OUTSIDE) {
mDeadZone.poke(event);
}
- if (mDelegateHelper != null && mDelegateIntercepted) {
- boolean ret = mDelegateHelper.onInterceptTouchEvent(event);
- if (ret) return true;
- }
return super.onTouchEvent(event);
}
- private void initDownStates(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_DOWN) {
- mDelegateIntercepted = false;
- }
- }
-
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
- initDownStates(event);
- boolean intercept = mTaskSwitchHelper.onInterceptTouchEvent(event);
- if (!intercept) {
- mDelegateIntercepted = mDelegateHelper.onInterceptTouchEvent(event);
- intercept = mDelegateIntercepted;
- } else {
- MotionEvent cancelEvent = MotionEvent.obtain(event);
- cancelEvent.setAction(MotionEvent.ACTION_CANCEL);
- mDelegateHelper.onInterceptTouchEvent(cancelEvent);
- cancelEvent.recycle();
- }
- return intercept;
+ return mTaskSwitchHelper.onInterceptTouchEvent(event);
}
public void abortCurrentGesture() {
- mDelegateHelper.abortCurrentGesture();
getHomeButton().abortCurrentGesture();
}
@@ -461,10 +429,6 @@
Log.d(TAG, "reorient(): rot=" + mDisplay.getRotation());
}
- // swap to x coordinate if orientation is not in vertical
- if (mDelegateHelper != null) {
- mDelegateHelper.setSwapXY(mVertical);
- }
updateTaskSwitchHelper();
setNavigationIconHints(mNavigationIconHints, true);
@@ -476,12 +440,6 @@
}
@Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- mDelegateHelper.setInitialTouchRegion(getHomeButton(), getBackButton(), getRecentsButton());
- }
-
- @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (DEBUG) Log.d(TAG, String.format(
"onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 7f1fea1..634270c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -83,6 +83,10 @@
insets.top = 0;
insets.right = 0;
} else {
+ if (mRightInset != 0) {
+ mRightInset = 0;
+ applyMargins();
+ }
boolean changed = getPaddingLeft() != 0
|| getPaddingRight() != 0
|| getPaddingTop() != 0
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 21f96c9..49d9988 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -87,11 +87,8 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
-import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
@@ -100,7 +97,6 @@
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
-import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
@@ -526,14 +522,20 @@
@Override
public String getPassword(Account account) {
+ int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "getPassword: " + account
+ ", caller's uid " + Binder.getCallingUid()
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
-
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot get secrets for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -617,15 +619,21 @@
@Override
public String getUserData(Account account, String key) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "getUserData: " + account
- + ", key " + key
- + ", caller's uid " + Binder.getCallingUid()
- + ", pid " + Binder.getCallingPid());
+ String msg = String.format("getUserData( account: %s, key: %s, callerUid: %s, pid: %s",
+ account, key, callingUid, Binder.getCallingPid());
+ Log.v(TAG, msg);
}
if (account == null) throw new IllegalArgumentException("account is null");
if (key == null) throw new IllegalArgumentException("key is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot get user data for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -676,13 +684,20 @@
@Override
public boolean addAccountExplicitly(Account account, String password, Bundle extras) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "addAccountExplicitly: " + account
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot explicitly add accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
/*
* Child users are not allowed to add accounts. Only the accounts that are
* shared by the parent profile can be added to child profile.
@@ -758,10 +773,24 @@
@Override
public boolean accountAuthenticated(final Account account) {
+ final int callingUid = Binder.getCallingUid();
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ String msg = String.format(
+ "accountAuthenticated( account: %s, callerUid: %s)",
+ account,
+ callingUid);
+ Log.v(TAG, msg);
+ }
if (account == null) {
throw new IllegalArgumentException("account is null");
}
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot notify authentication for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
int userId = Binder.getCallingUserHandle().getIdentifier();
if (!canUserModifyAccounts(userId) || !canUserModifyAccountsForType(userId, account.type)) {
return false;
@@ -1007,16 +1036,21 @@
@Override
public void renameAccount(
IAccountManagerResponse response, Account accountToRename, String newName) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "renameAccount: " + accountToRename + " -> " + newName
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (accountToRename == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(accountToRename);
+ if (!isAccountOwnedByCallingUid(accountToRename.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot rename accounts of type: %s",
+ callingUid,
+ accountToRename.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
-
- int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
Account resultingAccount = renameAccountInternal(accounts, accountToRename, newName,
@@ -1125,65 +1159,21 @@
@Override
public void removeAccount(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "removeAccount: " + account
- + ", response " + response
- + ", caller's uid " + Binder.getCallingUid()
- + ", pid " + Binder.getCallingPid());
- }
- if (response == null) throw new IllegalArgumentException("response is null");
- if (account == null) throw new IllegalArgumentException("account is null");
- checkManageAccountsPermission();
- UserHandle user = Binder.getCallingUserHandle();
- UserAccounts accounts = getUserAccountsForCaller();
- int userId = Binder.getCallingUserHandle().getIdentifier();
- if (!canUserModifyAccounts(userId)) {
- try {
- // TODO: This should be ERROR_CODE_USER_RESTRICTED instead. See http://b/16322768
- response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
- "User cannot modify accounts");
- } catch (RemoteException re) {
- }
- return;
- }
- if (!canUserModifyAccountsForType(userId, account.type)) {
- try {
- response.onError(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE,
- "User cannot modify accounts of this type (policy).");
- } catch (RemoteException re) {
- }
- return;
- }
-
- long identityToken = clearCallingIdentity();
-
- cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
- synchronized (accounts.credentialsPermissionNotificationIds) {
- for (Pair<Pair<Account, String>, Integer> pair:
- accounts.credentialsPermissionNotificationIds.keySet()) {
- if (account.equals(pair.first.first)) {
- int id = accounts.credentialsPermissionNotificationIds.get(pair);
- cancelNotification(id, user);
- }
- }
- }
-
- logRecord(accounts, DebugDbHelper.ACTION_CALLED_ACCOUNT_REMOVE, TABLE_ACCOUNTS);
-
- try {
- new RemoveAccountSession(accounts, response, account, expectActivityLaunch).bind();
- } finally {
- restoreCallingIdentity(identityToken);
- }
+ removeAccountAsUser(
+ response,
+ account,
+ expectActivityLaunch,
+ UserHandle.getCallingUserId());
}
@Override
public void removeAccountAsUser(IAccountManagerResponse response, Account account,
boolean expectActivityLaunch, int userId) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeAccount: " + account
+ ", response " + response
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid()
+ ", for user id " + userId);
}
@@ -1193,7 +1183,18 @@
// Only allow the system process to modify accounts of other users
enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
+ " trying to remove account for " + userId);
- checkManageAccountsPermission();
+ /*
+ * Only the system or authenticator should be allowed to remove accounts for that
+ * authenticator. This will let users remove accounts (via Settings in the system) but not
+ * arbitrary applications (like competing authenticators).
+ */
+ if (!isAccountOwnedByCallingUid(account.type, callingUid) && !isSystemUid(callingUid)) {
+ String msg = String.format(
+ "uid %s cannot remove accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccounts(userId);
if (!canUserModifyAccounts(userId)) {
@@ -1238,13 +1239,26 @@
@Override
public boolean removeAccountExplicitly(Account account) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "removeAccountExplicitly: " + account
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
- if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
+ if (account == null) {
+ /*
+ * Null accounts should result in returning false, as per
+ * AccountManage.addAccountExplicitly(...) java doc.
+ */
+ Log.e(TAG, "account is null");
+ return false;
+ } else if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot explicitly add accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
int userId = Binder.getCallingUserHandle().getIdentifier();
@@ -1357,7 +1371,6 @@
}
if (accountType == null) throw new IllegalArgumentException("accountType is null");
if (authToken == null) throw new IllegalArgumentException("authToken is null");
- checkManageAccountsOrUseCredentialsPermissions();
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1490,15 +1503,22 @@
@Override
public String peekAuthToken(Account account, String authTokenType) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "peekAuthToken: " + account
+ ", authTokenType " + authTokenType
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot peek the authtokens associated with accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1510,15 +1530,22 @@
@Override
public void setAuthToken(Account account, String authTokenType, String authToken) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
+ ", authTokenType " + authTokenType
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot set auth tokens associated with accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1530,15 +1557,21 @@
@Override
public void setPassword(Account account, String password) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setAuthToken: " + account
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot set secrets for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
- int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
setPasswordInternal(accounts, account, password, callingUid);
@@ -1594,16 +1627,21 @@
@Override
public void clearPassword(Account account) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "clearPassword: " + account
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (account == null) throw new IllegalArgumentException("account is null");
- checkManageAccountsPermission();
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot clear passwords for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
-
- int callingUid = getCallingUid();
long identityToken = clearCallingIdentity();
try {
setPasswordInternal(accounts, account, null, callingUid);
@@ -1614,15 +1652,22 @@
@Override
public void setUserData(Account account, String key, String value) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setUserData: " + account
+ ", key " + key
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (key == null) throw new IllegalArgumentException("key is null");
if (account == null) throw new IllegalArgumentException("account is null");
- checkAuthenticateAccountsPermission(account);
+ if (!isAccountOwnedByCallingUid(account.type, callingUid)) {
+ String msg = String.format(
+ "uid %s cannot set user data for accounts of type: %s",
+ callingUid,
+ account.type);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -1769,7 +1814,6 @@
return;
}
- checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
final UserAccounts accounts = getUserAccountsForCaller();
final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
authenticatorInfo = mAuthenticatorCache.getServiceInfo(
@@ -2047,7 +2091,6 @@
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
- checkManageAccountsPermission();
// Is user disallowed from modifying accounts?
int userId = Binder.getCallingUserHandle().getIdentifier();
@@ -2122,7 +2165,6 @@
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
- checkManageAccountsPermission();
// Only allow the system process to add accounts of other users
enforceCrossUserPermission(userId, "User " + UserHandle.getCallingUserId()
@@ -2213,7 +2255,6 @@
}
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
- checkManageAccountsPermission();
UserAccounts accounts = getUserAccounts(userId);
long identityToken = clearCallingIdentity();
try {
@@ -2250,7 +2291,6 @@
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
- checkManageAccountsPermission();
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -2278,16 +2318,23 @@
@Override
public void editProperties(IAccountManagerResponse response, final String accountType,
final boolean expectActivityLaunch) {
+ final int callingUid = Binder.getCallingUid();
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "editProperties: accountType " + accountType
+ ", response " + response
+ ", expectActivityLaunch " + expectActivityLaunch
- + ", caller's uid " + Binder.getCallingUid()
+ + ", caller's uid " + callingUid
+ ", pid " + Binder.getCallingPid());
}
if (response == null) throw new IllegalArgumentException("response is null");
if (accountType == null) throw new IllegalArgumentException("accountType is null");
- checkManageAccountsPermission();
+ if (!isAccountOwnedByCallingUid(accountType, callingUid) && !isSystemUid(callingUid)) {
+ String msg = String.format(
+ "uid %s cannot edit authenticator properites for account type: %s",
+ callingUid,
+ accountType);
+ throw new SecurityException(msg);
+ }
UserAccounts accounts = getUserAccountsForCaller();
long identityToken = clearCallingIdentity();
try {
@@ -3588,7 +3635,7 @@
private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
final boolean isPrivileged = isPrivileged(callerUid);
final boolean fromAuthenticator = account != null
- && hasAuthenticatorUid(account.type, callerUid);
+ && isAccountManagedByCaller(account.type, callerUid);
final boolean hasExplicitGrants = account != null
&& hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -3600,14 +3647,17 @@
return fromAuthenticator || hasExplicitGrants || isPrivileged;
}
- private boolean hasAuthenticatorUid(String accountType, int callingUid) {
+ private boolean isAccountManagedByCaller(String accountType, int callingUid) {
final int callingUserId = UserHandle.getUserId(callingUid);
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
mAuthenticatorCache.getAllServices(callingUserId)) {
if (serviceInfo.type.type.equals(accountType)) {
- return (serviceInfo.uid == callingUid) ||
- (mPackageManager.checkSignatures(serviceInfo.uid, callingUid)
- == PackageManager.SIGNATURE_MATCH);
+ /*
+ * We can't simply compare uids because uids can be recycled before the
+ * authenticator cache is updated.
+ */
+ final int sigChk = mPackageManager.checkSignatures(serviceInfo.uid, callingUid);
+ return sigChk == PackageManager.SIGNATURE_MATCH;
}
}
return false;
@@ -3648,36 +3698,49 @@
}
}
- private void checkCallingUidAgainstAuthenticator(Account account) {
- final int uid = Binder.getCallingUid();
- if (account == null || !hasAuthenticatorUid(account.type, uid)) {
- String msg = "caller uid " + uid + " is different than the authenticator's uid";
- Log.w(TAG, msg);
- throw new SecurityException(msg);
+ private boolean isSystemUid(int callingUid) {
+ String[] packages = null;
+ long ident = Binder.clearCallingIdentity();
+ try {
+ packages = mPackageManager.getPackagesForUid(callingUid);
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
+ if (packages != null) {
+ for (String name : packages) {
+ try {
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
+ if (packageInfo != null
+ && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
+ != 0) {
+ return true;
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, String.format("Could not find package [%s]", name), e);
+ }
+ }
+ } else {
+ Log.w(TAG, "No known packages with uid " + callingUid);
}
+ return false;
}
- private void checkAuthenticateAccountsPermission(Account account) {
- checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
- checkCallingUidAgainstAuthenticator(account);
+ private boolean isAccountOwnedByCallingUid(String accountType, int callingUid) {
+ if (!isAccountManagedByCaller(accountType, callingUid)) {
+ String msg = "caller uid " + callingUid + " is different than the authenticator's uid";
+ Log.w(TAG, msg);
+ return false;
+ }
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "caller uid " + callingUid + " is the same as the authenticator's uid");
+ }
+ return true;
}
private void checkReadAccountsPermission() {
checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
}
- private void checkManageAccountsPermission() {
- checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
- }
-
- private void checkManageAccountsOrUseCredentialsPermissions() {
- checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS,
- Manifest.permission.USE_CREDENTIALS);
- }
-
private boolean canUserModifyAccounts(int userId) {
if (getUserManager().getUserRestrictions(new UserHandle(userId))
.getBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS)) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 0d08c2a..27656d4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -32,6 +32,7 @@
import static com.android.server.am.TaskRecord.INVALID_TASK_ID;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.START_TAG;
@@ -4197,9 +4198,9 @@
if (rootR == null) {
Slog.w(TAG, "Finishing task with all activities already finished");
}
- // Do not allow task to finish if last task in lockTask mode. Launchable apps can
- // finish themselves.
- if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE && rootR == r &&
+ // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps can
+ // finish.
+ if (tr.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV && rootR == r &&
mStackSupervisor.isLastLockedTask(tr)) {
Slog.i(TAG, "Not finishing task in lock task mode");
mStackSupervisor.showLockTaskToast();
@@ -4361,9 +4362,10 @@
return false;
}
- // Do not allow the last non-launchable task to finish in Lock Task mode.
+ // Do not allow task to finish if last task in lockTask mode. Launchable priv-apps
+ // can finish.
final TaskRecord task = r.task;
- if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE &&
+ if (task.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE_PRIV &&
mStackSupervisor.isLastLockedTask(task) && task.getRootActivity() == r) {
mStackSupervisor.showLockTaskToast();
return false;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 23e62e2..9e33f2a 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -35,6 +35,7 @@
import static com.android.server.am.ActivityStack.ActivityState.*;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
@@ -1179,7 +1180,8 @@
mService.updateOomAdjLocked();
final TaskRecord task = r.task;
- if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) {
+ if (task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE ||
+ task.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE_PRIV) {
setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
}
@@ -3785,6 +3787,7 @@
switch (lockTaskAuth) {
case LOCK_TASK_AUTH_DONT_LOCK:
return !mLockTaskModeTasks.isEmpty();
+ case LOCK_TASK_AUTH_LAUNCHABLE_PRIV:
case LOCK_TASK_AUTH_LAUNCHABLE:
case LOCK_TASK_AUTH_WHITELISTED:
return false;
@@ -3801,12 +3804,14 @@
boolean didSomething = false;
for (int taskNdx = mLockTaskModeTasks.size() - 1; taskNdx >= 0; --taskNdx) {
final TaskRecord lockedTask = mLockTaskModeTasks.get(taskNdx);
- if (lockedTask.mLockTaskMode != LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED) {
- continue;
- }
- final boolean wasLaunchable = lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE;
+ final boolean wasWhitelisted =
+ (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
+ (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
lockedTask.setLockTaskAuth();
- if (wasLaunchable && lockedTask.mLockTaskAuth != LOCK_TASK_AUTH_LAUNCHABLE) {
+ final boolean isWhitelisted =
+ (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_LAUNCHABLE) ||
+ (lockedTask.mLockTaskAuth == LOCK_TASK_AUTH_WHITELISTED);
+ if (wasWhitelisted && !isWhitelisted) {
// Lost whitelisting authorization. End it now.
if (DEBUG_LOCKTASK) Slog.d(TAG_LOCKTASK, "onLockTaskPackagesUpdated: removing " +
lockedTask + " mLockTaskAuth=" + lockedTask.lockTaskAuthToString());
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index f966bcf..78f9f18 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -134,12 +134,15 @@
/** Can't be put in lockTask mode. */
final static int LOCK_TASK_AUTH_DONT_LOCK = 0;
- /** Can enter lockTask with user approval. Can never start over existing lockTask task. */
+ /** Can enter app pinning with user approval. Can never start over existing lockTask task. */
final static int LOCK_TASK_AUTH_PINNABLE = 1;
/** Starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing lockTask task. */
final static int LOCK_TASK_AUTH_LAUNCHABLE = 2;
- /** Can enter lockTask with user approval. Can start over existing lockTask task. */
+ /** Can enter lockTask without user approval. Can start over existing lockTask task. */
final static int LOCK_TASK_AUTH_WHITELISTED = 3;
+ /** Priv-app that starts in LOCK_TASK_MODE_LOCKED automatically. Can start over existing
+ * lockTask task. */
+ final static int LOCK_TASK_AUTH_LAUNCHABLE_PRIV = 4;
int mLockTaskAuth = LOCK_TASK_AUTH_PINNABLE;
int mLockTaskUid = -1; // The uid of the application that called startLockTask().
@@ -747,11 +750,18 @@
case LOCK_TASK_AUTH_PINNABLE: return "LOCK_TASK_AUTH_PINNABLE";
case LOCK_TASK_AUTH_LAUNCHABLE: return "LOCK_TASK_AUTH_LAUNCHABLE";
case LOCK_TASK_AUTH_WHITELISTED: return "LOCK_TASK_AUTH_WHITELISTED";
+ case LOCK_TASK_AUTH_LAUNCHABLE_PRIV: return "LOCK_TASK_AUTH_LAUNCHABLE_PRIV";
default: return "unknown=" + mLockTaskAuth;
}
}
void setLockTaskAuth() {
+ if (!mPrivileged &&
+ (mLockTaskMode == LOCK_TASK_LAUNCH_MODE_ALWAYS ||
+ mLockTaskMode == LOCK_TASK_LAUNCH_MODE_NEVER)) {
+ // Non-priv apps are not allowed to use always or never, fall back to default
+ mLockTaskMode = LOCK_TASK_LAUNCH_MODE_DEFAULT;
+ }
switch (mLockTaskMode) {
case LOCK_TASK_LAUNCH_MODE_DEFAULT:
mLockTaskAuth = isLockTaskWhitelistedLocked() ?
@@ -759,13 +769,11 @@
break;
case LOCK_TASK_LAUNCH_MODE_NEVER:
- mLockTaskAuth = mPrivileged ?
- LOCK_TASK_AUTH_DONT_LOCK : LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = LOCK_TASK_AUTH_DONT_LOCK;
break;
case LOCK_TASK_LAUNCH_MODE_ALWAYS:
- mLockTaskAuth = mPrivileged ?
- LOCK_TASK_AUTH_LAUNCHABLE: LOCK_TASK_AUTH_PINNABLE;
+ mLockTaskAuth = LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
break;
case LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED:
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7bdbec6..6c9fd3f 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -92,6 +92,7 @@
import android.content.pm.ActivityInfo;
import android.content.pm.ApplicationInfo;
import android.content.pm.FeatureInfo;
+import android.content.pm.IOnPermissionsChangeListener;
import android.content.pm.IPackageDataObserver;
import android.content.pm.IPackageDeleteObserver;
import android.content.pm.IPackageDeleteObserver2;
@@ -144,6 +145,7 @@
import android.os.Parcel;
import android.os.ParcelFileDescriptor;
import android.os.Process;
+import android.os.RemoteCallback;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.SELinux;
@@ -523,6 +525,8 @@
private AtomicInteger mNextMoveId = new AtomicInteger();
private final MoveCallbacks mMoveCallbacks;
+ private final OnPermissionChangeListeners mOnPermissionChangeListeners;
+
// Cache of users who need badging.
SparseBooleanArray mUserNeedsBadging = new SparseBooleanArray();
@@ -1731,6 +1735,9 @@
mPackageDexOptimizer = new PackageDexOptimizer(this);
mMoveCallbacks = new MoveCallbacks(FgThread.get().getLooper());
+ mOnPermissionChangeListeners = new OnPermissionChangeListeners(
+ FgThread.get().getLooper());
+
getDefaultDisplayMetrics(context, mMetrics);
SystemConfig systemConfig = SystemConfig.getInstance();
@@ -3195,10 +3202,11 @@
case PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED: {
gidsChanged = true;
- }
- break;
+ } break;
}
+ mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+
// Not critical if that is lost - app has to request again.
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
@@ -3255,6 +3263,8 @@
return;
}
+ mOnPermissionChangeListeners.onPermissionsChanged(pkg.applicationInfo.uid);
+
// Critical, after this call app should never have the permission.
mSettings.writeRuntimePermissionsForUserLPr(userId, true);
}
@@ -3397,6 +3407,24 @@
}
@Override
+ public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
+ mContext.enforceCallingOrSelfPermission(
+ Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS,
+ "addOnPermissionsChangeListener");
+
+ synchronized (mPackages) {
+ mOnPermissionChangeListeners.addListenerLocked(listener);
+ }
+ }
+
+ @Override
+ public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) {
+ synchronized (mPackages) {
+ mOnPermissionChangeListeners.removeListenerLocked(listener);
+ }
+ }
+
+ @Override
public boolean isProtectedBroadcast(String actionName) {
synchronized (mPackages) {
return mProtectedBroadcasts.contains(actionName);
@@ -15297,4 +15325,57 @@
}
}
}
+
+ private final class OnPermissionChangeListeners extends Handler {
+ private static final int MSG_ON_PERMISSIONS_CHANGED = 1;
+
+ private final RemoteCallbackList<IOnPermissionsChangeListener> mPermissionListeners =
+ new RemoteCallbackList<>();
+
+ public OnPermissionChangeListeners(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_PERMISSIONS_CHANGED: {
+ final int uid = msg.arg1;
+ handleOnPermissionsChanged(uid);
+ } break;
+ }
+ }
+
+ public void addListenerLocked(IOnPermissionsChangeListener listener) {
+ mPermissionListeners.register(listener);
+
+ }
+
+ public void removeListenerLocked(IOnPermissionsChangeListener listener) {
+ mPermissionListeners.unregister(listener);
+ }
+
+ public void onPermissionsChanged(int uid) {
+ if (mPermissionListeners.getRegisteredCallbackCount() > 0) {
+ obtainMessage(MSG_ON_PERMISSIONS_CHANGED, uid, 0).sendToTarget();
+ }
+ }
+
+ private void handleOnPermissionsChanged(int uid) {
+ final int count = mPermissionListeners.beginBroadcast();
+ try {
+ for (int i = 0; i < count; i++) {
+ IOnPermissionsChangeListener callback = mPermissionListeners
+ .getBroadcastItem(i);
+ try {
+ callback.onPermissionsChanged(uid);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Permission listener is dead", e);
+ }
+ }
+ } finally {
+ mPermissionListeners.finishBroadcast();
+ }
+ }
+ }
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ab1206b..2753700 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5975,40 +5975,6 @@
}
@Override
- public void sendDeviceInitializerStatus(int statusCode, String description) {
- synchronized (this) {
- String packageName = getDeviceInitializer();
- if (packageName == null) {
- throw new SecurityException("No device initializers");
- }
- UserHandle callingUser = Binder.getCallingUserHandle();
- int deviceInitializerUid = -1;
- try {
- deviceInitializerUid = mContext.getPackageManager().getPackageUid(
- packageName, callingUser.getIdentifier());
- } catch (NameNotFoundException e) {
- throw new SecurityException(e);
- }
- if (Binder.getCallingUid() != deviceInitializerUid) {
- throw new SecurityException("Caller must be a device initializer");
- }
- long id = Binder.clearCallingIdentity();
- try {
- Intent intent = new Intent(
- DevicePolicyManager.ACTION_SEND_DEVICE_INITIALIZER_STATUS);
- intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_INITIALIZER_STATUS_CODE,
- statusCode);
- intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_INITIALIZER_STATUS_DESCRIPTION,
- description);
- mContext.sendBroadcastAsUser(intent, callingUser,
- android.Manifest.permission.RECEIVE_DEVICE_INITIALIZER_STATUS);
- } finally {
- restoreCallingIdentity(id);
- }
- }
- }
-
- @Override
public boolean setKeyguardDisabled(ComponentName who, boolean disabled) {
Preconditions.checkNotNull(who, "ComponentName is null");
synchronized (this) {
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 6684be4..bb0a36f 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -48,6 +48,7 @@
import android.net.NetworkAgent;
import android.net.NetworkCapabilities;
import android.net.NetworkConfig;
+import android.net.NetworkFactory;
import android.net.NetworkInfo;
import android.net.NetworkInfo.DetailedState;
import android.net.NetworkMisc;
@@ -55,6 +56,7 @@
import android.net.RouteInfo;
import android.os.ConditionVariable;
import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Looper;
import android.os.INetworkManagementService;
import android.test.AndroidTestCase;
@@ -68,6 +70,7 @@
import java.net.InetAddress;
import java.util.concurrent.Future;
+import java.util.concurrent.atomic.AtomicBoolean;
/**
* Tests for {@link ConnectivityService}.
@@ -224,6 +227,31 @@
}
}
+ private static class MockNetworkFactory extends NetworkFactory {
+ final AtomicBoolean mNetworkStarted = new AtomicBoolean(false);
+
+ public MockNetworkFactory(Looper looper, Context context, String logTag,
+ NetworkCapabilities filter) {
+ super(looper, context, logTag, filter);
+ }
+
+ public int getMyRequestCount() {
+ return getRequestCount();
+ }
+
+ protected void startNetwork() {
+ mNetworkStarted.set(true);
+ }
+
+ protected void stopNetwork() {
+ mNetworkStarted.set(false);
+ }
+
+ public boolean getMyStartRequested() {
+ return mNetworkStarted.get();
+ }
+ }
+
private class WrappedConnectivityService extends ConnectivityService {
public WrappedConnectivityService(Context context, INetworkManagementService netManager,
INetworkStatsService statsService, INetworkPolicyManager policyManager) {
@@ -447,6 +475,71 @@
verifyNoNetwork();
}
+ @LargeTest
+ public void testNetworkFactoryRequests() throws Exception {
+ NetworkCapabilities filter = new NetworkCapabilities();
+ filter.addCapability(NET_CAPABILITY_INTERNET);
+ final HandlerThread handlerThread = new HandlerThread("testNetworkFactoryRequests");
+ handlerThread.start();
+ MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+ mServiceContext, "testFactory", filter);
+ testFactory.setScoreFilter(40);
+ testFactory.register();
+ try {
+ Thread.sleep(500);
+ } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(true, testFactory.getMyStartRequested());
+
+ // now bring in a higher scored network
+ MockNetworkAgent testAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+ ConditionVariable cv = waitForConnectivityBroadcasts(1);
+ testAgent.connect(true);
+ cv.block();
+ // part of the bringup makes another network request and then releases it
+ // wait for the release
+ try { Thread.sleep(500); } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // bring in a bunch of requests..
+ ConnectivityManager.NetworkCallback[] networkCallbacks =
+ new ConnectivityManager.NetworkCallback[10];
+ for (int i = 0; i< networkCallbacks.length; i++) {
+ networkCallbacks[i] = new ConnectivityManager.NetworkCallback();
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
+ mCm.requestNetwork(builder.build(), networkCallbacks[i]);
+ }
+
+ try {
+ Thread.sleep(1000);
+ } catch (Exception e) {}
+ assertEquals(11, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // remove the requests
+ for (int i = 0; i < networkCallbacks.length; i++) {
+ mCm.unregisterNetworkCallback(networkCallbacks[i]);
+ }
+ try {
+ Thread.sleep(500);
+ } catch (Exception e) {}
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(false, testFactory.getMyStartRequested());
+
+ // drop the higher scored network
+ cv = waitForConnectivityBroadcasts(1);
+ testAgent.disconnect();
+ cv.block();
+ assertEquals(1, testFactory.getMyRequestCount());
+ assertEquals(true, testFactory.getMyStartRequested());
+
+ testFactory.unregister();
+ handlerThread.quit();
+ }
+
+
// @Override
// public void tearDown() throws Exception {
// super.tearDown();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index b74b52d..da0c547 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -114,17 +114,12 @@
* (Some carriers require that emergency calls *not* be logged, presumably to avoid the risk of
* accidental redialing from the call log UI. This is a good idea, so the default here is
* false.)
- * <p>
- * TODO: on the other hand, it might still be useful to have some record of the emergency calls
- * you've made, or to be able to look up the exact date/time of an emergency call. So perhaps we
- * <b>should</b> log those calls, but instead fix the call log to disable the "call" button for
- * emergency numbers.
*/
public static final String
KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL = "allow_emergency_numbers_in_call_log_bool";
/** If true, removes the Voice Privacy option from Call Settings */
- public static final String KEY_VOICE_PRIVACY_DISABLE_BOOL = "voice_privacy_disable_bool";
+ public static final String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
/** Control whether users can reach the carrier portions of Cellular Network Settings. */
public static final String
@@ -302,7 +297,7 @@
sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
sDefaults.putBoolean(KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL, false);
- sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_BOOL, false);
+ sDefaults.putBoolean(KEY_VOICE_PRIVACY_DISABLE_UI_BOOL, false);
sDefaults.putBoolean(KEY_WORLD_PHONE_BOOL, false);
sDefaults.putInt(KEY_VOLTE_REPLACEMENT_RAT_INT, 0);
sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 3b7aa9f..ac92dc0 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -224,6 +224,18 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public void addOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
+ /** @hide */
+ @Override
+ public void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public int checkSignatures(String pkg1, String pkg2) {
throw new UnsupportedOperationException();