Merge "Improve boundary check for for Paint#DrawTextRun." 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 803d2fd..664c74b 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";
@@ -6148,10 +6123,10 @@
method public java.lang.String getPackageName();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
- field public static final int INTERACTION = 6; // 0x6
field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
field public static final int NONE = 0; // 0x0
+ field public static final int USER_INTERACTION = 7; // 0x7
}
public final class UsageStats implements android.os.Parcelable {
@@ -24477,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";
@@ -35492,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);
@@ -39554,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();
}
@@ -41851,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();
@@ -41870,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/removed.txt b/api/removed.txt
index 0046a70..f6ad27b 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -1,12 +1,3 @@
-package android {
-
- public static final class Manifest.permission {
- field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ";
- field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
- }
-
-}
-
package android.content.pm {
public class PackageInfo implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 72e4142..79c7353 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";
@@ -6341,10 +6313,10 @@
method public java.lang.String getPackageName();
method public long getTimeStamp();
field public static final int CONFIGURATION_CHANGE = 5; // 0x5
- field public static final int INTERACTION = 6; // 0x6
field public static final int MOVE_TO_BACKGROUND = 2; // 0x2
field public static final int MOVE_TO_FOREGROUND = 1; // 0x1
field public static final int NONE = 0; // 0x0
+ field public static final int USER_INTERACTION = 7; // 0x7
}
public final class UsageStats implements android.os.Parcelable {
@@ -9522,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);
@@ -9595,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);
@@ -9770,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 {
}
@@ -26409,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";
@@ -34160,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);
@@ -34234,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);
@@ -37764,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);
@@ -42140,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();
}
@@ -44437,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();
@@ -44456,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/api/system-removed.txt b/api/system-removed.txt
index 0046a70..f6ad27b 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -1,12 +1,3 @@
-package android {
-
- public static final class Manifest.permission {
- field public static final java.lang.String SUBSCRIBED_FEEDS_READ = "android.permission.SUBSCRIBED_FEEDS_READ";
- field public static final java.lang.String SUBSCRIBED_FEEDS_WRITE = "android.permission.SUBSCRIBED_FEEDS_WRITE";
- }
-
-}
-
package android.content.pm {
public class PackageInfo implements android.os.Parcelable {
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/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 9604789..c2bf28a 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -55,6 +55,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
+import java.util.List;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
@@ -166,6 +167,7 @@
if (runtimeIsa.equals(secondaryIsa)) {
final ApplicationInfo modified = new ApplicationInfo(info);
modified.nativeLibraryDir = modified.secondaryNativeLibraryDir;
+ modified.primaryCpuAbi = modified.secondaryCpuAbi;
return modified;
}
}
@@ -272,8 +274,9 @@
}
}
- final ArrayList<String> zipPaths = new ArrayList<>();
- final ArrayList<String> libPaths = new ArrayList<>();
+ final List<String> zipPaths = new ArrayList<>();
+ final List<String> apkPaths = new ArrayList<>();
+ final List<String> libPaths = new ArrayList<>();
if (mRegisterPackage) {
try {
@@ -329,6 +332,8 @@
}
}
+ apkPaths.addAll(zipPaths);
+
if (mSharedLibraries != null) {
for (String lib : mSharedLibraries) {
if (!zipPaths.contains(lib)) {
@@ -346,6 +351,14 @@
}
final String zip = TextUtils.join(File.pathSeparator, zipPaths);
+
+ // Add path to libraries in apk for current abi
+ if (mApplicationInfo.primaryCpuAbi != null) {
+ for (String apk : apkPaths) {
+ libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi);
+ }
+ }
+
final String lib = TextUtils.join(File.pathSeparator, libPaths);
/*
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/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 58279d7..369b692 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -68,9 +68,15 @@
public static final int CONFIGURATION_CHANGE = 5;
/**
- * An event type denoting that a package was interacted with in some way.
+ * An event type denoting that a package was interacted with in some way by the system.
+ * @hide
*/
- public static final int INTERACTION = 6;
+ public static final int SYSTEM_INTERACTION = 6;
+
+ /**
+ * An event type denoting that a package was interacted with in some way by the user.
+ */
+ public static final int USER_INTERACTION = 7;
/**
* {@hide}
diff --git a/core/java/android/app/usage/UsageStats.java b/core/java/android/app/usage/UsageStats.java
index 81c7422..0fce4e2 100644
--- a/core/java/android/app/usage/UsageStats.java
+++ b/core/java/android/app/usage/UsageStats.java
@@ -41,11 +41,19 @@
public long mEndTimeStamp;
/**
+ * Last time used by the user with an explicit action (notification, activity launch).
* {@hide}
*/
public long mLastTimeUsed;
/**
+ * The last time the package was used via implicit, non-user initiated actions (service
+ * was bound, etc).
+ * {@hide}
+ */
+ public long mLastTimeSystemUsed;
+
+ /**
* Last time the package was used and the beginning of the idle countdown.
* This uses a different timebase that is about how much the device has been in use in general.
* {@hide}
@@ -82,6 +90,7 @@
mLaunchCount = stats.mLaunchCount;
mLastEvent = stats.mLastEvent;
mBeginIdleTime = stats.mBeginIdleTime;
+ mLastTimeSystemUsed = stats.mLastTimeSystemUsed;
}
public String getPackageName() {
@@ -119,6 +128,16 @@
/**
* @hide
+ * Get the last time this package was used by the system (not the user). This can be different
+ * from {@link #getLastTimeUsed()} when the system binds to one of this package's services.
+ * See {@link System#currentTimeMillis()}.
+ */
+ public long getLastTimeSystemUsed() {
+ return mLastTimeSystemUsed;
+ }
+
+ /**
+ * @hide
* Get the last time this package was active, measured in milliseconds. This timestamp
* uses a timebase that represents how much the device was used and not wallclock time.
*/
@@ -151,6 +170,7 @@
mEndTimeStamp = right.mEndTimeStamp;
mLastTimeUsed = right.mLastTimeUsed;
mBeginIdleTime = right.mBeginIdleTime;
+ mLastTimeSystemUsed = right.mLastTimeSystemUsed;
}
mBeginTimeStamp = Math.min(mBeginTimeStamp, right.mBeginTimeStamp);
mTotalTimeInForeground += right.mTotalTimeInForeground;
@@ -172,6 +192,7 @@
dest.writeInt(mLaunchCount);
dest.writeInt(mLastEvent);
dest.writeLong(mBeginIdleTime);
+ dest.writeLong(mLastTimeSystemUsed);
}
public static final Creator<UsageStats> CREATOR = new Creator<UsageStats>() {
@@ -186,6 +207,7 @@
stats.mLaunchCount = in.readInt();
stats.mLastEvent = in.readInt();
stats.mBeginIdleTime = in.readLong();
+ stats.mLastTimeSystemUsed = in.readLong();
return stats;
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 33f38fb..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
*/
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 c3f2c43..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}.
*/
@@ -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/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index a3a998e..cc95c0e 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -87,6 +87,9 @@
public static final int MAX_DIMEN_FOR_ROUNDING = 1080; // maximum allowed width for rounding
+ // Keep up to date with values in system/core/include/system/window.h
+ public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
+
private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
if (holder == null) {
return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
@@ -690,6 +693,13 @@
LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp));
}
+ static void setScalingMode(Surface surface, int mode)
+ throws BufferQueueAbandonedException {
+ checkNotNull(surface);
+ LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode));
+ }
+
+
private static native int nativeDetectSurfaceType(Surface surface);
private static native int nativeDetectSurfaceDimens(Surface surface,
@@ -717,5 +727,7 @@
private static native int nativeDetectSurfaceUsageFlags(Surface surface);
+ private static native int nativeSetScalingMode(Surface surface, int scalingMode);
+
static native int nativeGetJpegFooterSize();
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index 33a802b..8bdd42a 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -415,8 +415,9 @@
Range<Integer>[] ranges = new Range[rangesSize];
int i = 0;
for (int[] r : fpsRanges) {
- ranges[i++] = Range.create(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
- r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+ ranges[i++] = Range.create(
+ (int) Math.floor(r[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] / 1000.0),
+ (int) Math.ceil(r[Camera.Parameters.PREVIEW_FPS_MAX_INDEX] / 1000.0));
}
m.set(CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES, ranges);
}
diff --git a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
index d5d7f0d..6a44ac5 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyRequestMapper.java
@@ -162,17 +162,19 @@
if (aeFpsRange != null) {
int[] legacyFps = convertAeFpsRangeToLegacy(aeFpsRange);
- // TODO - Should we enforce that all HAL1 devices must include (30, 30) FPS range?
- boolean supported = false;
+ int[] rangeToApply = null;
for(int[] range : params.getSupportedPreviewFpsRange()) {
- if (legacyFps[0] == range[0] && legacyFps[1] == range[1]) {
- supported = true;
+ // Round range up/down to integer FPS value
+ int intRangeLow = (int) Math.floor(range[0] / 1000.0) * 1000;
+ int intRangeHigh = (int) Math.ceil(range[1] / 1000.0) * 1000;
+ if (legacyFps[0] == intRangeLow && legacyFps[1] == intRangeHigh) {
+ rangeToApply = range;
break;
}
}
- if (supported) {
- params.setPreviewFpsRange(legacyFps[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
- legacyFps[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+ if (rangeToApply != null) {
+ params.setPreviewFpsRange(rangeToApply[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
+ rangeToApply[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
} else {
Log.w(TAG, "Unsupported FPS range set [" + legacyFps[0] + "," + legacyFps[1] + "]");
}
@@ -626,8 +628,8 @@
private static int[] convertAeFpsRangeToLegacy(Range<Integer> fpsRange) {
int[] legacyFps = new int[2];
- legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower();
- legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper();
+ legacyFps[Parameters.PREVIEW_FPS_MIN_INDEX] = fpsRange.getLower() * 1000;
+ legacyFps[Parameters.PREVIEW_FPS_MAX_INDEX] = fpsRange.getUpper() * 1000;
return legacyFps;
}
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index 5ea1ab8..348b14a 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -384,6 +384,8 @@
callbackOutputSizes.add(outSize);
break;
default:
+ LegacyCameraDevice.setScalingMode(s, LegacyCameraDevice.
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
mPreviewOutputs.add(s);
previewOutputSizes.add(outSize);
break;
@@ -412,6 +414,9 @@
mParams.setPreviewFpsRange(bestRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],
bestRange[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]);
+ Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs,
+ callbackOutputSizes, mParams);
+
if (previewOutputSizes.size() > 0) {
Size largestOutput = SizeAreaComparator.findLargestByArea(previewOutputSizes);
@@ -419,6 +424,9 @@
// Find largest jpeg dimension - assume to have the same aspect ratio as sensor.
Size largestJpegDimen = ParameterUtils.getLargestSupportedJpegSizeByArea(mParams);
+ Size chosenJpegDimen = (smallestSupportedJpegSize != null) ? smallestSupportedJpegSize
+ : largestJpegDimen;
+
List<Size> supportedPreviewSizes = ParameterUtils.convertSizeList(
mParams.getSupportedPreviewSizes());
@@ -430,7 +438,7 @@
for (Size s : supportedPreviewSizes) {
long currArea = s.getWidth() * s.getHeight();
long bestArea = bestPreviewDimen.getWidth() * bestPreviewDimen.getHeight();
- if (checkAspectRatiosMatch(largestJpegDimen, s) && (currArea < bestArea &&
+ if (checkAspectRatiosMatch(chosenJpegDimen, s) && (currArea < bestArea &&
currArea >= largestOutputArea)) {
bestPreviewDimen = s;
}
@@ -451,8 +459,6 @@
}
}
- Size smallestSupportedJpegSize = calculatePictureSize(mCallbackOutputs,
- callbackOutputSizes, mParams);
if (smallestSupportedJpegSize != null) {
/*
* Set takePicture size to the smallest supported JPEG size large enough
diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java
index 1c9c713..135f369 100644
--- a/core/java/android/os/ParcelFileDescriptor.java
+++ b/core/java/android/os/ParcelFileDescriptor.java
@@ -621,6 +621,9 @@
final int fd = getFd();
Parcel.clearFileDescriptor(mFd);
writeCommStatusAndClose(Status.DETACHED, null);
+ mClosed = true;
+ mGuard.close();
+ releaseResources();
return fd;
}
}
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/os/storage/DiskInfo.java b/core/java/android/os/storage/DiskInfo.java
index 04e54aa..5bc45d5 100644
--- a/core/java/android/os/storage/DiskInfo.java
+++ b/core/java/android/os/storage/DiskInfo.java
@@ -80,6 +80,12 @@
if (label.toLowerCase().contains("generic")) {
return false;
}
+ if (label.toLowerCase().startsWith("usb")) {
+ return false;
+ }
+ if (label.toLowerCase().startsWith("multiple")) {
+ return false;
+ }
return true;
}
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/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index d9c412b..aebe7f1 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8931,157 +8931,4 @@
public static final String EXTRA_DATA_SET = "android.provider.extra.DATA_SET";
}
}
-
- /**
- * @hide
- */
- protected interface MetadataSyncColumns {
-
- /**
- * The raw contact backup id.
- * A reference to the {@link ContactsContract.RawContacts#BACKUP_ID} that save the
- * persistent unique id for each raw contact within its source system.
- *
- * @hide
- */
- public static final String RAW_CONTACT_BACKUP_ID = "raw_contact_backup_id";
-
- /**
- * The account type to which the raw_contact of this item is associated. See
- * {@link RawContacts#ACCOUNT_TYPE}
- *
- * @hide
- */
- public static final String ACCOUNT_TYPE = "account_type";
-
- /**
- * The account name to which the raw_contact of this item is associated. See
- * {@link RawContacts#ACCOUNT_NAME}
- *
- * @hide
- */
- public static final String ACCOUNT_NAME = "account_name";
-
- /**
- * The data set within the account that the raw_contact of this row belongs to. This allows
- * multiple sync adapters for the same account type to distinguish between
- * each others' data.
- * {@link RawContacts#DATA_SET}
- *
- * @hide
- */
- public static final String DATA_SET = "data_set";
-
- /**
- * A text column contains the Json string got from People API. The Json string contains
- * all the metadata related to the raw contact, i.e., all the data fields and
- * aggregation exceptions.
- *
- * Here is an example of the Json string got from the actual schema.
- * <pre>
- * {
- * "unique_contact_id": {
- * "account_type": "CUSTOM_ACCOUNT",
- * "custom_account_type": "facebook",
- * "account_name": "android-test",
- * "contact_id": "1111111",
- * "data_set": "FOCUS"
- * },
- * "contact_prefs": {
- * "send_to_voicemail": true,
- * "starred": false,
- * "pinned": 2
- * },
- * "aggregation_data": [
- * {
- * "type": "TOGETHER",
- * "contact_ids": [
- * {
- * "account_type": "GOOGLE_ACCOUNT",
- * "account_name": "android-test2",
- * "contact_id": "2222222",
- * "data_set": "GOOGLE_PLUS"
- * },
- * {
- * "account_type": "GOOGLE_ACCOUNT",
- * "account_name": "android-test3",
- * "contact_id": "3333333",
- * "data_set": "CUSTOM",
- * "custom_data_set": "custom type"
- * }
- * ]
- * }
- * ],
- * "field_data": [
- * {
- * "field_data_id": "1001",
- * "field_data_prefs": {
- * "is_primary": true,
- * "is_super_primary": true
- * },
- * "usage_stats": [
- * {
- * "usage_type": "CALL",
- * "last_time_used": 10000001,
- * "usage_count": 10
- * }
- * ]
- * }
- * ]
- * }
- * </pre>
- *
- * @hide
- */
- public static final String DATA = "data";
-
- /**
- * The "deleted" flag: "0" by default, "1" if the row has been marked
- * for deletion. When {@link android.content.ContentResolver#delete} is
- * called on a raw contact, updating MetadataSync table to set the flag of the raw contact
- * as "1", then metadata sync adapter deletes the raw contact metadata on the server.
- * <P>Type: INTEGER</P>
- *
- * @hide
- */
- public static final String DELETED = "deleted";
- }
-
- /**
- * Constants for the metadata sync table. This table is used to cache the metadata_sync data
- * from server before it is merged into other CP2 tables.
- *
- * @hide
- */
- public static final class MetadataSync implements BaseColumns, MetadataSyncColumns {
-
- /** The authority for the contacts metadata */
- public static final String METADATA_AUTHORITY = "com.android.contacts.metadata";
-
- /** A content:// style uri to the authority for the contacts metadata */
- public static final Uri METADATA_AUTHORITY_URI = Uri.parse(
- "content://" + METADATA_AUTHORITY);
-
- /**
- * This utility class cannot be instantiated
- */
- private MetadataSync() {
- }
-
- /**
- * The content:// style URI for this table.
- */
- public static final Uri CONTENT_URI = Uri.withAppendedPath(METADATA_AUTHORITY_URI,
- "metadata_sync");
-
- /**
- * The MIME type of {@link #CONTENT_URI} providing a directory of contact metadata
- */
- public static final String CONTENT_TYPE = "vnd.android.cursor.dir/contact_metadata";
-
- /**
- * The MIME type of a {@link #CONTENT_URI} subdirectory of a single contact metadata.
- */
- public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/contact_metadata";
- }
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 167d8e5..f2d3e71 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7087,6 +7087,36 @@
BLUETOOTH_SAP_PRIORITY_PREFIX = "bluetooth_sap_priority_";
/**
+ * Device Idle (Doze) specific settings.
+ * This is encoded as a key=value list, separated by commas. Ex:
+ *
+ * "inactive_timeout=60000,sensing_timeout=400000"
+ *
+ * The following keys are supported:
+ *
+ * <pre>
+ * inactive_to (long)
+ * sensing_to (long)
+ * motion_inactive_to (long)
+ * idle_after_inactive_to (long)
+ * idle_pending_to (long)
+ * max_idle_pending_to (long)
+ * idle_pending_factor (float)
+ * idle_to (long)
+ * max_idle_to (long)
+ * idle_factor (float)
+ * min_time_to_alarm (long)
+ * max_temp_app_whitelist_duration (long)
+ * </pre>
+ *
+ * <p>
+ * Type: string
+ * @hide
+ * @see com.android.server.DeviceIdleController.Constants
+ */
+ public static final String DEVICE_IDLE_CONSTANTS = "device_idle_constants";
+
+ /**
* Get the key that retrieves a bluetooth headset's priority.
* @hide
*/
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 6c4d8fd..d51aa79 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1790,6 +1790,15 @@
}
}
+ /**
+ * Return localized string representing the given number of selected items.
+ *
+ * @hide
+ */
+ public static CharSequence formatSelectedCount(int count) {
+ return Resources.getSystem().getQuantityString(R.plurals.selected_count, count, count);
+ }
+
private static Object sLock = new Object();
private static char[] sTemp = null;
diff --git a/core/java/android/util/KeyValueListParser.java b/core/java/android/util/KeyValueListParser.java
new file mode 100644
index 0000000..4abdde0
--- /dev/null
+++ b/core/java/android/util/KeyValueListParser.java
@@ -0,0 +1,114 @@
+/*
+ * 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.util;
+
+import android.text.TextUtils;
+
+/**
+ * Parses a list of key=value pairs, separated by some delimiter, and puts the results in
+ * an internal Map. Values can be then queried by key, or if not found, a default value
+ * can be used.
+ * @hide
+ */
+public class KeyValueListParser {
+ private final ArrayMap<String, String> mValues = new ArrayMap<>();
+ private final TextUtils.StringSplitter mSplitter;
+
+ /**
+ * Constructs a new KeyValueListParser. This can be reused for different strings
+ * by calling {@link #setString(String)}.
+ * @param delim The delimiter that separates key=value pairs.
+ */
+ public KeyValueListParser(char delim) {
+ mSplitter = new TextUtils.SimpleStringSplitter(delim);
+ }
+
+ /**
+ * Resets the parser with a new string to parse. The string is expected to be in the following
+ * format:
+ * <pre>key1=value,key2=value,key3=value</pre>
+ *
+ * where the delimiter is a comma.
+ *
+ * @param str the string to parse.
+ * @throws IllegalArgumentException if the string is malformed.
+ */
+ public void setString(String str) throws IllegalArgumentException {
+ mValues.clear();
+ if (str != null) {
+ mSplitter.setString(str);
+ for (String pair : mSplitter) {
+ int sep = pair.indexOf('=');
+ if (sep < 0) {
+ mValues.clear();
+ throw new IllegalArgumentException(
+ "'" + pair + "' in '" + str + "' is not a valid key-value pair");
+ }
+ mValues.put(pair.substring(0, sep).trim(), pair.substring(sep + 1).trim());
+ }
+ }
+ }
+
+ /**
+ * Get the value for key as a long.
+ * @param key The key to lookup.
+ * @param def The value to return if the key was not found, or the value was not a long.
+ * @return the long value associated with the key.
+ */
+ public long getLong(String key, long def) {
+ String value = mValues.get(key);
+ if (value != null) {
+ try {
+ return Long.parseLong(value);
+ } catch (NumberFormatException e) {
+ // fallthrough
+ }
+ }
+ return def;
+ }
+
+ /**
+ * Get the value for key as a float.
+ * @param key The key to lookup.
+ * @param def The value to return if the key was not found, or the value was not a float.
+ * @return the float value associated with the key.
+ */
+ public float getFloat(String key, float def) {
+ String value = mValues.get(key);
+ if (value != null) {
+ try {
+ return Float.parseFloat(value);
+ } catch (NumberFormatException e) {
+ // fallthrough
+ }
+ }
+ return def;
+ }
+
+ /**
+ * Get the value for key as a string.
+ * @param key The key to lookup.
+ * @param def The value to return if the key was not found.
+ * @return the string value associated with the key.
+ */
+ public String getString(String key, String def) {
+ String value = mValues.get(key);
+ if (value != null) {
+ return value;
+ }
+ return def;
+ }
+}
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index d2b6533..a865307 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -22,6 +22,7 @@
import android.os.Message;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.Trace;
import android.util.Log;
import android.util.TimeUtils;
@@ -160,6 +161,14 @@
FrameInfo mFrameInfo = new FrameInfo();
/**
+ * Must be kept in sync with CALLBACK_* ints below, used to index into this array.
+ * @hide
+ */
+ private static final String[] CALLBACK_TRACE_TITLES = {
+ "input", "animation", "traversal", "commit"
+ };
+
+ /**
* Callback type: Input callback. Runs first.
* @hide
*/
@@ -584,16 +593,22 @@
mLastFrameTimeNanos = frameTimeNanos;
}
- mFrameInfo.markInputHandlingStart();
- doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
+ try {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, "Choreographer#doFrame");
- mFrameInfo.markAnimationsStart();
- doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+ mFrameInfo.markInputHandlingStart();
+ doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
- mFrameInfo.markPerformTraversalsStart();
- doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
+ mFrameInfo.markAnimationsStart();
+ doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
- doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
+ mFrameInfo.markPerformTraversalsStart();
+ doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
+
+ doCallbacks(Choreographer.CALLBACK_COMMIT, frameTimeNanos);
+ } finally {
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
if (DEBUG_FRAMES) {
final long endNanos = System.nanoTime();
@@ -627,6 +642,7 @@
// safe by ensuring the commit time is always at least one frame behind.
if (callbackType == Choreographer.CALLBACK_COMMIT) {
final long jitterNanos = now - frameTimeNanos;
+ Trace.traceCounter(Trace.TRACE_TAG_VIEW, "jitterNanos", (int) jitterNanos);
if (jitterNanos >= 2 * mFrameIntervalNanos) {
final long lastFrameOffset = jitterNanos % mFrameIntervalNanos
+ mFrameIntervalNanos;
@@ -644,6 +660,7 @@
}
}
try {
+ Trace.traceBegin(Trace.TRACE_TAG_VIEW, CALLBACK_TRACE_TITLES[callbackType]);
for (CallbackRecord c = callbacks; c != null; c = c.next) {
if (DEBUG_FRAMES) {
Log.d(TAG, "RunCallback: type=" + callbackType
@@ -661,6 +678,7 @@
callbacks = next;
} while (callbacks != null);
}
+ Trace.traceEnd(Trace.TRACE_TAG_VIEW);
}
}
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/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index e1e0154..e2f42db 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1105,12 +1105,7 @@
Debug.startMethodTracing("ViewAncestor");
}
- Trace.traceBegin(Trace.TRACE_TAG_VIEW, "performTraversals");
- try {
- performTraversals();
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_VIEW);
- }
+ performTraversals();
if (mProfile) {
Debug.stopMethodTracing();
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index b7d529e..b4ef58a 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -333,8 +333,8 @@
newVmSize = Math.max(newVmSize, f.length());
continue;
}
- if (path.contains("!")) {
- String[] split = TextUtils.split(path, "!");
+ if (path.contains("!/")) {
+ String[] split = TextUtils.split(path, "!/");
if (split.length == 2) {
try {
ZipFile z = new ZipFile(split[0]);
@@ -384,7 +384,7 @@
ZipEntry e = z.getEntry(entry);
if (e != null && e.getMethod() == ZipEntry.STORED) {
// Return a path formatted for dlopen() load from APK.
- return apkPath + "!" + entry;
+ return apkPath + "!/" + entry;
}
}
} catch (IOException e) {
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/ResolverComparator.java b/core/java/com/android/internal/app/ResolverComparator.java
index 42668f1..585cdf1 100644
--- a/core/java/com/android/internal/app/ResolverComparator.java
+++ b/core/java/com/android/internal/app/ResolverComparator.java
@@ -45,7 +45,7 @@
class ResolverComparator implements Comparator<ResolvedComponentInfo> {
private static final String TAG = "ResolverComparator";
- private static final boolean DEBUG = true;
+ private static final boolean DEBUG = false;
// Two weeks
private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
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/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index d0f7591..ad3a5e2 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -84,7 +84,11 @@
jint tileModeX, jint tileModeY)
{
SkBitmap bitmap;
- GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+ if (jbitmap) {
+ // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
+ // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
+ GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+ }
SkShader* s = SkShader::CreateBitmapShader(bitmap,
(SkShader::TileMode)tileModeX,
(SkShader::TileMode)tileModeY);
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 08d61d5..b9e48a0 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -49,6 +49,12 @@
};
static fields_t fields;
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+}
+
// ----------------------------------------------------------------------------
static void SurfaceTexture_setSurfaceTexture(JNIEnv* env, jobject thiz,
@@ -253,6 +259,11 @@
"Unable to create native SurfaceTexture");
return;
}
+ surfaceTexture->setName(String8::format("SurfaceTexture-%d-%d-%d",
+ (isDetached ? 0 : texName),
+ getpid(),
+ createProcessUniqueId()));
+
SurfaceTexture_setSurfaceTexture(env, thiz, surfaceTexture);
SurfaceTexture_setProducer(env, thiz, producer);
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index afdfd8f..5bef653 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -689,6 +689,23 @@
return NO_ERROR;
}
+static jint LegacyCameraDevice_nativeSetScalingMode(JNIEnv* env, jobject thiz, jobject surface,
+ jint mode) {
+ ALOGV("nativeSetScalingMode");
+ sp<ANativeWindow> anw;
+ if ((anw = getNativeWindow(env, surface)) == NULL) {
+ ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ status_t err = NO_ERROR;
+ if ((err = native_window_set_scaling_mode(anw.get(), static_cast<int>(mode))) != NO_ERROR) {
+ ALOGE("%s: Unable to set surface scaling mode, error %s (%d)", __FUNCTION__,
+ strerror(-err), err);
+ return err;
+ }
+ return NO_ERROR;
+}
+
static jint LegacyCameraDevice_nativeGetJpegFooterSize(JNIEnv* env, jobject thiz) {
ALOGV("nativeGetJpegFooterSize");
return static_cast<jint>(sizeof(struct camera3_jpeg_blob));
@@ -733,6 +750,9 @@
{ "nativeDetectSurfaceUsageFlags",
"(Landroid/view/Surface;)I",
(void *)LegacyCameraDevice_nativeDetectSurfaceUsageFlags },
+ { "nativeSetScalingMode",
+ "(Landroid/view/Surface;I)I",
+ (void *)LegacyCameraDevice_nativeSetScalingMode },
};
// Get all the required offsets in java class and register native functions
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 709de9e..e58ac1d 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"
@@ -1205,12 +1182,16 @@
<permission android:name="android.permission.BIND_TELECOM_CONNECTION_SERVICE"
android:protectionLevel="system|signature" />
-
<!-- @SystemApi Allows an application to control the in-call experience.
@hide -->
<permission android:name="android.permission.CONTROL_INCALL_EXPERIENCE"
android:protectionLevel="system|signature" />
+ <!-- Allows an application to receive STK related commands.
+ @hide -->
+ <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
+ android:protectionLevel="system|signature" />
+
<!-- ================================== -->
<!-- Permissions for sdcard interaction -->
<!-- ================================== -->
@@ -1603,24 +1584,6 @@
<permission android:name="android.permission.WRITE_APN_SETTINGS"
android:protectionLevel="signature|system" />
- <!-- Allows an application to allow access the subscribed feeds ContentProvider.
- @hide
- @removed
- -->
- <permission android:name="android.permission.SUBSCRIBED_FEEDS_READ"
- android:label="@string/permlab_subscribedFeedsRead"
- android:description="@string/permdesc_subscribedFeedsRead"
- android:protectionLevel="normal" />
-
- <!--
- @hide
- @removed
- -->
- <permission android:name="android.permission.SUBSCRIBED_FEEDS_WRITE"
- android:label="@string/permlab_subscribedFeedsWrite"
- android:description="@string/permdesc_subscribedFeedsWrite"
- android:protectionLevel="dangerous" />
-
<!-- Allows applications to change network connectivity state -->
<permission android:name="android.permission.CHANGE_NETWORK_STATE"
android:description="@string/permdesc_changeNetworkState"
@@ -1979,6 +1942,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 +2413,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 28274ae..f6af19c 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. -->
@@ -1302,12 +1281,6 @@
<string name="permdesc_readSyncStats">Allows an app to read the sync stats for an account, including the history of sync events and how much data is synced. </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_subscribedFeedsWrite">write subscribed feeds</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_subscribedFeedsWrite">Allows the app to modify
- your currently synced feeds. Malicious apps may change your synced feeds.</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_readDictionary">read terms you added to the dictionary</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_readDictionary">Allows the app to read all words,
@@ -4207,4 +4180,9 @@
notification_template_material_inbox.xml.
DO NOT TRANSLATE -->
<string name="notification_inbox_ellipsis">\u2026</string>
+
+ <!-- Label describing the number of selected items [CHAR LIMIT=48] -->
+ <plurals name="selected_count">
+ <item quantity="other"><xliff:g id="count" example="3">%1$d</xliff:g> selected</item>
+ </plurals>
</resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 8900688..b019adb 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2306,5 +2306,6 @@
<java-symbol type="string" name="ext_media_status_missing" />
<java-symbol type="string" name="ext_media_unsupported_notification_message" />
<java-symbol type="string" name="ext_media_unsupported_notification_title" />
+ <java-symbol type="plurals" name="selected_count" />
</resources>
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index 6d8d81f..3181017 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -17,8 +17,8 @@
LOCAL_PATH := $(call my-dir)
-# Use full Noto Sans Japanese font on extended footprint
-ifeq ($(EXTENDED_FONT_FOOTPRINT),true)
+# Use full Noto Sans Japanese font on non-smaller footprints
+ifneq ($(SMALLER_FONT_FOOTPRINT),true)
FONT_NOTOSANS_JP_FULL := true
endif
@@ -38,7 +38,7 @@
endef
##########################################
-# The following fonts are distributed as symlink only.
+# The following fonts are just symlinks, for backward compatibility.
##########################################
$(eval $(call create-font-symlink,DroidSans.ttf,Roboto-Regular.ttf))
$(eval $(call create-font-symlink,DroidSans-Bold.ttf,Roboto-Bold.ttf))
@@ -54,7 +54,7 @@
################################
# Do not include Motoya on space-constrained devices
ifneq ($(SMALLER_FONT_FOOTPRINT),true)
-# Do not include Motoya if we are including full NotoSans
+# Do not include Motoya if we are including Noto Sans Japanese
ifneq ($(FONT_NOTOSANS_JP_FULL),true)
include $(CLEAR_VARS)
@@ -82,26 +82,19 @@
extra_font_files :=
################################
-# Include DroidSansFallback only on non-EXTENDED_FONT_FOOTPRINT builds
-ifneq ($(EXTENDED_FONT_FOOTPRINT),true)
-
-# Include a subset of DroidSansFallback on SMALLER_FONT_FOOTPRINT build
+# Include the DroidSansFallback subset on SMALLER_FONT_FOOTPRINT build
ifeq ($(SMALLER_FONT_FOOTPRINT),true)
-droidsans_fallback_src := DroidSansFallback.ttf
-else # !SMALLER_FONT_FOOTPRINT
-droidsans_fallback_src := DroidSansFallbackFull.ttf
-endif # SMALLER_FONT_FOOTPRINT
include $(CLEAR_VARS)
LOCAL_MODULE := DroidSansFallback.ttf
-LOCAL_SRC_FILES := $(droidsans_fallback_src)
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
LOCAL_MODULE_CLASS := ETC
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE_PATH := $(TARGET_OUT)/fonts
include $(BUILD_PREBUILT)
droidsans_fallback_src :=
-endif # !EXTENDED_FONT_FOOTPRINT
+endif # SMALLER_FONT_FOOTPRINT
################################
# Build the rest of font files as prebuilt.
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/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index bd74bc8..9211225 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -16,6 +16,8 @@
package android.graphics;
+import android.annotation.NonNull;
+
/**
* Shader used to draw a bitmap as a texture. The bitmap can be repeated or
* mirrored by setting the tiling mode.
@@ -38,7 +40,7 @@
* @param tileX The tiling mode for x to draw the bitmap in.
* @param tileY The tiling mode for y to draw the bitmap in.
*/
- public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
+ public BitmapShader(@NonNull Bitmap bitmap, TileMode tileX, TileMode tileY) {
mBitmap = bitmap;
mTileX = tileX;
mTileY = tileY;
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/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 49614bd..635fa11 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -72,6 +72,12 @@
jmethodID ctor;
} gSurfacePlaneClassInfo;
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+ static volatile int32_t globalCounter = 0;
+ return android_atomic_inc(&globalCounter);
+}
+
// ----------------------------------------------------------------------------
class JNIImageReaderContext : public ConsumerBase::FrameAvailableListener
@@ -808,6 +814,9 @@
sp<ConsumerBase> consumer;
sp<CpuConsumer> cpuConsumer;
sp<BufferItemConsumer> opaqueConsumer;
+ String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
+ width, height, format, maxImages, getpid(),
+ createProcessUniqueId());
if (isFormatOpaque(nativeFormat)) {
// Use the SW_READ_NEVER usage to tell producer that this format is not for preview or video
// encoding. The only possibility will be ZSL output.
@@ -819,6 +828,7 @@
return;
}
ctx->setOpaqueConsumer(opaqueConsumer);
+ opaqueConsumer->setName(consumerName);
consumer = opaqueConsumer;
} else {
cpuConsumer = new CpuConsumer(gbConsumer, maxImages, /*controlledByApp*/true);
@@ -828,6 +838,7 @@
return;
}
ctx->setCpuConsumer(cpuConsumer);
+ cpuConsumer->setName(consumerName);
consumer = cpuConsumer;
}
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/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 943104d..a4e6ce7 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -68,9 +68,6 @@
<!-- Button label that copies files to the current directory [CHAR LIMIT=24] -->
<string name="button_copy">Copy</string>
- <!-- Action mode title summarizing the number of documents selected [CHAR LIMIT=32] -->
- <string name="mode_selected_count"><xliff:g id="count" example="3">%1$d</xliff:g> selected</string>
-
<!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
<string name="sort_name">By name</string>
<!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index a789da8..f4be9c5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -54,6 +54,7 @@
import android.os.Parcelable;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
+import android.text.TextUtils;
import android.text.format.DateUtils;
import android.text.format.Formatter;
import android.text.format.Time;
@@ -474,8 +475,7 @@
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.mode_directory, menu);
- mode.setTitle(getResources()
- .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
+ mode.setTitle(TextUtils.formatSelectedCount(mCurrentView.getCheckedItemCount()));
return true;
}
@@ -571,8 +571,7 @@
}
}
- mode.setTitle(getResources()
- .getString(R.string.mode_selected_count, mCurrentView.getCheckedItemCount()));
+ mode.setTitle(TextUtils.formatSelectedCount(mCurrentView.getCheckedItemCount()));
}
};
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/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index e6a89f1..273f166 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -117,6 +117,7 @@
private static final int MSG_FINGERPRINT_AUTH_FAILED = 326;
private static final int MSG_FACE_UNLOCK_STATE_CHANGED = 327;
private static final int MSG_SIM_SUBSCRIPTION_INFO_CHANGED = 328;
+ private static final int MSG_AIRPLANE_MODE_CHANGED = 329;
private static KeyguardUpdateMonitor sInstance;
@@ -222,6 +223,9 @@
case MSG_SIM_SUBSCRIPTION_INFO_CHANGED:
handleSimSubscriptionInfoChanged();
break;
+ case MSG_AIRPLANE_MODE_CHANGED:
+ handleAirplaneModeChanged();
+ break;
}
}
};
@@ -305,6 +309,15 @@
}
}
+ private void handleAirplaneModeChanged() {
+ for (int j = 0; j < mCallbacks.size(); j++) {
+ KeyguardUpdateMonitorCallback cb = mCallbacks.get(j).get();
+ if (cb != null) {
+ cb.onRefreshCarrierInfo();
+ }
+ }
+ }
+
/** @return List of SubscriptionInfo records, maybe empty but never null */
List<SubscriptionInfo> getSubscriptionInfo(boolean forceReload) {
List<SubscriptionInfo> sil = mSubscriptionInfo;
@@ -486,6 +499,8 @@
} else if (TelephonyManager.ACTION_PHONE_STATE_CHANGED.equals(action)) {
String state = intent.getStringExtra(TelephonyManager.EXTRA_STATE);
mHandler.sendMessage(mHandler.obtainMessage(MSG_PHONE_STATE_CHANGED, state));
+ } else if (Intent.ACTION_AIRPLANE_MODE_CHANGED.equals(action)) {
+ mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED);
} else if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
dispatchBootCompleted();
}
@@ -721,6 +736,7 @@
filter.addAction(Intent.ACTION_TIME_CHANGED);
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
+ filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
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/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 1dba942e..5137e1b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -516,7 +516,7 @@
}
private void dumpSettings(Cursor cursor, PrintWriter pw) {
- if (!cursor.moveToFirst()) {
+ if (cursor == null || !cursor.moveToFirst()) {
return;
}
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/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 49eb9b2..c8212c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -404,7 +404,9 @@
((TileRecord) r).openingDetail = true;
}
} else {
- MetricsLogger.hidden(mContext, mDetailRecord.detailAdapter.getMetricsCategory());
+ if (mDetailRecord != null) {
+ MetricsLogger.hidden(mContext, mDetailRecord.detailAdapter.getMetricsCategory());
+ }
mClosingDetail = true;
setGridContentVisibility(true);
listener = mTeardownDetailWhenDone;
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/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 03d0482..08a6603 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;
}
@@ -343,7 +353,8 @@
@Override
public void getBoundsOnScreen(Rect outRect, boolean clipToParent) {
super.getBoundsOnScreen(outRect, clipToParent);
- outRect.bottom = (int) (outRect.top + getActualHeight());
+ outRect.bottom = outRect.top + getActualHeight();
+ outRect.top += getClipTopOptimization();
}
public int getContentHeight() {
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/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 49278c5..aa891b6 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -17,6 +17,7 @@
package com.android.systemui.volume;
import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_ALL_MASK;
+import static android.accessibilityservice.AccessibilityServiceInfo.FEEDBACK_GENERIC;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.animation.LayoutTransition;
@@ -422,17 +423,15 @@
protected void rescheduleTimeoutH() {
mHandler.removeMessages(H.DISMISS);
- int timeout = -1;
- if (!mAccessibility.mFeedbackEnabled) {
- timeout = computeTimeoutH();
- mHandler.sendMessageDelayed(mHandler
- .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
- }
+ final int timeout = computeTimeoutH();
+ mHandler.sendMessageDelayed(mHandler
+ .obtainMessage(H.DISMISS, Events.DISMISS_REASON_TIMEOUT, 0), timeout);
if (D.BUG) Log.d(TAG, "rescheduleTimeout " + timeout + " " + Debug.getCaller());
mController.userActivity();
}
private int computeTimeoutH() {
+ if (mAccessibility.mFeedbackEnabled) return 20000;
if (mSafetyWarning != null) return 5000;
if (mExpanded || mExpanding) return 5000;
if (mActiveStream == AudioManager.STREAM_MUSIC) return 1500;
@@ -959,7 +958,7 @@
}
}
- private final class Accessibility {
+ private final class Accessibility extends AccessibilityDelegate {
private AccessibilityManager mMgr;
private boolean mFeedbackEnabled;
@@ -976,14 +975,7 @@
updateFeedbackEnabled();
}
});
- mDialogView.setAccessibilityDelegate(new AccessibilityDelegate() {
- @Override
- public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
- AccessibilityEvent event) {
- rescheduleTimeoutH();
- return super.onRequestSendAccessibilityEvent(host, child, event);
- }
- });
+ mDialogView.setAccessibilityDelegate(this);
mMgr.addAccessibilityStateChangeListener(new AccessibilityStateChangeListener() {
@Override
public void onAccessibilityStateChanged(boolean enabled) {
@@ -993,15 +985,23 @@
updateFeedbackEnabled();
}
+ @Override
+ public boolean onRequestSendAccessibilityEvent(ViewGroup host, View child,
+ AccessibilityEvent event) {
+ rescheduleTimeoutH();
+ return super.onRequestSendAccessibilityEvent(host, child, event);
+ }
+
private void updateFeedbackEnabled() {
mFeedbackEnabled = computeFeedbackEnabled();
}
private boolean computeFeedbackEnabled() {
+ // are there any enabled non-generic a11y services?
final List<AccessibilityServiceInfo> services =
mMgr.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
for (AccessibilityServiceInfo asi : services) {
- if ((asi.feedbackType & FEEDBACK_ALL_MASK) != 0) {
+ if (asi.feedbackType != 0 && asi.feedbackType != FEEDBACK_GENERIC) {
return true;
}
}
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 4c7b523..ad34b37 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -22,6 +22,7 @@
import android.app.AppGlobals;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -29,12 +30,14 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.database.ContentObserver;
import android.hardware.Sensor;
import android.hardware.SensorManager;
import android.hardware.TriggerEvent;
import android.hardware.TriggerEventListener;
import android.hardware.display.DisplayManager;
import android.net.INetworkPolicyManager;
+import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
@@ -48,11 +51,11 @@
import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.UserHandle;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
-import android.util.Log;
+import android.util.KeyValueListParser;
import android.util.Slog;
-import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseLongArray;
import android.util.TimeUtils;
@@ -62,7 +65,6 @@
import com.android.internal.app.IBatteryStats;
import com.android.internal.os.AtomicFile;
import com.android.internal.os.BackgroundThread;
-import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.XmlUtils;
import com.android.server.am.BatteryStatsService;
@@ -103,84 +105,7 @@
// TODO: These need to be moved to system settings.
- /**
- * This is the time, after becoming inactive, at which we start looking at the
- * motion sensor to determine if the device is being left alone. We don't do this
- * immediately after going inactive just because we don't want to be continually running
- * the significant motion sensor whenever the screen is off.
- */
- private static final long DEFAULT_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 30*60*1000L
- : 3 * 60 * 1000L;
-
- /**
- * If we don't receive a callback from AnyMotion in this amount of time, we will change from
- * STATE_SENSING to STATE_INACTIVE, and any AnyMotion callbacks while not in STATE_SENSING will
- * be ignored.
- */
- private static final long DEFAULT_SENSING_TIMEOUT = !DEBUG ? 5 * 60 * 1000L : 60 * 1000L;
-
- /**
- * This is the time, after seeing motion, that we wait after becoming inactive from
- * that until we start looking for motion again.
- */
- private static final long DEFAULT_MOTION_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 10*60*1000L
- : 60 * 1000L;
-
- /**
- * This is the time, after the inactive timeout elapses, that we will wait looking
- * for significant motion until we truly consider the device to be idle.
- */
-
- private static final long DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT = !COMPRESS_TIME ? 30*60*1000L
- : 3 * 60 * 1000L;
-
- /**
- * This is the initial time, after being idle, that we will allow ourself to be back
- * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
- */
-
- private static final long DEFAULT_IDLE_PENDING_TIMEOUT = !COMPRESS_TIME ? 5*60*1000L
- : 30 * 1000L;
-
- /**
- * Maximum pending idle timeout (time spent running) we will be allowed to use.
- */
- private static final long DEFAULT_MAX_IDLE_PENDING_TIMEOUT = !COMPRESS_TIME ? 10*60*1000L
- : 60 * 1000L;
- /**
- * Scaling factor to apply to current pending idle timeout each time we cycle through
- * that state.
- */
- private static final float DEFAULT_IDLE_PENDING_FACTOR = 2f;
- /**
- * This is the initial time that we want to sit in the idle state before waking up
- * again to return to pending idle and allowing normal work to run.
- */
-
- private static final long DEFAULT_IDLE_TIMEOUT = !COMPRESS_TIME ? 60*60*1000L
- : 6 * 60 * 1000L;
-
- /**
- * Maximum idle duration we will be allowed to use.
- */
- private static final long DEFAULT_MAX_IDLE_TIMEOUT = !COMPRESS_TIME ? 6*60*60*1000L
- : 30 * 60 * 1000L;
- /**
- * Scaling factor to apply to current idle timeout each time we cycle through that state.
- */
- private static final float DEFAULT_IDLE_FACTOR = 2f;
- /**
- * This is the minimum time we will allow until the next upcoming alarm for us to
- * actually go in to idle mode.
- */
- private static final long DEFAULT_MIN_TIME_TO_ALARM = !COMPRESS_TIME ? 60*60*1000L
- : 6 * 60 * 1000L;
-
- /**
- * Max amount of time to temporarily whitelist an app when it receives a high priority tickle.
- */
- private static final long MAX_TEMP_APP_WHITELIST_DURATION = 5 * 60 * 1000L;
private AlarmManager mAlarmManager;
private IBatteryStats mBatteryStats;
@@ -306,6 +231,230 @@
}
};
+ /**
+ * All times are in milliseconds. These constants are kept synchronized with the system
+ * global Settings. Any access to this class or its fields should be done while
+ * holding the DeviceIdleController lock.
+ */
+ private class Constants extends ContentObserver {
+ // Key names stored in the settings value.
+ private static final String KEY_INACTIVE_TIMEOUT = "inactive_to";
+ private static final String KEY_SENSING_TIMEOUT = "sensing_to";
+ private static final String KEY_MOTION_INACTIVE_TIMEOUT = "motion_inactive_to";
+ private static final String KEY_IDLE_AFTER_INACTIVE_TIMEOUT = "idle_after_inactive_to";
+ private static final String KEY_IDLE_PENDING_TIMEOUT = "idle_pending_to";
+ private static final String KEY_MAX_IDLE_PENDING_TIMEOUT = "max_idle_pending_to";
+ private static final String KEY_IDLE_PENDING_FACTOR = "idle_pending_factor";
+ private static final String KEY_IDLE_TIMEOUT = "idle_to";
+ private static final String KEY_MAX_IDLE_TIMEOUT = "max_idle_to";
+ private static final String KEY_IDLE_FACTOR = "idle_factor";
+ private static final String KEY_MIN_TIME_TO_ALARM = "min_time_to_alarm";
+ private static final String KEY_MAX_TEMP_APP_WHITELIST_DURATION =
+ "max_temp_app_whitelist_duration";
+
+ /**
+ * This is the time, after becoming inactive, at which we start looking at the
+ * motion sensor to determine if the device is being left alone. We don't do this
+ * immediately after going inactive just because we don't want to be continually running
+ * the significant motion sensor whenever the screen is off.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_INACTIVE_TIMEOUT
+ */
+ public long INACTIVE_TIMEOUT;
+
+ /**
+ * If we don't receive a callback from AnyMotion in this amount of time, we will change from
+ * STATE_SENSING to STATE_INACTIVE, and any AnyMotion callbacks while not in STATE_SENSING
+ * will be ignored.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_SENSING_TIMEOUT
+ */
+ public long SENSING_TIMEOUT;
+
+ /**
+ * This is the time, after seeing motion, that we wait after becoming inactive from
+ * that until we start looking for motion again.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MOTION_INACTIVE_TIMEOUT
+ */
+ public long MOTION_INACTIVE_TIMEOUT;
+
+ /**
+ * This is the time, after the inactive timeout elapses, that we will wait looking
+ * for significant motion until we truly consider the device to be idle.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
+ */
+ public long IDLE_AFTER_INACTIVE_TIMEOUT;
+
+ /**
+ * This is the initial time, after being idle, that we will allow ourself to be back
+ * in the IDLE_PENDING state allowing the system to run normally until we return to idle.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_PENDING_TIMEOUT
+ */
+ public long IDLE_PENDING_TIMEOUT;
+
+ /**
+ * Maximum pending idle timeout (time spent running) we will be allowed to use.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MAX_IDLE_PENDING_TIMEOUT
+ */
+ public long MAX_IDLE_PENDING_TIMEOUT;
+
+ /**
+ * Scaling factor to apply to current pending idle timeout each time we cycle through
+ * that state.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_PENDING_FACTOR
+ */
+ public float IDLE_PENDING_FACTOR;
+
+ /**
+ * This is the initial time that we want to sit in the idle state before waking up
+ * again to return to pending idle and allowing normal work to run.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_TIMEOUT
+ */
+ public long IDLE_TIMEOUT;
+
+ /**
+ * Maximum idle duration we will be allowed to use.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MAX_IDLE_TIMEOUT
+ */
+ public long MAX_IDLE_TIMEOUT;
+
+ /**
+ * Scaling factor to apply to current idle timeout each time we cycle through that state.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_IDLE_FACTOR
+ */
+ public float IDLE_FACTOR;
+
+ /**
+ * This is the minimum time we will allow until the next upcoming alarm for us to
+ * actually go in to idle mode.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MIN_TIME_TO_ALARM
+ */
+ public long MIN_TIME_TO_ALARM;
+
+ /**
+ * Max amount of time to temporarily whitelist an app when it receives a high priority
+ * tickle.
+ * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+ * @see #KEY_MAX_TEMP_APP_WHITELIST_DURATION
+ */
+ public long MAX_TEMP_APP_WHITELIST_DURATION;
+
+ private final ContentResolver mResolver;
+ private final KeyValueListParser mParser = new KeyValueListParser(',');
+
+ public Constants(Handler handler, ContentResolver resolver) {
+ super(handler);
+ mResolver = resolver;
+ mResolver.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.DEVICE_IDLE_CONSTANTS), false, this);
+ updateConstants();
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateConstants();
+ }
+
+ private void updateConstants() {
+ synchronized (DeviceIdleController.this) {
+ try {
+ mParser.setString(Settings.Global.getString(mResolver,
+ Settings.Global.DEVICE_IDLE_CONSTANTS));
+ } catch (IllegalArgumentException e) {
+ // Failed to parse the settings string, log this and move on
+ // with defaults.
+ Slog.e(TAG, "Bad device idle settings", e);
+ }
+
+ INACTIVE_TIMEOUT = mParser.getLong(KEY_INACTIVE_TIMEOUT,
+ !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
+ SENSING_TIMEOUT = mParser.getLong(KEY_SENSING_TIMEOUT,
+ !DEBUG ? 5 * 60 * 1000L : 60 * 1000L);
+ MOTION_INACTIVE_TIMEOUT = mParser.getLong(KEY_MOTION_INACTIVE_TIMEOUT,
+ !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
+ IDLE_AFTER_INACTIVE_TIMEOUT = mParser.getLong(KEY_IDLE_AFTER_INACTIVE_TIMEOUT,
+ !COMPRESS_TIME ? 30 * 60 * 1000L : 3 * 60 * 1000L);
+ IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_IDLE_PENDING_TIMEOUT,
+ !COMPRESS_TIME ? 5 * 60 * 1000L : 30 * 1000L);
+ MAX_IDLE_PENDING_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_PENDING_TIMEOUT,
+ !COMPRESS_TIME ? 10 * 60 * 1000L : 60 * 1000L);
+ IDLE_PENDING_FACTOR = mParser.getFloat(KEY_IDLE_PENDING_FACTOR,
+ 2f);
+ IDLE_TIMEOUT = mParser.getLong(KEY_IDLE_TIMEOUT,
+ !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
+ MAX_IDLE_TIMEOUT = mParser.getLong(KEY_MAX_IDLE_TIMEOUT,
+ !COMPRESS_TIME ? 6 * 60 * 60 * 1000L : 30 * 60 * 1000L);
+ IDLE_FACTOR = mParser.getFloat(KEY_IDLE_FACTOR,
+ 2f);
+ MIN_TIME_TO_ALARM = mParser.getLong(KEY_MIN_TIME_TO_ALARM,
+ !COMPRESS_TIME ? 60 * 60 * 1000L : 6 * 60 * 1000L);
+ MAX_TEMP_APP_WHITELIST_DURATION = mParser.getLong(KEY_MAX_TEMP_APP_WHITELIST_DURATION,
+ 5 * 60 * 1000L);
+ }
+ }
+
+ void dump(PrintWriter pw) {
+ pw.println(" Settings:");
+
+ pw.print(" DOZE_INACTIVE_TIMEOUT=");
+ TimeUtils.formatDuration(INACTIVE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_SENSING_TIMEOUT=");
+ TimeUtils.formatDuration(SENSING_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_MOTION_INACTIVE_TIMEOUT=");
+ TimeUtils.formatDuration(MOTION_INACTIVE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_IDLE_AFTER_INACTIVE_TIMEOUT=");
+ TimeUtils.formatDuration(IDLE_AFTER_INACTIVE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_IDLE_PENDING_TIMEOUT=");
+ TimeUtils.formatDuration(IDLE_PENDING_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_MAX_IDLE_PENDING_TIMEOUT=");
+ TimeUtils.formatDuration(MAX_IDLE_PENDING_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_IDLE_PENDING_FACTOR=");
+ pw.println(IDLE_PENDING_FACTOR);
+
+ pw.print(" DOZE_IDLE_TIMEOUT=");
+ TimeUtils.formatDuration(IDLE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_MAX_IDLE_TIMEOUT=");
+ TimeUtils.formatDuration(MAX_IDLE_TIMEOUT, pw);
+ pw.println();
+
+ pw.print(" DOZE_IDLE_FACTOR=");
+ pw.println(IDLE_FACTOR);
+
+ pw.print(" DOZE_MIN_TIME_TO_ALARM=");
+ TimeUtils.formatDuration(MIN_TIME_TO_ALARM, pw);
+ pw.println();
+
+ pw.print(" DOZE_MAX_TEMP_APP_WHITELIST_DURATION=");
+ TimeUtils.formatDuration(MAX_TEMP_APP_WHITELIST_DURATION, pw);
+ pw.println();
+ }
+ }
+
+ private Constants mConstants;
+
@Override
public void onAnyMotionResult(int result) {
if (DEBUG) Slog.d(TAG, "onAnyMotionResult(" + result + ")");
@@ -474,6 +623,8 @@
}
}
+ mConstants = new Constants(mHandler, getContext().getContentResolver());
+
readConfigFileLocked();
updateWhitelistAppIdsLocked();
@@ -482,7 +633,7 @@
// a battery update the next time the level drops.
mCharging = true;
mState = STATE_ACTIVE;
- mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+ mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
}
publishBinderService(SERVICE_NAME, new BinderService());
@@ -613,14 +764,12 @@
*/
public void addPowerSaveTempWhitelistAppInternal(String packageName, long duration,
int userId) {
- if (duration > MAX_TEMP_APP_WHITELIST_DURATION) {
- duration = MAX_TEMP_APP_WHITELIST_DURATION;
- }
try {
int uid = getContext().getPackageManager().getPackageUid(packageName, userId);
int appId = UserHandle.getAppId(uid);
final long timeNow = System.currentTimeMillis();
synchronized (this) {
+ duration = Math.min(duration, mConstants.MAX_TEMP_APP_WHITELIST_DURATION);
long currentEndTime = mTempWhitelistAppIdEndTimes.get(appId);
// Set the new end time
mTempWhitelistAppIdEndTimes.put(appId, timeNow + duration);
@@ -704,7 +853,7 @@
EventLogTags.writeDeviceIdle(STATE_ACTIVE, reason);
scheduleReportActiveLocked(false);
mState = STATE_ACTIVE;
- mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+ mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
mNextIdlePendingDelay = 0;
mNextIdleDelay = 0;
cancelAlarmLocked();
@@ -731,7 +880,7 @@
* within the DEFAULT_SENSING_TIMEOUT, to return to STATE_INACTIVE.
*/
void enterInactiveStateLocked() {
- mInactiveTimeout = DEFAULT_INACTIVE_TIMEOUT;
+ mInactiveTimeout = mConstants.INACTIVE_TIMEOUT;
becomeInactiveIfAppropriateLocked();
}
@@ -740,7 +889,7 @@
EventLogTags.writeDeviceIdleStep();
final long now = SystemClock.elapsedRealtime();
- if ((now+DEFAULT_MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
+ if ((now+mConstants.MIN_TIME_TO_ALARM) > mAlarmManager.getNextWakeFromIdleTime()) {
// Whoops, there is an upcoming alarm. We don't actually want to go idle.
if (mState != STATE_ACTIVE) {
becomeActiveLocked("alarm");
@@ -753,10 +902,10 @@
// We have now been inactive long enough, it is time to start looking
// for significant motion and sleep some more while doing so.
startMonitoringSignificantMotion();
- scheduleAlarmLocked(DEFAULT_IDLE_AFTER_INACTIVE_TIMEOUT, false);
+ scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
// Reset the upcoming idle delays.
- mNextIdlePendingDelay = DEFAULT_IDLE_PENDING_TIMEOUT;
- mNextIdleDelay = DEFAULT_IDLE_TIMEOUT;
+ mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
+ mNextIdleDelay = mConstants.IDLE_TIMEOUT;
mState = STATE_IDLE_PENDING;
if (DEBUG) Slog.d(TAG, "Moved from STATE_INACTIVE to STATE_IDLE_PENDING.");
EventLogTags.writeDeviceIdle(mState, "step");
@@ -764,7 +913,7 @@
case STATE_IDLE_PENDING:
mState = STATE_SENSING;
if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE_PENDING to STATE_SENSING.");
- scheduleSensingAlarmLocked(DEFAULT_SENSING_TIMEOUT);
+ scheduleSensingAlarmLocked(mConstants.SENSING_TIMEOUT);
mAnyMotionDetector.checkForAnyMotion();
break;
case STATE_SENSING:
@@ -773,11 +922,9 @@
scheduleAlarmLocked(mNextIdleDelay, true);
if (DEBUG) Slog.d(TAG, "Moved to STATE_IDLE. Next alarm in " + mNextIdleDelay +
" ms.");
- mNextIdleDelay = (long)(mNextIdleDelay * DEFAULT_IDLE_FACTOR);
+ mNextIdleDelay = (long)(mNextIdleDelay * mConstants.IDLE_FACTOR);
if (DEBUG) Slog.d(TAG, "Setting mNextIdleDelay = " + mNextIdleDelay);
- if (mNextIdleDelay > DEFAULT_MAX_IDLE_TIMEOUT) {
- mNextIdleDelay = DEFAULT_MAX_IDLE_TIMEOUT;
- }
+ mNextIdleDelay = Math.min(mNextIdleDelay, mConstants.MAX_IDLE_TIMEOUT);
mState = STATE_IDLE;
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_ON);
break;
@@ -786,10 +933,8 @@
scheduleAlarmLocked(mNextIdlePendingDelay, false);
if (DEBUG) Slog.d(TAG, "Moved from STATE_IDLE to STATE_IDLE_MAINTENANCE. " +
"Next alarm in " + mNextIdlePendingDelay + " ms.");
- mNextIdlePendingDelay = (long)(mNextIdlePendingDelay*DEFAULT_IDLE_PENDING_FACTOR);
- if (mNextIdlePendingDelay > DEFAULT_MAX_IDLE_PENDING_TIMEOUT) {
- mNextIdlePendingDelay = DEFAULT_MAX_IDLE_PENDING_TIMEOUT;
- }
+ mNextIdlePendingDelay = Math.min(mConstants.MAX_IDLE_PENDING_TIMEOUT,
+ (long)(mNextIdlePendingDelay * mConstants.IDLE_PENDING_FACTOR));
mState = STATE_IDLE_MAINTENANCE;
EventLogTags.writeDeviceIdle(mState, "step");
mHandler.sendEmptyMessage(MSG_REPORT_IDLE_OFF);
@@ -807,7 +952,7 @@
if (mState != STATE_ACTIVE) {
scheduleReportActiveLocked(true);
mState = STATE_ACTIVE;
- mInactiveTimeout = DEFAULT_MOTION_INACTIVE_TIMEOUT;
+ mInactiveTimeout = mConstants.MOTION_INACTIVE_TIMEOUT;
EventLogTags.writeDeviceIdle(mState, "motion");
becomeInactiveIfAppropriateLocked();
}
@@ -1179,6 +1324,9 @@
pw.println();
}
}
+
+ mConstants.dump(pw);
+
pw.print(" mSigMotionSensor="); pw.println(mSigMotionSensor);
pw.print(" mCurDisplay="); pw.println(mCurDisplay);
pw.print(" mIdleDisabled="); pw.println(mIdleDisabled);
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..6496ba2 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;
@@ -2967,9 +2968,14 @@
// should never happen).
SparseArray<ProcessRecord> procs = mProcessNames.getMap().get(processName);
if (procs == null) return null;
- final int N = procs.size();
- for (int i = 0; i < N; i++) {
- if (UserHandle.isSameUser(procs.keyAt(i), uid)) return procs.valueAt(i);
+ final int procCount = procs.size();
+ for (int i = 0; i < procCount; i++) {
+ final int procUid = procs.keyAt(i);
+ if (UserHandle.isApp(procUid) || !UserHandle.isSameUser(procUid, uid)) {
+ // Don't use an app process or different user process for system component.
+ continue;
+ }
+ return procs.valueAt(i);
}
}
ProcessRecord proc = mProcessNames.get(processName, uid);
@@ -4197,9 +4203,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 +4367,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;
@@ -18617,7 +18624,7 @@
if (packages != null) {
for (int i = 0; i < packages.length; i++) {
mUsageStatsService.reportEvent(packages[i], app.userId,
- UsageEvents.Event.INTERACTION);
+ UsageEvents.Event.SYSTEM_INTERACTION);
}
}
}
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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8ee2076..90e912d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1407,7 +1407,7 @@
mAppUsageStats.reportEvent(r.sbn.getPackageName(),
userId == UserHandle.USER_ALL ? UserHandle.USER_OWNER
: userId,
- UsageEvents.Event.INTERACTION);
+ UsageEvents.Event.USER_INTERACTION);
r.setSeen();
}
}
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/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4861050..1802301 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -208,7 +208,7 @@
static final boolean DEBUG_APP_ORIENTATION = false;
static final boolean DEBUG_CONFIGURATION = false;
static final boolean DEBUG_APP_TRANSITIONS = false;
- static final boolean DEBUG_STARTING_WINDOW = true;
+ static final boolean DEBUG_STARTING_WINDOW = false;
static final boolean DEBUG_WALLPAPER = false;
static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
static final boolean DEBUG_DRAG = false;
diff --git a/services/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/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index a615675..1aa2978 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -110,7 +110,10 @@
usageStats.mLastEvent = eventType;
}
- usageStats.mLastTimeUsed = timeStamp;
+ if (eventType != UsageEvents.Event.SYSTEM_INTERACTION) {
+ usageStats.mLastTimeUsed = timeStamp;
+ }
+ usageStats.mLastTimeSystemUsed = timeStamp;
usageStats.mEndTimeStamp = timeStamp;
if (eventType == UsageEvents.Event.MOVE_TO_FOREGROUND) {
@@ -131,9 +134,9 @@
usageStats.mBeginIdleTime = timeStamp;
}
- void updateLastUsedTime(String packageName, long lastUsedTime) {
+ void updateSystemLastUsedTime(String packageName, long lastUsedTime) {
UsageStats usageStats = getOrCreateUsageStats(packageName);
- usageStats.mLastTimeUsed = lastUsedTime;
+ usageStats.mLastTimeSystemUsed = lastUsedTime;
}
void updateConfigurationStats(Configuration config, long timeStamp) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 633aee8..7a34757 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -60,7 +60,6 @@
import android.telephony.TelephonyManager;
import android.util.ArraySet;
import android.util.AtomicFile;
-import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
@@ -543,14 +542,15 @@
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
final long beginIdleTime = service.getBeginIdleTime(event.mPackage);
- final long lastUsedTime = service.getLastUsedTime(event.mPackage);
+ final long lastUsedTime = service.getSystemLastUsedTime(event.mPackage);
final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
lastUsedTime, screenOnTime, timeNow);
service.reportEvent(event, getScreenOnTimeLocked(timeNow));
// Inform listeners if necessary
if ((event.mEventType == Event.MOVE_TO_FOREGROUND
|| event.mEventType == Event.MOVE_TO_BACKGROUND
- || event.mEventType == Event.INTERACTION)) {
+ || event.mEventType == Event.SYSTEM_INTERACTION
+ || event.mEventType == Event.USER_INTERACTION)) {
if (previouslyIdle) {
// Slog.d(TAG, "Informing listeners of out-of-idle " + event.mPackage);
mHandler.sendMessage(mHandler.obtainMessage(MSG_INFORM_LISTENERS, userId,
@@ -575,11 +575,11 @@
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
final long beginIdleTime = service.getBeginIdleTime(packageName);
- final long lastUsedTime = service.getLastUsedTime(packageName);
+ final long lastUsedTime = service.getSystemLastUsedTime(packageName);
final boolean previouslyIdle = hasPassedIdleTimeoutLocked(beginIdleTime,
lastUsedTime, screenOnTime, timeNow);
service.setBeginIdleTime(packageName, deviceUsageTime);
- service.setLastUsedTime(packageName,
+ service.setSystemLastUsedTime(packageName,
timeNow - (idle ? DEFAULT_WALLCLOCK_APP_IDLE_THRESHOLD_MILLIS : 0) - 5000);
// Inform listeners if necessary
if (previouslyIdle != idle) {
@@ -666,7 +666,7 @@
final UserUsageStatsService service =
getUserDataAndInitializeIfNeededLocked(userId, timeNow);
long beginIdleTime = service.getBeginIdleTime(packageName);
- long lastUsedTime = service.getLastUsedTime(packageName);
+ long lastUsedTime = service.getSystemLastUsedTime(packageName);
return hasPassedIdleTimeoutLocked(beginIdleTime, lastUsedTime, screenOnTime, timeNow);
}
}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
index 0111201..f2ca3a4 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXmlV1.java
@@ -55,6 +55,7 @@
// Time attributes stored as an offset of the beginTime.
private static final String LAST_TIME_ACTIVE_ATTR = "lastTimeActive";
+ private static final String LAST_TIME_ACTIVE_SYSTEM_ATTR = "lastTimeActiveSystem";
private static final String BEGIN_IDLE_TIME_ATTR = "beginIdleTime";
private static final String END_TIME_ATTR = "endTime";
private static final String TIME_ATTR = "time";
@@ -71,6 +72,16 @@
// Apply the offset to the beginTime to find the absolute time.
stats.mLastTimeUsed = statsOut.beginTime + XmlUtils.readLongAttribute(
parser, LAST_TIME_ACTIVE_ATTR);
+
+ final String lastTimeUsedSystem = parser.getAttributeValue(null,
+ LAST_TIME_ACTIVE_SYSTEM_ATTR);
+ if (TextUtils.isEmpty(lastTimeUsedSystem)) {
+ // If the field isn't present, use the old one.
+ stats.mLastTimeSystemUsed = stats.mLastTimeUsed;
+ } else {
+ stats.mLastTimeSystemUsed = statsOut.beginTime + Long.parseLong(lastTimeUsedSystem);
+ }
+
final String beginIdleTime = parser.getAttributeValue(null, BEGIN_IDLE_TIME_ATTR);
if (!TextUtils.isEmpty(beginIdleTime)) {
stats.mBeginIdleTime = Long.parseLong(beginIdleTime);
@@ -130,6 +141,8 @@
// Write the time offset.
XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_ATTR,
usageStats.mLastTimeUsed - stats.beginTime);
+ XmlUtils.writeLongAttribute(xml, LAST_TIME_ACTIVE_SYSTEM_ATTR,
+ usageStats.mLastTimeSystemUsed - stats.beginTime);
XmlUtils.writeStringAttribute(xml, PACKAGE_ATTR, usageStats.mPackageName);
XmlUtils.writeLongAttribute(xml, TOTAL_TIME_ACTIVE_ATTR, usageStats.mTotalTimeInForeground);
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 7c00dae..b07b815 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -157,7 +157,7 @@
if (pi.applicationInfo != null && (firstUpdate || pi.applicationInfo.isSystemApp())
&& getBeginIdleTime(packageName) == -1) {
for (IntervalStats stats : mCurrentStats) {
- stats.update(packageName, currentTimeMillis, Event.INTERACTION);
+ stats.update(packageName, currentTimeMillis, Event.SYSTEM_INTERACTION);
stats.updateBeginIdleTime(packageName, deviceUsageTime);
mStatsChanged = true;
}
@@ -199,7 +199,7 @@
if (currentDailyStats.events == null) {
currentDailyStats.events = new TimeSparseArray<>();
}
- if (event.mEventType != UsageEvents.Event.INTERACTION) {
+ if (event.mEventType != UsageEvents.Event.SYSTEM_INTERACTION) {
currentDailyStats.events.put(event.mTimeStamp, event);
}
@@ -226,9 +226,9 @@
notifyStatsChanged();
}
- void setLastUsedTime(String packageName, long lastUsedTime) {
+ void setSystemLastUsedTime(String packageName, long lastUsedTime) {
for (IntervalStats stats : mCurrentStats) {
- stats.updateLastUsedTime(packageName, lastUsedTime);
+ stats.updateSystemLastUsedTime(packageName, lastUsedTime);
}
notifyStatsChanged();
}
@@ -397,13 +397,13 @@
}
}
- long getLastUsedTime(String packageName) {
+ long getSystemLastUsedTime(String packageName) {
final IntervalStats yearly = mCurrentStats[UsageStatsManager.INTERVAL_YEARLY];
UsageStats packageUsage;
if ((packageUsage = yearly.packageStats.get(packageName)) == null) {
return -1;
} else {
- return packageUsage.getLastTimeUsed();
+ return packageUsage.getLastTimeSystemUsed();
}
}
@@ -586,8 +586,11 @@
for (int i = 0; i < pkgCount; i++) {
final UsageStats usageStats = pkgStats.valueAt(i);
pw.printPair("package", usageStats.mPackageName);
- pw.printPair("totalTime", formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
+ pw.printPair("totalTime",
+ formatElapsedTime(usageStats.mTotalTimeInForeground, prettyDates));
pw.printPair("lastTime", formatDateTime(usageStats.mLastTimeUsed, prettyDates));
+ pw.printPair("lastTimeSystem",
+ formatDateTime(usageStats.mLastTimeSystemUsed, prettyDates));
pw.printPair("inactiveTime",
formatElapsedTime(screenOnTime - usageStats.mBeginIdleTime, prettyDates));
pw.println();
@@ -596,8 +599,7 @@
pw.println("configurations");
pw.increaseIndent();
- final ArrayMap<Configuration, ConfigurationStats> configStats =
- stats.configurations;
+ final ArrayMap<Configuration, ConfigurationStats> configStats = stats.configurations;
final int configCount = configStats.size();
for (int i = 0; i < configCount; i++) {
final ConfigurationStats config = configStats.valueAt(i);
@@ -659,8 +661,10 @@
return "CONTINUE_PREVIOUS_DAY";
case UsageEvents.Event.CONFIGURATION_CHANGE:
return "CONFIGURATION_CHANGE";
- case UsageEvents.Event.INTERACTION:
- return "INTERACTION";
+ case UsageEvents.Event.SYSTEM_INTERACTION:
+ return "SYSTEM_INTERACTION";
+ case UsageEvents.Event.USER_INTERACTION:
+ return "USER_INTERACTION";
default:
return "UNKNOWN";
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 6de438c..da0c547 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -114,11 +114,6 @@
* (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";
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();
diff --git a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
index 8e6daea..05cac10 100644
--- a/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
+++ b/tests/UsageStatsTest/src/com/android/tests/usagestats/UsageLogActivity.java
@@ -28,8 +28,6 @@
import android.widget.BaseAdapter;
import android.widget.TextView;
-import java.util.ArrayList;
-
public class UsageLogActivity extends ListActivity implements Runnable {
private static final long USAGE_STATS_PERIOD = 1000 * 60 * 60 * 24 * 14;
@@ -166,8 +164,8 @@
case UsageEvents.Event.CONFIGURATION_CHANGE:
return "Config change";
- case UsageEvents.Event.INTERACTION:
- return "Interaction";
+ case UsageEvents.Event.USER_INTERACTION:
+ return "User Interaction";
default:
return "Unknown: " + eventType;