Merge "Merge commit '12562abcd47de4aee3b0469cb04bf771c2072113' into manual_merge_12562abcd47d"
diff --git a/api/current.txt b/api/current.txt
index bca65ee..cd66ed6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -203,6 +203,8 @@
public static final class R.attr {
ctor public R.attr();
+ field public static final int __removed0 = 16844097; // 0x1010541
+ field public static final int __removed1 = 16844099; // 0x1010543
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -758,7 +760,6 @@
field public static final int keyboardLayout = 16843691; // 0x10103ab
field public static final int keyboardMode = 16843341; // 0x101024d
field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
- field public static final int keyboardNavigationSection = 16844097; // 0x1010541
field public static final int keycode = 16842949; // 0x10100c5
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int label = 16842753; // 0x1010001
@@ -908,7 +909,6 @@
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
- field public static final int nextSectionForward = 16844099; // 0x1010543
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -5583,6 +5583,18 @@
field public static final int STYLE_SPINNER = 0; // 0x0
}
+ public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
+ ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+ method public int describeContents();
+ method public android.app.PendingIntent getUserAction();
+ method public java.lang.CharSequence getUserActionTitle();
+ method public java.lang.CharSequence getUserMessage();
+ method public void showAsDialog(android.app.Activity);
+ method public void showAsNotification(android.content.Context);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
+ }
+
public final class RemoteAction implements android.os.Parcelable {
ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
method public android.app.RemoteAction clone();
@@ -30454,14 +30466,22 @@
}
public class StorageManager {
+ method public long getCacheQuotaBytes();
+ method public long getCacheSizeBytes();
+ method public long getExternalCacheQuotaBytes();
+ method public long getExternalCacheSizeBytes();
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryStorageVolume();
method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+ method public boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
+ method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+ method public void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
+ method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
}
@@ -37830,7 +37850,8 @@
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
- field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
@@ -37922,9 +37943,13 @@
field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+ field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+ field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+ field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+ field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -42210,7 +42235,9 @@
method public android.view.Display.Mode[] getSupportedModes();
method public deprecated float[] getSupportedRefreshRates();
method public deprecated int getWidth();
+ method public boolean isHdr();
method public boolean isValid();
+ method public boolean isWideColorGamut();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
field public static final int FLAG_PRESENTATION = 8; // 0x8
field public static final int FLAG_PRIVATE = 4; // 0x4
@@ -42279,7 +42306,7 @@
method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
- method public android.view.View findNextKeyboardNavigationGroup(int, android.view.View, android.view.View, int);
+ method public android.view.View findNextKeyboardNavigationCluster(android.view.View, android.view.View, int);
method public static android.view.FocusFinder getInstance();
}
@@ -43577,7 +43604,7 @@
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
- method public void addKeyboardNavigationGroups(int, java.util.Collection<android.view.View>, int);
+ method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -43741,7 +43768,6 @@
method public int getNextFocusLeftId();
method public int getNextFocusRightId();
method public int getNextFocusUpId();
- method public int getNextSectionForwardId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
method public android.view.ViewOutlineProvider getOutlineProvider();
method public int getOverScrollMode();
@@ -43847,7 +43873,6 @@
method public boolean isInLayout();
method public boolean isInTouchMode();
method public final boolean isKeyboardNavigationCluster();
- method public final boolean isKeyboardNavigationSection();
method public boolean isLaidOut();
method public boolean isLayoutDirectionResolved();
method public boolean isLayoutRequested();
@@ -43870,7 +43895,7 @@
method public boolean isVerticalFadingEdgeEnabled();
method public boolean isVerticalScrollBarEnabled();
method public void jumpDrawablesToCurrentState();
- method public android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+ method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public void layout(int, int, int, int);
method public final void measure(int, int);
method protected static int[] mergeDrawableStates(int[], int[]);
@@ -44020,7 +44045,6 @@
method public void setImportantForAccessibility(int);
method public void setKeepScreenOn(boolean);
method public void setKeyboardNavigationCluster(boolean);
- method public void setKeyboardNavigationSection(boolean);
method public void setLabelFor(int);
method public void setLayerPaint(android.graphics.Paint);
method public void setLayerType(int, android.graphics.Paint);
@@ -44038,7 +44062,6 @@
method public void setNextFocusLeftId(int);
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
- method public void setNextSectionForwardId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -44165,8 +44188,6 @@
field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
field public static final int INVISIBLE = 4; // 0x4
field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
- field public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1; // 0x1
- field public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2; // 0x2
field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
field public static final int LAYER_TYPE_NONE = 0; // 0x0
field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
@@ -44685,7 +44706,7 @@
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
- method public abstract android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+ method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 53552fc..a3deab0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -312,6 +312,8 @@
public static final class R.attr {
ctor public R.attr();
+ field public static final int __removed0 = 16844097; // 0x1010541
+ field public static final int __removed1 = 16844099; // 0x1010543
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -867,7 +869,6 @@
field public static final int keyboardLayout = 16843691; // 0x10103ab
field public static final int keyboardMode = 16843341; // 0x101024d
field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
- field public static final int keyboardNavigationSection = 16844097; // 0x1010541
field public static final int keycode = 16842949; // 0x10100c5
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int label = 16842753; // 0x1010001
@@ -1017,7 +1018,6 @@
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
- field public static final int nextSectionForward = 16844099; // 0x1010543
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -5504,9 +5504,11 @@
ctor public Notification.TvExtender();
ctor public Notification.TvExtender(android.app.Notification);
method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+ method public java.lang.String getChannel();
method public android.app.PendingIntent getContentIntent();
method public android.app.PendingIntent getDeleteIntent();
method public boolean isAvailableOnTv();
+ method public android.app.Notification.TvExtender setChannel(java.lang.String);
method public android.app.Notification.TvExtender setContentIntent(android.app.PendingIntent);
method public android.app.Notification.TvExtender setDeleteIntent(android.app.PendingIntent);
}
@@ -5770,6 +5772,18 @@
field public static final int STYLE_SPINNER = 0; // 0x0
}
+ public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
+ ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+ method public int describeContents();
+ method public android.app.PendingIntent getUserAction();
+ method public java.lang.CharSequence getUserActionTitle();
+ method public java.lang.CharSequence getUserMessage();
+ method public void showAsDialog(android.app.Activity);
+ method public void showAsNotification(android.content.Context);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
+ }
+
public final class RemoteAction implements android.os.Parcelable {
ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
method public android.app.RemoteAction clone();
@@ -33206,14 +33220,22 @@
}
public class StorageManager {
+ method public long getCacheQuotaBytes();
+ method public long getCacheSizeBytes();
+ method public long getExternalCacheQuotaBytes();
+ method public long getExternalCacheSizeBytes();
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryStorageVolume();
method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+ method public boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
+ method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+ method public void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
+ method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
}
@@ -41040,7 +41062,8 @@
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
- field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
@@ -41132,9 +41155,13 @@
field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+ field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+ field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+ field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+ field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -45512,7 +45539,9 @@
method public android.view.Display.Mode[] getSupportedModes();
method public deprecated float[] getSupportedRefreshRates();
method public deprecated int getWidth();
+ method public boolean isHdr();
method public boolean isValid();
+ method public boolean isWideColorGamut();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
field public static final int FLAG_PRESENTATION = 8; // 0x8
field public static final int FLAG_PRIVATE = 4; // 0x4
@@ -45581,7 +45610,7 @@
method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
- method public android.view.View findNextKeyboardNavigationGroup(int, android.view.View, android.view.View, int);
+ method public android.view.View findNextKeyboardNavigationCluster(android.view.View, android.view.View, int);
method public static android.view.FocusFinder getInstance();
}
@@ -46879,7 +46908,7 @@
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
- method public void addKeyboardNavigationGroups(int, java.util.Collection<android.view.View>, int);
+ method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -47043,7 +47072,6 @@
method public int getNextFocusLeftId();
method public int getNextFocusRightId();
method public int getNextFocusUpId();
- method public int getNextSectionForwardId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
method public android.view.ViewOutlineProvider getOutlineProvider();
method public int getOverScrollMode();
@@ -47149,7 +47177,6 @@
method public boolean isInLayout();
method public boolean isInTouchMode();
method public final boolean isKeyboardNavigationCluster();
- method public final boolean isKeyboardNavigationSection();
method public boolean isLaidOut();
method public boolean isLayoutDirectionResolved();
method public boolean isLayoutRequested();
@@ -47172,7 +47199,7 @@
method public boolean isVerticalFadingEdgeEnabled();
method public boolean isVerticalScrollBarEnabled();
method public void jumpDrawablesToCurrentState();
- method public android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+ method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public void layout(int, int, int, int);
method public final void measure(int, int);
method protected static int[] mergeDrawableStates(int[], int[]);
@@ -47322,7 +47349,6 @@
method public void setImportantForAccessibility(int);
method public void setKeepScreenOn(boolean);
method public void setKeyboardNavigationCluster(boolean);
- method public void setKeyboardNavigationSection(boolean);
method public void setLabelFor(int);
method public void setLayerPaint(android.graphics.Paint);
method public void setLayerType(int, android.graphics.Paint);
@@ -47340,7 +47366,6 @@
method public void setNextFocusLeftId(int);
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
- method public void setNextSectionForwardId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -47467,8 +47492,6 @@
field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
field public static final int INVISIBLE = 4; // 0x4
field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
- field public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1; // 0x1
- field public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2; // 0x2
field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
field public static final int LAYER_TYPE_NONE = 0; // 0x0
field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
@@ -47987,7 +48010,7 @@
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
- method public abstract android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+ method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
diff --git a/api/test-current.txt b/api/test-current.txt
index d18af4c..f07f3b4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -203,6 +203,8 @@
public static final class R.attr {
ctor public R.attr();
+ field public static final int __removed0 = 16844097; // 0x1010541
+ field public static final int __removed1 = 16844099; // 0x1010543
field public static final int absListViewStyle = 16842858; // 0x101006a
field public static final int accessibilityEventTypes = 16843648; // 0x1010380
field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -758,7 +760,6 @@
field public static final int keyboardLayout = 16843691; // 0x10103ab
field public static final int keyboardMode = 16843341; // 0x101024d
field public static final int keyboardNavigationCluster = 16844096; // 0x1010540
- field public static final int keyboardNavigationSection = 16844097; // 0x1010541
field public static final int keycode = 16842949; // 0x10100c5
field public static final int killAfterRestore = 16843420; // 0x101029c
field public static final int label = 16842753; // 0x1010001
@@ -908,7 +909,6 @@
field public static final int nextFocusLeft = 16842977; // 0x10100e1
field public static final int nextFocusRight = 16842978; // 0x10100e2
field public static final int nextFocusUp = 16842979; // 0x10100e3
- field public static final int nextSectionForward = 16844099; // 0x1010543
field public static final int noHistory = 16843309; // 0x101022d
field public static final int normalScreens = 16843397; // 0x1010285
field public static final int notificationTimeout = 16843651; // 0x1010383
@@ -5594,6 +5594,18 @@
field public static final int STYLE_SPINNER = 0; // 0x0
}
+ public final class RecoverableSecurityException extends java.lang.SecurityException implements android.os.Parcelable {
+ ctor public RecoverableSecurityException(java.lang.Throwable, java.lang.CharSequence, java.lang.CharSequence, android.app.PendingIntent);
+ method public int describeContents();
+ method public android.app.PendingIntent getUserAction();
+ method public java.lang.CharSequence getUserActionTitle();
+ method public java.lang.CharSequence getUserMessage();
+ method public void showAsDialog(android.app.Activity);
+ method public void showAsNotification(android.content.Context);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.RecoverableSecurityException> CREATOR;
+ }
+
public final class RemoteAction implements android.os.Parcelable {
ctor public RemoteAction(android.graphics.drawable.Icon, java.lang.CharSequence, java.lang.CharSequence, android.app.RemoteAction.OnActionListener);
method public android.app.RemoteAction clone();
@@ -30567,14 +30579,22 @@
}
public class StorageManager {
+ method public long getCacheQuotaBytes();
+ method public long getCacheSizeBytes();
+ method public long getExternalCacheQuotaBytes();
+ method public long getExternalCacheSizeBytes();
method public java.lang.String getMountedObbPath(java.lang.String);
method public android.os.storage.StorageVolume getPrimaryStorageVolume();
method public android.os.storage.StorageVolume getStorageVolume(java.io.File);
method public java.util.List<android.os.storage.StorageVolume> getStorageVolumes();
+ method public boolean isCacheBehaviorAtomic(java.io.File) throws java.io.IOException;
+ method public boolean isCacheBehaviorTombstone(java.io.File) throws java.io.IOException;
method public boolean isEncrypted(java.io.File);
method public boolean isObbMounted(java.lang.String);
method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
+ method public void setCacheBehaviorAtomic(java.io.File, boolean) throws java.io.IOException;
+ method public void setCacheBehaviorTombstone(java.io.File, boolean) throws java.io.IOException;
method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
}
@@ -37951,7 +37971,8 @@
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
- field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_3WAYCALL_FLASH_DELAY_INT = "cdma_3waycall_flash_delay_int";
@@ -38043,9 +38064,13 @@
field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+ field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+ field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+ field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+ field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -42499,7 +42524,9 @@
method public android.view.Display.Mode[] getSupportedModes();
method public deprecated float[] getSupportedRefreshRates();
method public deprecated int getWidth();
+ method public boolean isHdr();
method public boolean isValid();
+ method public boolean isWideColorGamut();
field public static final int DEFAULT_DISPLAY = 0; // 0x0
field public static final int FLAG_PRESENTATION = 8; // 0x8
field public static final int FLAG_PRIVATE = 4; // 0x4
@@ -42568,7 +42595,7 @@
method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
method public android.view.View findNextFocusFromRect(android.view.ViewGroup, android.graphics.Rect, int);
- method public android.view.View findNextKeyboardNavigationGroup(int, android.view.View, android.view.View, int);
+ method public android.view.View findNextKeyboardNavigationCluster(android.view.View, android.view.View, int);
method public static android.view.FocusFinder getInstance();
}
@@ -43868,7 +43895,7 @@
method public void addChildrenForAccessibility(java.util.ArrayList<android.view.View>);
method public void addFocusables(java.util.ArrayList<android.view.View>, int);
method public void addFocusables(java.util.ArrayList<android.view.View>, int, int);
- method public void addKeyboardNavigationGroups(int, java.util.Collection<android.view.View>, int);
+ method public void addKeyboardNavigationClusters(java.util.Collection<android.view.View>, int);
method public void addOnAttachStateChangeListener(android.view.View.OnAttachStateChangeListener);
method public void addOnLayoutChangeListener(android.view.View.OnLayoutChangeListener);
method public void addTouchables(java.util.ArrayList<android.view.View>);
@@ -44032,7 +44059,6 @@
method public int getNextFocusLeftId();
method public int getNextFocusRightId();
method public int getNextFocusUpId();
- method public int getNextSectionForwardId();
method public android.view.View.OnFocusChangeListener getOnFocusChangeListener();
method public android.view.ViewOutlineProvider getOutlineProvider();
method public int getOverScrollMode();
@@ -44139,7 +44165,6 @@
method public boolean isInLayout();
method public boolean isInTouchMode();
method public final boolean isKeyboardNavigationCluster();
- method public final boolean isKeyboardNavigationSection();
method public boolean isLaidOut();
method public boolean isLayoutDirectionResolved();
method public boolean isLayoutRequested();
@@ -44162,7 +44187,7 @@
method public boolean isVerticalFadingEdgeEnabled();
method public boolean isVerticalScrollBarEnabled();
method public void jumpDrawablesToCurrentState();
- method public android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+ method public android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public void layout(int, int, int, int);
method public final void measure(int, int);
method protected static int[] mergeDrawableStates(int[], int[]);
@@ -44312,7 +44337,6 @@
method public void setImportantForAccessibility(int);
method public void setKeepScreenOn(boolean);
method public void setKeyboardNavigationCluster(boolean);
- method public void setKeyboardNavigationSection(boolean);
method public void setLabelFor(int);
method public void setLayerPaint(android.graphics.Paint);
method public void setLayerType(int, android.graphics.Paint);
@@ -44330,7 +44354,6 @@
method public void setNextFocusLeftId(int);
method public void setNextFocusRightId(int);
method public void setNextFocusUpId(int);
- method public void setNextSectionForwardId(int);
method public void setOnApplyWindowInsetsListener(android.view.View.OnApplyWindowInsetsListener);
method public void setOnClickListener(android.view.View.OnClickListener);
method public void setOnContextClickListener(android.view.View.OnContextClickListener);
@@ -44457,8 +44480,6 @@
field public static final int IMPORTANT_FOR_ACCESSIBILITY_YES = 1; // 0x1
field public static final int INVISIBLE = 4; // 0x4
field public static final int KEEP_SCREEN_ON = 67108864; // 0x4000000
- field public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1; // 0x1
- field public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2; // 0x2
field public static final int LAYER_TYPE_HARDWARE = 2; // 0x2
field public static final int LAYER_TYPE_NONE = 0; // 0x0
field public static final int LAYER_TYPE_SOFTWARE = 1; // 0x1
@@ -44981,7 +45002,7 @@
method public abstract boolean isLayoutRequested();
method public abstract boolean isTextAlignmentResolved();
method public abstract boolean isTextDirectionResolved();
- method public abstract android.view.View keyboardNavigationGroupSearch(int, android.view.View, int);
+ method public abstract android.view.View keyboardNavigationClusterSearch(android.view.View, int);
method public abstract void notifySubtreeAccessibilityStateChanged(android.view.View, android.view.View, int);
method public abstract boolean onNestedFling(android.view.View, float, float, boolean);
method public abstract boolean onNestedPreFling(android.view.View, float, float);
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 1d4b038..c1a888d 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -520,17 +520,17 @@
/** @hide Flag for registerUidObserver: report uid has become active. */
public static final int UID_OBSERVER_ACTIVE = 1<<3;
- /** @hide Mode for {@link IActivityManager#getAppStartMode}: normal free-to-run operation. */
+ /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: normal free-to-run operation. */
public static final int APP_START_MODE_NORMAL = 0;
- /** @hide Mode for {@link IActivityManager#getAppStartMode}: delay running until later. */
+ /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: delay running until later. */
public static final int APP_START_MODE_DELAYED = 1;
- /** @hide Mode for {@link IActivityManager#getAppStartMode}: delay running until later, with
+ /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: delay running until later, with
* rigid errors (throwing exception). */
public static final int APP_START_MODE_DELAYED_RIGID = 2;
- /** @hide Mode for {@link IActivityManager#getAppStartMode}: disable/cancel pending
+ /** @hide Mode for {@link IActivityManager#isAppStartModeDisabled}: disable/cancel pending
* launches; this is the mode for ephemeral apps. */
public static final int APP_START_MODE_DISABLED = 3;
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index b2c97f6..d37888d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1341,8 +1341,8 @@
}
try {
final Intent intent = ActivityManager.getService().registerReceiver(
- mMainThread.getApplicationThread(), mBasePackageName,
- rd, filter, broadcastPermission, userId);
+ mMainThread.getApplicationThread(), mBasePackageName, rd, filter,
+ broadcastPermission, userId);
if (intent != null) {
intent.setExtrasClassLoader(getClassLoader());
intent.prepareToEnterProcess();
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 135c2a4..5a48793 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -264,7 +264,7 @@
boolean isImmersive(in IBinder token);
void setImmersive(in IBinder token, boolean immersive);
boolean isTopActivityImmersive();
- void crashApplication(int uid, int initialPid, in String packageName, in String message);
+ void crashApplication(int uid, int initialPid, in String packageName, int userId, in String message);
String getProviderMimeType(in Uri uri, int userId);
IBinder newUriPermissionOwner(in String name);
void grantUriPermissionFromOwner(in IBinder owner, int fromUid, in String targetPkg,
@@ -475,7 +475,7 @@
void suppressResizeConfigChanges(boolean suppress);
void moveTasksToFullscreenStack(int fromStackId, boolean onTop);
boolean moveTopActivityToPinnedStack(int stackId, in Rect bounds);
- int getAppStartMode(int uid, in String packageName);
+ boolean isAppStartModeDisabled(int uid, in String packageName);
boolean unlockUser(int userid, in byte[] token, in byte[] secret,
in IProgressListener listener);
boolean isInMultiWindowMode(in IBinder token);
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index 3e87254..c0bf0c4 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -327,7 +327,7 @@
* password.
*/
public boolean isDeviceLocked() {
- return isDeviceLocked(UserHandle.getCallingUserId());
+ return isDeviceLocked(UserHandle.myUserId());
}
/**
@@ -352,7 +352,7 @@
* @return true if a PIN, pattern or password was set.
*/
public boolean isDeviceSecure() {
- return isDeviceSecure(UserHandle.getCallingUserId());
+ return isDeviceSecure(UserHandle.myUserId());
}
/**
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 5b74e23..601dfce 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -7088,11 +7088,13 @@
private static final String EXTRA_FLAGS = "flags";
private static final String EXTRA_CONTENT_INTENT = "content_intent";
private static final String EXTRA_DELETE_INTENT = "delete_intent";
+ private static final String EXTRA_CHANNEL_ID = "channel_id";
// Flags bitwise-ored to mFlags
private static final int FLAG_AVAILABLE_ON_TV = 0x1;
private int mFlags;
+ private String mChannelId;
private PendingIntent mContentIntent;
private PendingIntent mDeleteIntent;
@@ -7113,6 +7115,7 @@
null : notif.extras.getBundle(EXTRA_TV_EXTENDER);
if (bundle != null) {
mFlags = bundle.getInt(EXTRA_FLAGS);
+ mChannelId = bundle.getString(EXTRA_CHANNEL_ID);
mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT);
mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT);
}
@@ -7128,6 +7131,7 @@
Bundle bundle = new Bundle();
bundle.putInt(EXTRA_FLAGS, mFlags);
+ bundle.putString(EXTRA_CHANNEL_ID, mChannelId);
if (mContentIntent != null) {
bundle.putParcelable(EXTRA_CONTENT_INTENT, mContentIntent);
}
@@ -7149,6 +7153,23 @@
}
/**
+ * Specifies the channel the notification should be delivered on when shown on TV.
+ * It can be different from the channel that the notification is delivered to when
+ * posting on a non-TV device.
+ */
+ public TvExtender setChannel(String channelId) {
+ mChannelId = channelId;
+ return this;
+ }
+
+ /**
+ * Returns the id of the channel this notification posts to on TV.
+ */
+ public String getChannel() {
+ return mChannelId;
+ }
+
+ /**
* Supplies a {@link PendingIntent} to be sent when the notification is selected on TV.
* If provided, it is used instead of the content intent specified
* at the level of Notification.
diff --git a/core/java/android/app/RecoverableSecurityException.java b/core/java/android/app/RecoverableSecurityException.java
new file mode 100644
index 0000000..1f015a6
--- /dev/null
+++ b/core/java/android/app/RecoverableSecurityException.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.internal.util.Preconditions;
+
+/**
+ * Specialization of {@link SecurityException} that contains additional
+ * information about how to involve the end user to recover from the exception.
+ * <p>
+ * This exception is only appropriate where there is a concrete action the user
+ * can take to recover and make forward progress, such as confirming or entering
+ * authentication credentials.
+ * <p class="note">
+ * Note: legacy code that receives this exception may treat it as a general
+ * {@link SecurityException}, and thus there is no guarantee that the messages
+ * contained will be shown to the end user.
+ * </p>
+ */
+public final class RecoverableSecurityException extends SecurityException implements Parcelable {
+ private static final String TAG = "RecoverableSecurityException";
+
+ private final CharSequence mUserMessage;
+ private final CharSequence mUserActionTitle;
+ private final PendingIntent mUserAction;
+
+ /** {@hide} */
+ public RecoverableSecurityException(Parcel in) {
+ this(new SecurityException(in.readString()), in.readCharSequence(), in.readCharSequence(),
+ PendingIntent.CREATOR.createFromParcel(in));
+ }
+
+ /**
+ * Create an instance ready to be thrown.
+ *
+ * @param cause original cause with details designed for engineering
+ * audiences.
+ * @param userMessage short message describing the issue for end user
+ * audiences, which may be shown in a notification or dialog.
+ * This should be less than 64 characters. For example: <em>PIN
+ * required to access Document.pdf</em>
+ * @param userActionTitle short title describing the primary action. This
+ * should be less than 24 characters. For example: <em>Enter
+ * PIN</em>
+ * @param userAction primary action that will initiate the recovery. This
+ * must launch an activity that is expected to set
+ * {@link Activity#setResult(int)} before finishing to
+ * communicate the final status of the recovery. For example,
+ * apps that observe {@link Activity#RESULT_OK} may choose to
+ * immediately retry their operation.
+ */
+ public RecoverableSecurityException(Throwable cause, CharSequence userMessage,
+ CharSequence userActionTitle, PendingIntent userAction) {
+ super(cause.getMessage());
+ mUserMessage = Preconditions.checkNotNull(userMessage);
+ mUserActionTitle = Preconditions.checkNotNull(userActionTitle);
+ mUserAction = Preconditions.checkNotNull(userAction);
+ }
+
+ /**
+ * Return short message describing the issue for end user audiences, which
+ * may be shown in a notification or dialog.
+ */
+ public CharSequence getUserMessage() {
+ return mUserMessage;
+ }
+
+ /**
+ * Return short title describing the primary action.
+ */
+ public CharSequence getUserActionTitle() {
+ return mUserActionTitle;
+ }
+
+ /**
+ * Return primary action that will initiate the recovery.
+ */
+ public PendingIntent getUserAction() {
+ return mUserAction;
+ }
+
+ /**
+ * Convenience method that will show a very simple notification populated
+ * with the details from this exception.
+ * <p>
+ * If you want more flexibility over retrying your original operation once
+ * the user action has finished, consider presenting your own UI that uses
+ * {@link Activity#startIntentSenderForResult} to launch the
+ * {@link PendingIntent#getIntentSender()} from {@link #getUserAction()}
+ * when requested. If the result of that activity is
+ * {@link Activity#RESULT_OK}, you should consider retrying.
+ * <p>
+ * This method will only display the most recent exception from any single
+ * remote UID; notifications from older exceptions will always be replaced.
+ */
+ public void showAsNotification(Context context) {
+ final Notification.Builder builder = new Notification.Builder(context)
+ .setSmallIcon(com.android.internal.R.drawable.ic_print_error)
+ .setContentTitle(mUserActionTitle)
+ .setContentText(mUserMessage)
+ .setContentIntent(mUserAction)
+ .setCategory(Notification.CATEGORY_ERROR);
+
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+ nm.notify(TAG, mUserAction.getCreatorUid(), builder.build());
+ }
+
+ /**
+ * Convenience method that will show a very simple dialog populated with the
+ * details from this exception.
+ * <p>
+ * If you want more flexibility over retrying your original operation once
+ * the user action has finished, consider presenting your own UI that uses
+ * {@link Activity#startIntentSenderForResult} to launch the
+ * {@link PendingIntent#getIntentSender()} from {@link #getUserAction()}
+ * when requested. If the result of that activity is
+ * {@link Activity#RESULT_OK}, you should consider retrying.
+ * <p>
+ * This method will only display the most recent exception from any single
+ * remote UID; dialogs from older exceptions will always be replaced.
+ */
+ public void showAsDialog(Activity activity) {
+ final LocalDialog dialog = new LocalDialog();
+ final Bundle args = new Bundle();
+ args.putParcelable(TAG, this);
+ dialog.setArguments(args);
+
+ final String tag = TAG + "_" + mUserAction.getCreatorUid();
+ final FragmentManager fm = activity.getFragmentManager();
+ final FragmentTransaction ft = fm.beginTransaction();
+ final Fragment old = fm.findFragmentByTag(tag);
+ if (old != null) {
+ ft.remove(old);
+ }
+ ft.add(dialog, tag);
+ ft.commitAllowingStateLoss();
+ }
+
+ /** {@hide} */
+ public static class LocalDialog extends DialogFragment {
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ final RecoverableSecurityException e = getArguments().getParcelable(TAG);
+ return new AlertDialog.Builder(getActivity())
+ .setMessage(e.mUserMessage)
+ .setPositiveButton(e.mUserActionTitle, (dialog, which) -> {
+ try {
+ e.mUserAction.send();
+ } catch (PendingIntent.CanceledException ignored) {
+ }
+ })
+ .setNegativeButton(android.R.string.cancel, null)
+ .create();
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(getMessage());
+ dest.writeCharSequence(mUserMessage);
+ dest.writeCharSequence(mUserActionTitle);
+ mUserAction.writeToParcel(dest, flags);
+ }
+
+ public static final Creator<RecoverableSecurityException> CREATOR =
+ new Creator<RecoverableSecurityException>() {
+ @Override
+ public RecoverableSecurityException createFromParcel(Parcel source) {
+ return new RecoverableSecurityException(source);
+ }
+
+ @Override
+ public RecoverableSecurityException[] newArray(int size) {
+ return new RecoverableSecurityException[size];
+ }
+ };
+}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 0da89eb..aa56be6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3735,13 +3735,13 @@
}
/**
- * Called by a device owner to set whether auto time is required. If auto time is required the
- * user cannot set the date and time, but has to use network date and time.
+ * Called by a device or profile owner to set whether auto time is required. If auto time is
+ * required, no user will be able set the date and time and network date and time will be used.
* <p>
* Note: if auto time is required the user can still manually set the time zone.
* <p>
- * The calling device admin must be a device owner. If it is not, a security exception will be
- * thrown.
+ * The calling device admin must be a device or profile owner. If it is not, a security
+ * exception will be thrown.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param required Whether auto time is set required or not.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 8cc9a3a..c550094 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4842,6 +4842,10 @@
* or not running) apps, regardless of whether that would be done by default. By
* default they will only receive broadcasts if the broadcast has specified an
* explicit component or package name.
+ *
+ * NOTE: dumpstate uses this flag numerically, so when its value is changed
+ * the broadcast code there must also be changed to match.
+ *
* @hide
*/
public static final int FLAG_RECEIVER_INCLUDE_BACKGROUND = 0x01000000;
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index b03c907..35a266b 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -291,4 +291,6 @@
void fstrim(int flags) = 72;
AppFuseMount mountProxyFileDescriptorBridge() = 73;
ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
+ long getCacheQuotaBytes(String volumeUuid, int uid) = 75;
+ long getCacheSizeBytes(String volumeUuid, int uid) = 76;
}
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index c6ff476..626d6f4 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -24,27 +24,32 @@
import android.app.ActivityThread;
import android.content.ContentResolver;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageMoveObserver;
import android.content.pm.PackageManager;
import android.os.Binder;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
-import android.os.ProxyFileDescriptorCallback;
import android.os.Looper;
import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.ServiceManager.ServiceNotFoundException;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.OsConstants;
import android.text.TextUtils;
import android.util.Log;
import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
+
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.os.AppFuseMount;
@@ -60,6 +65,7 @@
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.ref.WeakReference;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -1396,6 +1402,222 @@
}
}
+ /**
+ * Return quota size in bytes for cached data belonging to the calling app.
+ * <p>
+ * If your app goes above this quota, your cached files will be some of the
+ * first to be deleted when additional disk space is needed. Conversely, if
+ * your app stays under this quota, your cached files will be some of the
+ * last to be deleted when additional disk space is needed.
+ * <p>
+ * This quota may change over time depending on how frequently the user
+ * interacts with your app, and depending on how much disk space is used.
+ * <p>
+ * Cached data tracked by this method always includes
+ * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
+ * it also includes {@link Context#getExternalCacheDir()} if the primary
+ * shared/external storage is hosted on the same storage device as your
+ * private data.
+ * <p class="note">
+ * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+ * then cached data for all packages in your shared UID is tracked together
+ * as a single unit.
+ * </p>
+ *
+ * @see #getCacheQuotaBytes()
+ * @see #getCacheSizeBytes()
+ * @see #getExternalCacheQuotaBytes()
+ * @see #getExternalCacheSizeBytes()
+ */
+ public long getCacheQuotaBytes() {
+ try {
+ final ApplicationInfo app = mContext.getApplicationInfo();
+ return mStorageManager.getCacheQuotaBytes(app.volumeUuid, app.uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return total size in bytes of cached data belonging to the calling app.
+ * <p>
+ * Cached data tracked by this method always includes
+ * {@link Context#getCacheDir()} and {@link Context#getCodeCacheDir()}, and
+ * it also includes {@link Context#getExternalCacheDir()} if the primary
+ * shared/external storage is hosted on the same storage device as your
+ * private data.
+ * <p class="note">
+ * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+ * then cached data for all packages in your shared UID is tracked together
+ * as a single unit.
+ * </p>
+ *
+ * @see #getCacheQuotaBytes()
+ * @see #getCacheSizeBytes()
+ * @see #getExternalCacheQuotaBytes()
+ * @see #getExternalCacheSizeBytes()
+ */
+ public long getCacheSizeBytes() {
+ try {
+ final ApplicationInfo app = mContext.getApplicationInfo();
+ return mStorageManager.getCacheSizeBytes(app.volumeUuid, app.uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return quota size in bytes for cached data on primary shared/external
+ * storage belonging to the calling app.
+ * <p>
+ * If primary shared/external storage is hosted on the same storage device
+ * as your private data, this method will return -1, since all data stored
+ * under {@link Context#getExternalCacheDir()} will be counted under
+ * {@link #getCacheQuotaBytes()}.
+ * <p class="note">
+ * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+ * then cached data for all packages in your shared UID is tracked together
+ * as a single unit.
+ * </p>
+ */
+ public long getExternalCacheQuotaBytes() {
+ final ApplicationInfo app = mContext.getApplicationInfo();
+ final String primaryUuid = getPrimaryStorageUuid();
+ if (Objects.equals(app.volumeUuid, primaryUuid)) {
+ return -1;
+ }
+ try {
+ return mStorageManager.getCacheQuotaBytes(primaryUuid, app.uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Return total size in bytes of cached data on primary shared/external
+ * storage belonging to the calling app.
+ * <p>
+ * If primary shared/external storage is hosted on the same storage device
+ * as your private data, this method will return -1, since all data stored
+ * under {@link Context#getExternalCacheDir()} will be counted under
+ * {@link #getCacheQuotaBytes()}.
+ * <p class="note">
+ * Note: if your app uses the {@code android:sharedUserId} manifest feature,
+ * then cached data for all packages in your shared UID is tracked together
+ * as a single unit.
+ * </p>
+ */
+ public long getExternalCacheSizeBytes() {
+ final ApplicationInfo app = mContext.getApplicationInfo();
+ final String primaryUuid = getPrimaryStorageUuid();
+ if (Objects.equals(app.volumeUuid, primaryUuid)) {
+ return -1;
+ }
+ try {
+ return mStorageManager.getCacheSizeBytes(primaryUuid, app.uid);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ private static final String XATTR_ATOMIC = "user.atomic";
+ private static final String XATTR_TOMBSTONE = "user.tombstone";
+
+ /** {@hide} */
+ private static void setCacheBehavior(File path, String name, boolean enabled)
+ throws IOException {
+ if (!path.isDirectory()) {
+ throw new IOException("Cache behavior can only be set on directories");
+ }
+ if (enabled) {
+ try {
+ Os.setxattr(path.getAbsolutePath(), name,
+ "1".getBytes(StandardCharsets.UTF_8), 0);
+ } catch (ErrnoException e) {
+ throw e.rethrowAsIOException();
+ }
+ } else {
+ try {
+ Os.removexattr(path.getAbsolutePath(), name);
+ } catch (ErrnoException e) {
+ if (e.errno != OsConstants.ENODATA) {
+ throw e.rethrowAsIOException();
+ }
+ }
+ }
+ }
+
+ /** {@hide} */
+ private static boolean isCacheBehavior(File path, String name) throws IOException {
+ try {
+ Os.getxattr(path.getAbsolutePath(), name);
+ return true;
+ } catch (ErrnoException e) {
+ if (e.errno != OsConstants.ENODATA) {
+ throw e.rethrowAsIOException();
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Enable or disable special cache behavior that treats this directory and
+ * its contents as an atomic unit.
+ * <p>
+ * When enabled and this directory is considered for automatic deletion by
+ * the OS, all contained files will either be deleted together, or not at
+ * all. This is useful when you have a directory that contains several
+ * related metadata files that depend on each other, such as movie file and
+ * a subtitle file.
+ * <p>
+ * When enabled, the <em>newest</em> {@link File#lastModified()} value of
+ * any contained files is considered the modified time of the entire
+ * directory.
+ * <p>
+ * This behavior can only be set on a directory, and it applies recursively
+ * to all contained files and directories.
+ */
+ public void setCacheBehaviorAtomic(File path, boolean atomic) throws IOException {
+ setCacheBehavior(path, XATTR_ATOMIC, atomic);
+ }
+
+ /**
+ * Read the current value set by
+ * {@link #setCacheBehaviorAtomic(File, boolean)}.
+ */
+ public boolean isCacheBehaviorAtomic(File path) throws IOException {
+ return isCacheBehavior(path, XATTR_ATOMIC);
+ }
+
+ /**
+ * Enable or disable special cache behavior that leaves deleted cache files
+ * intact as tombstones.
+ * <p>
+ * When enabled and a file contained in this directory is automatically
+ * deleted by the OS, the file will be truncated to have a length of 0 bytes
+ * instead of being fully deleted. This is useful if you need to distinguish
+ * between a file that was deleted versus one that never existed.
+ * <p>
+ * This behavior can only be set on a directory, and it applies recursively
+ * to all contained files and directories.
+ * <p class="note">
+ * Note: this behavior is ignored completely if the user explicitly requests
+ * that all cached data be cleared.
+ * </p>
+ */
+ public void setCacheBehaviorTombstone(File path, boolean tombstone) throws IOException {
+ setCacheBehavior(path, XATTR_TOMBSTONE, tombstone);
+ }
+
+ /**
+ * Read the current value set by
+ * {@link #setCacheBehaviorTombstone(File, boolean)}.
+ */
+ public boolean isCacheBehaviorTombstone(File path) throws IOException {
+ return isCacheBehavior(path, XATTR_TOMBSTONE);
+ }
+
private final Object mFuseAppLoopLock = new Object();
@GuardedBy("mFuseAppLoopLock")
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index b37ea8e..105cc47 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -292,7 +292,7 @@
public static final int STATE_VR = 5;
/* The color mode constants defined below must be kept in sync with the ones in
- * system/graphics.h */
+ * system/core/include/system/graphics-base.h */
/**
* Display color mode: The current color mode is unknown or invalid.
@@ -306,11 +306,24 @@
*/
public static final int COLOR_MODE_DEFAULT = 0;
- /**
- * Display color mode: SRGB
- * @hide
- */
+ /** @hide */
+ public static final int COLOR_MODE_BT601_625 = 1;
+ /** @hide */
+ public static final int COLOR_MODE_BT601_625_UNADJUSTED = 2;
+ /** @hide */
+ public static final int COLOR_MODE_BT601_525 = 3;
+ /** @hide */
+ public static final int COLOR_MODE_BT601_525_UNADJUSTED = 4;
+ /** @hide */
+ public static final int COLOR_MODE_BT709 = 5;
+ /** @hide */
+ public static final int COLOR_MODE_DCI_P3 = 6;
+ /** @hide */
public static final int COLOR_MODE_SRGB = 7;
+ /** @hide */
+ public static final int COLOR_MODE_ADOBE_RGB = 8;
+ /** @hide */
+ public static final int COLOR_MODE_DISPLAY_P3 = 9;
/**
* Internal method to create a display.
@@ -745,6 +758,8 @@
/**
* Returns the display's HDR capabilities.
+ *
+ * @see #isHdr()
*/
public HdrCapabilities getHdrCapabilities() {
synchronized (this) {
@@ -754,6 +769,35 @@
}
/**
+ * Returns whether this display supports any HDR type.
+ *
+ * @see #getHdrCapabilities()
+ * @see HdrCapabilities#getSupportedHdrTypes()
+ */
+ public boolean isHdr() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ int[] types = mDisplayInfo.hdrCapabilities.getSupportedHdrTypes();
+ return types != null && types.length > 0;
+ }
+ }
+
+ /**
+ * Returns whether this display can be used to display wide color gamut content.
+ */
+ public boolean isWideColorGamut() {
+ synchronized (this) {
+ updateDisplayInfoLocked();
+ for (int colorMode : mDisplayInfo.supportedColorModes) {
+ if (colorMode == COLOR_MODE_DCI_P3 || colorMode > COLOR_MODE_SRGB) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+
+ /**
* Gets the supported color modes of this device.
* @hide
*/
diff --git a/core/java/android/view/FocusFinder.java b/core/java/android/view/FocusFinder.java
index a07a7ef..41a13cf 100644
--- a/core/java/android/view/FocusFinder.java
+++ b/core/java/android/view/FocusFinder.java
@@ -16,16 +16,12 @@
package android.view;
-import static android.view.View.KEYBOARD_NAVIGATION_GROUP_CLUSTER;
-import static android.view.View.KEYBOARD_NAVIGATION_GROUP_SECTION;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.graphics.Rect;
import android.util.ArrayMap;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
-import android.view.View.KeyboardNavigationGroupType;
import java.util.ArrayList;
import java.util.Collections;
@@ -110,31 +106,28 @@
}
/**
- * Find the root of the next keyboard navigation group after the current one. The group type can
- * be either a cluster or a section.
- * @param groupType Type of the keyboard navigation group
+ * Find the root of the next keyboard navigation cluster after the current one.
* @param root The view tree to look inside. Cannot be null
- * @param currentGroup The starting point of the search. Null means the default group
+ * @param currentCluster The starting point of the search. Null means the default cluster
* @param direction Direction to look
- * @return The next group, or null if none exists
+ * @return The next cluster, or null if none exists
*/
- public View findNextKeyboardNavigationGroup(
- @KeyboardNavigationGroupType int groupType,
+ public View findNextKeyboardNavigationCluster(
@NonNull View root,
- @Nullable View currentGroup,
+ @Nullable View currentCluster,
int direction) {
View next = null;
- final ArrayList<View> groups = mTempList;
+ final ArrayList<View> clusters = mTempList;
try {
- groups.clear();
- root.addKeyboardNavigationGroups(groupType, groups, direction);
- if (!groups.isEmpty()) {
- next = findNextKeyboardNavigationGroup(
- groupType, root, currentGroup, groups, direction);
+ clusters.clear();
+ root.addKeyboardNavigationClusters(clusters, direction);
+ if (!clusters.isEmpty()) {
+ next = findNextKeyboardNavigationCluster(
+ root, currentCluster, clusters, direction);
}
} finally {
- groups.clear();
+ clusters.clear();
}
return next;
}
@@ -207,25 +200,22 @@
}
}
- private View findNextKeyboardNavigationGroup(
- @KeyboardNavigationGroupType int groupType,
+ private View findNextKeyboardNavigationCluster(
View root,
- View currentGroup,
- List<View> groups,
+ View currentCluster,
+ List<View> clusters,
int direction) {
- final int count = groups.size();
+ final int count = clusters.size();
switch (direction) {
case View.FOCUS_FORWARD:
case View.FOCUS_DOWN:
case View.FOCUS_RIGHT:
- return getNextKeyboardNavigationGroup(
- groupType, root, currentGroup, groups, count);
+ return getNextKeyboardNavigationCluster(root, currentCluster, clusters, count);
case View.FOCUS_BACKWARD:
case View.FOCUS_UP:
case View.FOCUS_LEFT:
- return getPreviousKeyboardNavigationGroup(
- groupType, root, currentGroup, groups, count);
+ return getPreviousKeyboardNavigationCluster(root, currentCluster, clusters, count);
default:
throw new IllegalArgumentException("Unknown direction: " + direction);
}
@@ -331,70 +321,50 @@
return null;
}
- private static View getNextKeyboardNavigationGroup(
- @KeyboardNavigationGroupType int groupType,
+ private static View getNextKeyboardNavigationCluster(
View root,
- View currentGroup,
- List<View> groups,
+ View currentCluster,
+ List<View> clusters,
int count) {
- if (currentGroup == null) {
- // The current group is the default one.
- // The next group after the default one is the first one.
- // Note that the caller guarantees that 'group' is not empty.
- return groups.get(0);
+ if (currentCluster == null) {
+ // The current cluster is the default one.
+ // The next cluster after the default one is the first one.
+ // Note that the caller guarantees that 'clusters' is not empty.
+ return clusters.get(0);
}
- final int position = groups.lastIndexOf(currentGroup);
+ final int position = clusters.lastIndexOf(currentCluster);
if (position >= 0 && position + 1 < count) {
- // Return the next non-default group if we can find it.
- return groups.get(position + 1);
+ // Return the next non-default cluster if we can find it.
+ return clusters.get(position + 1);
}
- switch (groupType) {
- case KEYBOARD_NAVIGATION_GROUP_CLUSTER:
- // The current cluster is the last one. The next one is the default one, i.e. the
- // root.
- return root;
- case KEYBOARD_NAVIGATION_GROUP_SECTION:
- // There is no "default section", hence returning the first one.
- return groups.get(0);
- default:
- throw new IllegalArgumentException(
- "Unknown keyboard navigation group type: " + groupType);
- }
+ // The current cluster is the last one. The next one is the default one, i.e. the
+ // root.
+ return root;
}
- private static View getPreviousKeyboardNavigationGroup(
- @KeyboardNavigationGroupType int groupType,
+ private static View getPreviousKeyboardNavigationCluster(
View root,
- View currentGroup,
- List<View> groups,
+ View currentCluster,
+ List<View> clusters,
int count) {
- if (currentGroup == null) {
- // The current group is the default one.
- // The previous group before the default one is the last one.
- // Note that the caller guarantees that 'groups' is not empty.
- return groups.get(count - 1);
+ if (currentCluster == null) {
+ // The current cluster is the default one.
+ // The previous cluster before the default one is the last one.
+ // Note that the caller guarantees that 'clusters' is not empty.
+ return clusters.get(count - 1);
}
- final int position = groups.indexOf(currentGroup);
+ final int position = clusters.indexOf(currentCluster);
if (position > 0) {
- // Return the previous non-default group if we can find it.
- return groups.get(position - 1);
+ // Return the previous non-default cluster if we can find it.
+ return clusters.get(position - 1);
}
- switch (groupType) {
- case KEYBOARD_NAVIGATION_GROUP_CLUSTER:
- // The current cluster is the first one. The previous one is the default one, i.e.
- // the root.
- return root;
- case KEYBOARD_NAVIGATION_GROUP_SECTION:
- // There is no "default section", hence returning the last one.
- return groups.get(count - 1);
- default:
- throw new IllegalArgumentException(
- "Unknown keyboard navigation group type: " + groupType);
- }
+ // The current cluster is the first one. The previous one is the default one, i.e.
+ // the root.
+ return root;
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 26e311c..13555f4 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1252,14 +1252,6 @@
@Retention(RetentionPolicy.SOURCE)
public @interface FocusRealDirection {} // Like @FocusDirection, but without forward/backward
- /** @hide */
- @IntDef({
- KEYBOARD_NAVIGATION_GROUP_CLUSTER,
- KEYBOARD_NAVIGATION_GROUP_SECTION
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface KeyboardNavigationGroupType {}
-
/**
* Use with {@link #focusSearch(int)}. Move focus to the previous selectable
* item.
@@ -1293,18 +1285,6 @@
public static final int FOCUS_DOWN = 0x00000082;
/**
- * Use with {@link #keyboardNavigationGroupSearch(int, View, int)}. Search for a keyboard
- * navigation cluster.
- */
- public static final int KEYBOARD_NAVIGATION_GROUP_CLUSTER = 1;
-
- /**
- * Use with {@link #keyboardNavigationGroupSearch(int, View, int)}. Search for a keyboard
- * navigation section.
- */
- public static final int KEYBOARD_NAVIGATION_GROUP_SECTION = 2;
-
- /**
* Bits of {@link #getMeasuredWidthAndState()} and
* {@link #getMeasuredWidthAndState()} that provide the actual measured size.
*/
@@ -2500,7 +2480,7 @@
* 1 PFLAG3_SCROLL_INDICATOR_END
* 1 PFLAG3_ASSIST_BLOCKED
* 1 PFLAG3_CLUSTER
- * 1 PFLAG3_SECTION
+ * x * NO LONGER NEEDED, SHOULD BE REUSED *
* 1 PFLAG3_FINGER_DOWN
* 1 PFLAG3_FOCUSED_BY_DEFAULT
* xxxx * NO LONGER NEEDED, SHOULD BE REUSED *
@@ -2710,14 +2690,6 @@
private static final int PFLAG3_CLUSTER = 0x8000;
/**
- * Flag indicating that the view is a root of a keyboard navigation section.
- *
- * @see #isKeyboardNavigationSection()
- * @see #setKeyboardNavigationSection(boolean)
- */
- private static final int PFLAG3_SECTION = 0x10000;
-
- /**
* Indicates that the user is currently touching the screen.
* Currently used for the tooltip positioning only.
*/
@@ -3807,11 +3779,6 @@
*/
int mNextClusterForwardId = View.NO_ID;
- /**
- * User-specified next keyboard navigation section.
- */
- int mNextSectionForwardId = View.NO_ID;
-
private CheckForLongPress mPendingCheckForLongPress;
private CheckForTap mPendingCheckForTap = null;
private PerformClick mPerformClick;
@@ -4622,9 +4589,6 @@
case R.styleable.View_nextClusterForward:
mNextClusterForwardId = a.getResourceId(attr, View.NO_ID);
break;
- case R.styleable.View_nextSectionForward:
- mNextSectionForwardId = a.getResourceId(attr, View.NO_ID);
- break;
case R.styleable.View_minWidth:
mMinWidth = a.getDimensionPixelSize(attr, 0);
break;
@@ -4769,11 +4733,6 @@
setKeyboardNavigationCluster(a.getBoolean(attr, true));
}
break;
- case R.styleable.View_keyboardNavigationSection:
- if (a.peekValue(attr) != null) {
- setKeyboardNavigationSection(a.getBoolean(attr, true));
- }
- break;
case R.styleable.View_focusedByDefault:
if (a.peekValue(attr) != null) {
setFocusedByDefault(a.getBoolean(attr, true));
@@ -8043,28 +8002,6 @@
}
/**
- * Gets the id of the root of the next keyboard navigation section.
- * @return The next keyboard navigation section ID, or {@link #NO_ID} if the framework should
- * decide automatically.
- *
- * @attr ref android.R.styleable#View_nextSectionForward
- */
- public int getNextSectionForwardId() {
- return mNextSectionForwardId;
- }
-
- /**
- * Sets the id of the view to use as the root of the next keyboard navigation section.
- * @param nextSectionForwardId The next section ID, or {@link #NO_ID} if the framework should
- * decide automatically.
- *
- * @attr ref android.R.styleable#View_nextSectionForward
- */
- public void setNextSectionForwardId(int nextSectionForwardId) {
- mNextSectionForwardId = nextSectionForwardId;
- }
-
- /**
* Returns the visibility of this view and all of its ancestors
*
* @return True if this view and all of its ancestors are {@link #VISIBLE}
@@ -9186,49 +9123,11 @@
}
/**
- * Returns whether this View is a root of a keyboard navigation section.
- *
- * @return True if this view is a root of a section, or false otherwise.
- * @attr ref android.R.styleable#View_keyboardNavigationSection
- */
- @ViewDebug.ExportedProperty(category = "keyboardNavigationSection")
- public final boolean isKeyboardNavigationSection() {
- return (mPrivateFlags3 & PFLAG3_SECTION) != 0;
- }
-
- /**
- * Set whether this view is a root of a keyboard navigation section.
- *
- * @param isSection If true, this view is a root of a section.
- *
- * @attr ref android.R.styleable#View_keyboardNavigationSection
- */
- public void setKeyboardNavigationSection(boolean isSection) {
- if (isSection) {
- mPrivateFlags3 |= PFLAG3_SECTION;
- } else {
- mPrivateFlags3 &= ~PFLAG3_SECTION;
- }
- }
-
- final boolean isKeyboardNavigationGroupOfType(@KeyboardNavigationGroupType int groupType) {
- switch (groupType) {
- case KEYBOARD_NAVIGATION_GROUP_CLUSTER:
- return isKeyboardNavigationCluster();
- case KEYBOARD_NAVIGATION_GROUP_SECTION:
- return isKeyboardNavigationSection();
- default:
- throw new IllegalArgumentException(
- "Unknown keyboard navigation group type: " + groupType);
- }
- }
-
- /**
* Returns whether this View should receive focus when the focus is restored for the view
* hierarchy containing this view.
* <p>
* Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
- * window or serves as a target of cluster or section navigation.
+ * window or serves as a target of cluster navigation.
*
* @see #restoreDefaultFocus(int)
*
@@ -9245,7 +9144,7 @@
* hierarchy containing this view.
* <p>
* Focus gets restored for a view hierarchy when the root of the hierarchy gets added to a
- * window or serves as a target of cluster or section navigation.
+ * window or serves as a target of cluster navigation.
*
* @param isFocusedByDefault {@code true} to set this view as the default-focus view,
* {@code false} otherwise.
@@ -9284,35 +9183,28 @@
}
/**
- * Find the nearest keyboard navigation group in the specified direction. The group type can be
- * either a cluster or a section.
- * This does not actually give focus to that group.
+ * Find the nearest keyboard navigation cluster in the specified direction.
+ * This does not actually give focus to that cluster.
*
- * @param groupType Type of the keyboard navigation group
- * @param currentGroup The starting point of the search. Null means the current group is not
- * found yet
+ * @param currentCluster The starting point of the search. Null means the current cluster is not
+ * found yet
* @param direction Direction to look
*
- * @return The nearest keyboard navigation group in the specified direction, or null if none
+ * @return The nearest keyboard navigation cluster in the specified direction, or null if none
* can be found
*/
- public View keyboardNavigationGroupSearch(
- @KeyboardNavigationGroupType int groupType, View currentGroup, int direction) {
- if (isKeyboardNavigationGroupOfType(groupType)) {
- currentGroup = this;
+ public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
+ if (isKeyboardNavigationCluster()) {
+ currentCluster = this;
}
- if (isRootNamespace()
- || (groupType == KEYBOARD_NAVIGATION_GROUP_SECTION
- && isKeyboardNavigationCluster())) {
+ if (isRootNamespace()) {
// Root namespace means we should consider ourselves the top of the
// tree for group searching; otherwise we could be group searching
// into other tabs. see LocalActivityManager and TabHost for more info.
- // In addition, a cluster node works as a root for section searches.
- return FocusFinder.getInstance().findNextKeyboardNavigationGroup(
- groupType, this, currentGroup, direction);
+ return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
+ this, currentCluster, direction);
} else if (mParent != null) {
- return mParent.keyboardNavigationGroupSearch(
- groupType, currentGroup, direction);
+ return mParent.keyboardNavigationClusterSearch(currentCluster, direction);
}
return null;
}
@@ -9440,19 +9332,16 @@
}
/**
- * Adds any keyboard navigation group roots that are descendants of this view (possibly
- * including this view if it is a group root itself) to views. The group type can be either a
- * cluster or a section.
+ * Adds any keyboard navigation cluster roots that are descendants of this view (possibly
+ * including this view if it is a cluster root itself) to views.
*
- * @param groupType Type of the keyboard navigation group
- * @param views Keyboard navigation group roots found so far
+ * @param views Keyboard navigation cluster roots found so far
* @param direction Direction to look
*/
- public void addKeyboardNavigationGroups(
- @KeyboardNavigationGroupType int groupType,
+ public void addKeyboardNavigationClusters(
@NonNull Collection<View> views,
int direction) {
- if (!(isKeyboardNavigationGroupOfType(groupType))) {
+ if (!(isKeyboardNavigationCluster())) {
return;
}
views.add(this);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index d252d75..480741e 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -915,13 +915,10 @@
*/
@Override
public View focusSearch(View focused, int direction) {
- if (isRootNamespace()
- || isKeyboardNavigationCluster()
- && (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD)) {
+ if (isRootNamespace()) {
// root namespace means we should consider ourselves the top of the
// tree for focus searching; otherwise we could be focus searching
// into other tabs. see LocalActivityManager and TabHost for more info.
- // Cluster's root works same way for the forward and backward navigation.
return FocusFinder.getInstance().findNextFocus(this, focused, direction);
} else if (mParent != null) {
return mParent.focusSearch(focused, direction);
@@ -1136,12 +1133,6 @@
@Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
- if (isKeyboardNavigationCluster()
- && (direction == FOCUS_FORWARD || direction == FOCUS_BACKWARD) && !hasFocus()) {
- // A cluster cannot be focus-entered from outside using forward/backward navigation.
- return;
- }
-
final int focusableCount = views.size();
final int descendantFocusability = getDescendantFocusability();
@@ -1175,11 +1166,10 @@
}
@Override
- public void addKeyboardNavigationGroups(
- @KeyboardNavigationGroupType int groupType, Collection<View> views, int direction) {
+ public void addKeyboardNavigationClusters(Collection<View> views, int direction) {
final int focusableCount = views.size();
- super.addKeyboardNavigationGroups(groupType, views, direction);
+ super.addKeyboardNavigationClusters(views, direction);
if (focusableCount != views.size()) {
// No need to look for groups inside a group.
@@ -1195,14 +1185,8 @@
for (int i = 0; i < count; i++) {
final View child = children[i];
- if (groupType == KEYBOARD_NAVIGATION_GROUP_SECTION
- && child.isKeyboardNavigationCluster()) {
- // When the current cluster is the default cluster, and we are searching for
- // sections, ignore sections inside non-default clusters.
- continue;
- }
if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
- child.addKeyboardNavigationGroups(groupType, views, direction);
+ child.addKeyboardNavigationClusters(views, direction);
}
}
}
@@ -3072,8 +3056,7 @@
final View[] children = mChildren;
for (int i = index; i != end; i += increment) {
View child = children[i];
- if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE
- && !child.isKeyboardNavigationCluster()) {
+ if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE) {
if (child.requestFocus(direction, previouslyFocusedRect)) {
return true;
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index c9277ca..79b05cd 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -18,7 +18,6 @@
import android.graphics.Rect;
import android.os.Bundle;
-import android.view.View.KeyboardNavigationGroupType;
import android.view.accessibility.AccessibilityEvent;
/**
@@ -148,20 +147,17 @@
public View focusSearch(View v, int direction);
/**
- * Find the nearest keyboard navigation group in the specified direction. The group type can be
- * either a cluster or a section.
- * This does not actually give focus to that group.
+ * Find the nearest keyboard navigation cluster in the specified direction.
+ * This does not actually give focus to that cluster.
*
- * @param groupType Type of the keyboard navigation group
- * @param currentGroup The starting point of the search. Null means the current group is not
- * found yet
+ * @param currentCluster The starting point of the search. Null means the current cluster is not
+ * found yet
* @param direction Direction to look
*
- * @return The nearest keyboard navigation group in the specified direction, or null if none
+ * @return The nearest keyboard navigation cluster in the specified direction, or null if none
* can be found
*/
- View keyboardNavigationGroupSearch(
- @KeyboardNavigationGroupType int groupType, View currentGroup, int direction);
+ View keyboardNavigationClusterSearch(View currentCluster, int direction);
/**
* Change the z order of the child so it's on top of all other children.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c0f2c37..3cbe82e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,8 +16,6 @@
package android.view;
-import static android.view.View.KEYBOARD_NAVIGATION_GROUP_CLUSTER;
-import static android.view.View.KEYBOARD_NAVIGATION_GROUP_SECTION;
import static android.view.WindowCallbacks.RESIZE_MODE_DOCKED_DIVIDER;
import static android.view.WindowCallbacks.RESIZE_MODE_FREEFORM;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
@@ -73,7 +71,6 @@
import android.util.TypedValue;
import android.view.Surface.OutOfResourcesException;
import android.view.View.AttachInfo;
-import android.view.View.KeyboardNavigationGroupType;
import android.view.View.MeasureSpec;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
@@ -4397,14 +4394,13 @@
return false;
}
- private boolean performKeyboardGroupNavigation(
- @KeyboardNavigationGroupType int groupType, int direction) {
+ private boolean performKeyboardGroupNavigation(int direction) {
final View focused = mView.findFocus();
- final View group = focused != null
- ? focused.keyboardNavigationGroupSearch(groupType, null, direction)
- : keyboardNavigationGroupSearch(groupType, null, direction);
+ final View cluster = focused != null
+ ? focused.keyboardNavigationClusterSearch(null, direction)
+ : keyboardNavigationClusterSearch(null, direction);
- if (group != null && group.restoreDefaultFocus(View.FOCUS_DOWN)) {
+ if (cluster != null && cluster.restoreDefaultFocus(View.FOCUS_DOWN)) {
return true;
}
@@ -4424,32 +4420,15 @@
}
int groupNavigationDirection = 0;
- @KeyboardNavigationGroupType int groupType = 0;
if (event.getAction() == KeyEvent.ACTION_DOWN && event.isCtrlPressed()) {
final int character =
event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_CTRL_MASK);
if (character == '+') {
- groupType = KEYBOARD_NAVIGATION_GROUP_CLUSTER;
groupNavigationDirection = View.FOCUS_FORWARD;
}
if (character == '_') {
- groupType = KEYBOARD_NAVIGATION_GROUP_CLUSTER;
- groupNavigationDirection = View.FOCUS_BACKWARD;
- }
- }
-
- if (event.getAction() == KeyEvent.ACTION_DOWN && event.isAltPressed()) {
- final int character =
- event.getUnicodeChar(event.getMetaState() & ~KeyEvent.META_ALT_MASK);
- if (character == '+') {
- groupType = KEYBOARD_NAVIGATION_GROUP_SECTION;
- groupNavigationDirection = View.FOCUS_FORWARD;
- }
-
- if (character == '_') {
- groupType = KEYBOARD_NAVIGATION_GROUP_SECTION;
groupNavigationDirection = View.FOCUS_BACKWARD;
}
}
@@ -4479,7 +4458,7 @@
// Handle automatic focus changes.
if (event.getAction() == KeyEvent.ACTION_DOWN) {
if (groupNavigationDirection != 0) {
- if (performKeyboardGroupNavigation(groupType, groupNavigationDirection)) {
+ if (performKeyboardGroupNavigation(groupNavigationDirection)) {
return FINISH_HANDLED;
}
} else {
@@ -5910,11 +5889,10 @@
* {@inheritDoc}
*/
@Override
- public View keyboardNavigationGroupSearch(
- @KeyboardNavigationGroupType int groupType, View currentGroup, int direction) {
+ public View keyboardNavigationClusterSearch(View currentCluster, int direction) {
checkThread();
- return FocusFinder.getInstance().findNextKeyboardNavigationGroup(groupType,
- mView, currentGroup, direction);
+ return FocusFinder.getInstance().findNextKeyboardNavigationCluster(
+ mView, currentCluster, direction);
}
public void debug() {
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 716997f..c08cd72 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -1080,22 +1080,6 @@
return enabledSubtypes;
}
- // At the initial boot, the settings for input methods are not set,
- // so we need to enable IME in that case.
- public void enableAllIMEsIfThereIsNoEnabledIME() {
- if (TextUtils.isEmpty(getEnabledInputMethodsStr())) {
- StringBuilder sb = new StringBuilder();
- final int N = mMethodList.size();
- for (int i = 0; i < N; i++) {
- InputMethodInfo imi = mMethodList.get(i);
- Slog.i(TAG, "Adding: " + imi.getId());
- if (i > 0) sb.append(':');
- sb.append(imi.getId());
- }
- putEnabledInputMethodsStr(sb.toString());
- }
- }
-
public List<Pair<String, ArrayList<String>>> getEnabledInputMethodsAndSubtypeListLocked() {
return buildInputMethodsAndSubtypeList(getEnabledInputMethodsStr(),
mInputMethodSplitter,
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index a29882b4..ece5540 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1314,7 +1314,7 @@
}
private boolean isDoNotAskCredentialsOnBootSet() {
- return mDevicePolicyManager.getDoNotAskCredentialsOnBoot();
+ return getDevicePolicyManager().getDoNotAskCredentialsOnBoot();
}
private boolean shouldEncryptWithCredentials(boolean defaultValue) {
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 9ce5670..c49287c 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -63,97 +63,87 @@
get_canvas(canvasHandle)->setBitmap(bitmap);
}
-static jboolean isOpaque(JNIEnv*, jobject, jlong canvasHandle) {
+static jboolean isOpaque(jlong canvasHandle) {
return get_canvas(canvasHandle)->isOpaque() ? JNI_TRUE : JNI_FALSE;
}
-static jint getWidth(JNIEnv*, jobject, jlong canvasHandle) {
+static jint getWidth(jlong canvasHandle) {
return static_cast<jint>(get_canvas(canvasHandle)->width());
}
-static jint getHeight(JNIEnv*, jobject, jlong canvasHandle) {
+static jint getHeight(jlong canvasHandle) {
return static_cast<jint>(get_canvas(canvasHandle)->height());
}
-static void setHighContrastText(JNIEnv*, jobject, jlong canvasHandle, jboolean highContrastText) {
+static void setHighContrastText(jlong canvasHandle, jboolean highContrastText) {
Canvas* canvas = get_canvas(canvasHandle);
canvas->setHighContrastText(highContrastText);
}
-static jint getSaveCount(JNIEnv*, jobject, jlong canvasHandle) {
- return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
-}
-
-static jint save(JNIEnv*, jobject, jlong canvasHandle, jint flagsHandle) {
+static jint save(jlong canvasHandle, jint flagsHandle) {
SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
return static_cast<jint>(get_canvas(canvasHandle)->save(flags));
}
-static jint saveLayer(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
+static jint saveLayer(jlong canvasHandle, jfloat l, jfloat t,
jfloat r, jfloat b, jlong paintHandle, jint flagsHandle) {
Paint* paint = reinterpret_cast<Paint*>(paintHandle);
SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
return static_cast<jint>(get_canvas(canvasHandle)->saveLayer(l, t, r, b, paint, flags));
}
-static jint saveLayerAlpha(JNIEnv* env, jobject, jlong canvasHandle, jfloat l, jfloat t,
+static jint saveLayerAlpha(jlong canvasHandle, jfloat l, jfloat t,
jfloat r, jfloat b, jint alpha, jint flagsHandle) {
SaveFlags::Flags flags = static_cast<SaveFlags::Flags>(flagsHandle);
return static_cast<jint>(get_canvas(canvasHandle)->saveLayerAlpha(l, t, r, b, alpha, flags));
}
-static void restore(JNIEnv* env, jobject, jlong canvasHandle, jboolean throwOnUnderflow) {
+static bool restore(jlong canvasHandle) {
Canvas* canvas = get_canvas(canvasHandle);
- if (canvas->getSaveCount() <= 1) { // cannot restore anymore
- if (throwOnUnderflow) {
- doThrowISE(env, "Underflow in restore - more restores than saves");
- }
- return; // compat behavior - return without throwing
+ if (canvas->getSaveCount() <= 1) {
+ return false; // cannot restore anymore
}
canvas->restore();
+ return true; // success
}
-static void restoreToCount(JNIEnv* env, jobject, jlong canvasHandle, jint restoreCount,
- jboolean throwOnUnderflow) {
+static void restoreToCount(jlong canvasHandle, jint saveCount) {
Canvas* canvas = get_canvas(canvasHandle);
- if (restoreCount < 1 || restoreCount > canvas->getSaveCount()) {
- if (throwOnUnderflow) {
- doThrowIAE(env, "Underflow in restoreToCount - more restores than saves");
- return;
- }
- restoreCount = 1; // compat behavior - restore as far as possible
- }
- canvas->restoreToCount(restoreCount);
+ canvas->restoreToCount(saveCount);
}
-static void getCTM(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
+static jint getSaveCount(jlong canvasHandle) {
+ return static_cast<jint>(get_canvas(canvasHandle)->getSaveCount());
+}
+
+static void getMatrix(jlong canvasHandle, jlong matrixHandle) {
SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
get_canvas(canvasHandle)->getMatrix(matrix);
}
-static void setMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
+static void setMatrix(jlong canvasHandle, jlong matrixHandle) {
const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
get_canvas(canvasHandle)->setMatrix(matrix ? *matrix : SkMatrix::I());
}
-static void concat(JNIEnv* env, jobject, jlong canvasHandle, jlong matrixHandle) {
+static void concat(jlong canvasHandle, jlong matrixHandle) {
const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
get_canvas(canvasHandle)->concat(*matrix);
}
-static void rotate(JNIEnv*, jobject, jlong canvasHandle, jfloat degrees) {
+static void rotate(jlong canvasHandle, jfloat degrees) {
get_canvas(canvasHandle)->rotate(degrees);
}
-static void scale(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
+static void scale(jlong canvasHandle, jfloat sx, jfloat sy) {
get_canvas(canvasHandle)->scale(sx, sy);
}
-static void skew(JNIEnv*, jobject, jlong canvasHandle, jfloat sx, jfloat sy) {
+static void skew(jlong canvasHandle, jfloat sx, jfloat sy) {
get_canvas(canvasHandle)->skew(sx, sy);
}
-static void translate(JNIEnv*, jobject, jlong canvasHandle, jfloat dx, jfloat dy) {
+static void translate(jlong canvasHandle, jfloat dx, jfloat dy) {
get_canvas(canvasHandle)->translate(dx, dy);
}
@@ -171,13 +161,13 @@
return result ? JNI_TRUE : JNI_FALSE;
}
-static jboolean quickRejectRect(JNIEnv* env, jobject, jlong canvasHandle,
+static jboolean quickRejectRect(jlong canvasHandle,
jfloat left, jfloat top, jfloat right, jfloat bottom) {
bool result = get_canvas(canvasHandle)->quickRejectRect(left, top, right, bottom);
return result ? JNI_TRUE : JNI_FALSE;
}
-static jboolean quickRejectPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle) {
+static jboolean quickRejectPath(jlong canvasHandle, jlong pathHandle) {
SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
bool result = get_canvas(canvasHandle)->quickRejectPath(*path);
return result ? JNI_TRUE : JNI_FALSE;
@@ -205,14 +195,14 @@
return static_cast<SkClipOp>(rgnOp);
}
-static jboolean clipRect(JNIEnv*, jobject, jlong canvasHandle, jfloat l, jfloat t,
+static jboolean clipRect(jlong canvasHandle, jfloat l, jfloat t,
jfloat r, jfloat b, jint opHandle) {
bool nonEmptyClip = get_canvas(canvasHandle)->clipRect(l, t, r, b,
opHandleToClipOp(opHandle));
return nonEmptyClip ? JNI_TRUE : JNI_FALSE;
}
-static jboolean clipPath(JNIEnv* env, jobject, jlong canvasHandle, jlong pathHandle,
+static jboolean clipPath(jlong canvasHandle, jlong pathHandle,
jint opHandle) {
SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
bool nonEmptyClip = get_canvas(canvasHandle)->clipPath(path, opHandleToClipOp(opHandle));
@@ -565,7 +555,7 @@
env->ReleaseStringChars(text, jchars);
}
-static void setDrawFilter(JNIEnv* env, jobject, jlong canvasHandle, jlong filterHandle) {
+static void setDrawFilter(jlong canvasHandle, jlong filterHandle) {
get_canvas(canvasHandle)->setDrawFilter(reinterpret_cast<SkDrawFilter*>(filterHandle));
}
@@ -587,6 +577,9 @@
// ------------ @FastNative ----------------
{"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
+ {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
+
+ // ------------ @CriticalNative ----------------
{"nIsOpaque","(J)Z", (void*) CanvasJNI::isOpaque},
{"nGetWidth","(J)I", (void*) CanvasJNI::getWidth},
{"nGetHeight","(J)I", (void*) CanvasJNI::getHeight},
@@ -595,16 +588,15 @@
{"nSaveLayer","(JFFFFJI)I", (void*) CanvasJNI::saveLayer},
{"nSaveLayerAlpha","(JFFFFII)I", (void*) CanvasJNI::saveLayerAlpha},
{"nGetSaveCount","(J)I", (void*) CanvasJNI::getSaveCount},
- {"nRestore","(JZ)V", (void*) CanvasJNI::restore},
- {"nRestoreToCount","(JIZ)V", (void*) CanvasJNI::restoreToCount},
- {"nGetCTM", "(JJ)V", (void*)CanvasJNI::getCTM},
+ {"nRestore","(J)Z", (void*) CanvasJNI::restore},
+ {"nRestoreToCount","(JI)V", (void*) CanvasJNI::restoreToCount},
+ {"nGetMatrix", "(JJ)V", (void*)CanvasJNI::getMatrix},
{"nSetMatrix","(JJ)V", (void*) CanvasJNI::setMatrix},
{"nConcat","(JJ)V", (void*) CanvasJNI::concat},
{"nRotate","(JF)V", (void*) CanvasJNI::rotate},
{"nScale","(JFF)V", (void*) CanvasJNI::scale},
{"nSkew","(JFF)V", (void*) CanvasJNI::skew},
{"nTranslate","(JFF)V", (void*) CanvasJNI::translate},
- {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
{"nQuickReject","(JJ)Z", (void*) CanvasJNI::quickRejectPath},
{"nQuickReject","(JFFFF)Z", (void*)CanvasJNI::quickRejectRect},
{"nClipRect","(JFFFFI)Z", (void*) CanvasJNI::clipRect},
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 87c2b25..df7a5f5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2896,9 +2896,7 @@
See {@link android.view.View#setKeyboardNavigationCluster(boolean)}. -->
<attr name="keyboardNavigationCluster" format="boolean" />
- <!-- Whether this view is a root of a keyboard navigation section.
- See {@link android.view.View#setKeyboardNavigationSection(boolean)}. -->
- <attr name="keyboardNavigationSection" format="boolean" />
+ <attr name="__removed0" format="boolean" />
<!-- Defines the next keyboard navigation cluster.
@@ -2907,12 +2905,7 @@
will result when the reference is accessed.-->
<attr name="nextClusterForward" format="reference"/>
- <!-- Defines the next keyboard navigation section.
-
- If the reference refers to a view that does not exist or is part
- of a hierarchy that is invisible, a {@link java.lang.RuntimeException}
- will result when the reference is accessed.-->
- <attr name="nextSectionForward" format="reference"/>
+ <attr name="__removed1" format="reference"/>
<!-- Whether this view is a default-focus view.
Only one view per keyboard navigation cluster can have this attribute set to true.
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 060c59e..40d0e45 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2777,9 +2777,9 @@
<public name="paddingVertical" />
<public name="visibleToInstantApps" />
<public name="keyboardNavigationCluster" />
- <public name="keyboardNavigationSection" />
+ <public name="__removed0" />
<public name="nextClusterForward" />
- <public name="nextSectionForward" />
+ <public name="__removed1" />
<public name="textColorError" />
<public name="focusedByDefault" />
<public name="appCategory" />
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index cc5cc7b..8572345 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -21,11 +21,8 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Size;
-import android.text.GraphicsOperations;
-import android.text.SpannableString;
-import android.text.SpannedString;
-import android.text.TextUtils;
+import dalvik.annotation.optimization.CriticalNative;
import dalvik.annotation.optimization.FastNative;
import libcore.util.NativeAllocationRegistry;
@@ -501,8 +498,10 @@
* an error to call restore() more times than save() was called.
*/
public void restore() {
- boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated();
- nRestore(mNativeCanvasWrapper, throwOnUnderflow);
+ if (!nRestore(mNativeCanvasWrapper)
+ && (!sCompatibilityRestore || !isHardwareAccelerated())) {
+ throw new IllegalStateException("Underflow in restore - more restores than saves");
+ }
}
/**
@@ -527,8 +526,16 @@
* @param saveCount The save level to restore to.
*/
public void restoreToCount(int saveCount) {
- boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated();
- nRestoreToCount(mNativeCanvasWrapper, saveCount, throwOnUnderflow);
+ if (saveCount < 1) {
+ if (!sCompatibilityRestore || !isHardwareAccelerated()) {
+ // do nothing and throw without restoring
+ throw new IllegalArgumentException(
+ "Underflow in restoreToCount - more restores than saves");
+ }
+ // compat behavior - restore as far as possible
+ saveCount = 1;
+ }
+ nRestoreToCount(mNativeCanvasWrapper, saveCount);
}
/**
@@ -643,7 +650,7 @@
*/
@Deprecated
public void getMatrix(@NonNull Matrix ctm) {
- nGetCTM(mNativeCanvasWrapper, ctm.native_instance);
+ nGetMatrix(mNativeCanvasWrapper, ctm.native_instance);
}
/**
@@ -1059,79 +1066,66 @@
// ---------------- @FastNative -------------------
@FastNative
- private static native void nSetBitmap(long canvasHandle,
- Bitmap bitmap);
+ private static native void nSetBitmap(long canvasHandle, Bitmap bitmap);
+
@FastNative
+ private static native boolean nGetClipBounds(long nativeCanvas, Rect bounds);
+
+ // ---------------- @CriticalNative -------------------
+
+ @CriticalNative
private static native boolean nIsOpaque(long canvasHandle);
- @FastNative
+ @CriticalNative
private static native void nSetHighContrastText(long renderer, boolean highContrastText);
- @FastNative
+ @CriticalNative
private static native int nGetWidth(long canvasHandle);
- @FastNative
+ @CriticalNative
private static native int nGetHeight(long canvasHandle);
- @FastNative
+ @CriticalNative
private static native int nSave(long canvasHandle, int saveFlags);
- @FastNative
- private static native int nSaveLayer(long nativeCanvas, float l,
- float t, float r, float b,
- long nativePaint,
- int layerFlags);
- @FastNative
- private static native int nSaveLayerAlpha(long nativeCanvas, float l,
- float t, float r, float b,
- int alpha, int layerFlags);
- @FastNative
- private static native void nRestore(long canvasHandle, boolean tolerateUnderflow);
- @FastNative
- private static native void nRestoreToCount(long canvasHandle,
- int saveCount,
- boolean tolerateUnderflow);
- @FastNative
+ @CriticalNative
+ private static native int nSaveLayer(long nativeCanvas, float l, float t, float r, float b,
+ long nativePaint, int layerFlags);
+ @CriticalNative
+ private static native int nSaveLayerAlpha(long nativeCanvas, float l, float t, float r, float b,
+ int alpha, int layerFlags);
+ @CriticalNative
+ private static native boolean nRestore(long canvasHandle);
+ @CriticalNative
+ private static native void nRestoreToCount(long canvasHandle, int saveCount);
+ @CriticalNative
private static native int nGetSaveCount(long canvasHandle);
- @FastNative
- private static native void nTranslate(long canvasHandle,
- float dx, float dy);
- @FastNative
- private static native void nScale(long canvasHandle,
- float sx, float sy);
- @FastNative
+ @CriticalNative
+ private static native void nTranslate(long canvasHandle, float dx, float dy);
+ @CriticalNative
+ private static native void nScale(long canvasHandle, float sx, float sy);
+ @CriticalNative
private static native void nRotate(long canvasHandle, float degrees);
- @FastNative
- private static native void nSkew(long canvasHandle,
- float sx, float sy);
- @FastNative
- private static native void nConcat(long nativeCanvas,
- long nativeMatrix);
- @FastNative
- private static native void nSetMatrix(long nativeCanvas,
- long nativeMatrix);
- @FastNative
+ @CriticalNative
+ private static native void nSkew(long canvasHandle, float sx, float sy);
+ @CriticalNative
+ private static native void nConcat(long nativeCanvas, long nativeMatrix);
+ @CriticalNative
+ private static native void nSetMatrix(long nativeCanvas, long nativeMatrix);
+ @CriticalNative
private static native boolean nClipRect(long nativeCanvas,
- float left, float top,
- float right, float bottom,
- int regionOp);
- @FastNative
- private static native boolean nClipPath(long nativeCanvas,
- long nativePath,
- int regionOp);
- @FastNative
- private static native void nSetDrawFilter(long nativeCanvas,
- long nativeFilter);
- @FastNative
- private static native boolean nGetClipBounds(long nativeCanvas,
- Rect bounds);
- @FastNative
- private static native void nGetCTM(long nativeCanvas,
- long nativeMatrix);
- @FastNative
- private static native boolean nQuickReject(long nativeCanvas,
- long nativePath);
- @FastNative
- private static native boolean nQuickReject(long nativeCanvas,
- float left, float top,
- float right, float bottom);
+ float left, float top, float right, float bottom, int regionOp);
+ @CriticalNative
+ private static native boolean nClipPath(long nativeCanvas, long nativePath, int regionOp);
+ @CriticalNative
+ private static native void nSetDrawFilter(long nativeCanvas, long nativeFilter);
+ @CriticalNative
+ private static native void nGetMatrix(long nativeCanvas, long nativeMatrix);
+ @CriticalNative
+ private static native boolean nQuickReject(long nativeCanvas, long nativePath);
+ @CriticalNative
+ private static native boolean nQuickReject(long nativeCanvas, float left, float top,
+ float right, float bottom);
+
+
+ // ---------------- Draw Methods -------------------
/**
* <p>
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 6f3ed9c..5a2791c 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -311,13 +311,32 @@
TestUtils::syncHierarchyPropertiesAndDisplayList(node);
}
- FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
- sLightGeometry, Caches::getInstance());
- frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
+ {
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
- DeferRenderNodeSceneTestRenderer renderer;
- frameBuilder.replayBakedOps<TestDispatcher>(renderer);
- EXPECT_EQ(4, renderer.getIndex());
+ DeferRenderNodeSceneTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(4, renderer.getIndex());
+ }
+
+ for (auto& node : nodes) {
+ EXPECT_FALSE(node->nothingToDraw());
+ node->setStagingDisplayList(nullptr, nullptr);
+ node->destroyHardwareResources(nullptr);
+ EXPECT_TRUE(node->nothingToDraw());
+ }
+
+ {
+ // Validate no crashes if any nodes are missing DisplayLists
+ FrameBuilder frameBuilder(SkRect::MakeWH(800, 600), 800, 600,
+ sLightGeometry, Caches::getInstance());
+ frameBuilder.deferRenderNodeScene(nodes, contentDrawBounds);
+
+ FailRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ }
}
RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_noFbo0) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index fede34d..f72d091 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -131,6 +131,9 @@
<!-- Assist -->
<uses-permission android:name="android.permission.ACCESS_VOICE_INTERACTION_SERVICE" />
+ <!-- Doze mode temp whitelisting for notification dispatching. -->
+ <uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" />
+
<!-- Listen for keyboard attachment / detachment -->
<uses-permission android:name="android.permission.TABLET_MODE" />
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
index a9d1fa9..152dbc5 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginFragment.java
@@ -14,17 +14,13 @@
package com.android.systemui.plugins;
-import android.annotation.Nullable;
import android.app.Fragment;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.view.LayoutInflater;
public abstract class PluginFragment extends Fragment implements Plugin {
- private static final String KEY_PLUGIN_PACKAGE = "plugin_package_name";
private Context mPluginContext;
@Override
@@ -33,45 +29,17 @@
}
@Override
- public void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- if (savedInstanceState != null) {
- Context sysuiContext = getContext();
- Context pluginContext = recreatePluginContext(sysuiContext, savedInstanceState);
- onCreate(sysuiContext, pluginContext);
- }
- if (mPluginContext == null) {
- throw new RuntimeException("PluginFragments must call super.onCreate("
- + "Context sysuiContext, Context pluginContext)");
- }
+ public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
+ return super.getLayoutInflater(savedInstanceState).cloneInContext(getContext());
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
- outState.putString(KEY_PLUGIN_PACKAGE, getContext().getPackageName());
}
- private Context recreatePluginContext(Context sysuiContext, Bundle savedInstanceState) {
- final String pkg = savedInstanceState.getString(KEY_PLUGIN_PACKAGE);
- try {
- ApplicationInfo appInfo = sysuiContext.getPackageManager().getApplicationInfo(pkg, 0);
- return PluginManager.getInstance(sysuiContext).getContext(appInfo, pkg);
- } catch (NameNotFoundException e) {
- throw new RuntimeException("Plugin with invalid package? " + pkg, e);
- }
- }
-
- @Override
- public LayoutInflater getLayoutInflater(Bundle savedInstanceState) {
- return super.getLayoutInflater(savedInstanceState).cloneInContext(mPluginContext);
- }
-
- /**
- * Should only be called after {@link Plugin#onCreate(Context, Context)}.
- */
@Override
public Context getContext() {
- return mPluginContext != null ? mPluginContext : super.getContext();
+ return mPluginContext;
}
}
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
index 47b97bd..9f44bd4 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginInstanceManager.java
@@ -177,8 +177,12 @@
if (DEBUG) Log.d(TAG, "onPluginConnected");
PluginPrefs.setHasPlugins(mContext);
PluginInfo<T> info = (PluginInfo<T>) msg.obj;
- info.mPlugin.onCreate(mContext, info.mPluginContext);
- mListener.onPluginConnected(info.mPlugin);
+ if (!(msg.obj instanceof PluginFragment)) {
+ // Only call onDestroy for plugins that aren't fragments, as fragments
+ // will get the onCreate as part of the fragment lifecycle.
+ info.mPlugin.onCreate(mContext, info.mPluginContext);
+ }
+ mListener.onPluginConnected(info.mPlugin, info.mPluginContext);
break;
case PLUGIN_DISCONNECTED:
if (DEBUG) Log.d(TAG, "onPluginDisconnected");
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java
index b2f92d6..b488d2a 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/PluginListener.java
@@ -14,6 +14,8 @@
package com.android.systemui.plugins;
+import android.content.Context;
+
/**
* Interface for listening to plugins being connected.
*/
@@ -24,7 +26,7 @@
* It may also be called in the future if the plugin package changes
* and needs to be reloaded.
*/
- void onPluginConnected(T plugin);
+ void onPluginConnected(T plugin, Context pluginContext);
/**
* Called when a plugin has been uninstalled/updated and should be removed
diff --git a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
index efa7cae..efddf20 100644
--- a/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/PluginInflateContainer.java
@@ -98,7 +98,7 @@
}
@Override
- public void onPluginConnected(ViewProvider plugin) {
+ public void onPluginConnected(ViewProvider plugin, Context context) {
mPluginView = plugin.getView();
inflateLayout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index f83a5d3..f2aaec1 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -207,7 +207,7 @@
PluginManager.getInstance(this).addPluginListener(OverlayPlugin.ACTION,
new PluginListener<OverlayPlugin>() {
@Override
- public void onPluginConnected(OverlayPlugin plugin) {
+ public void onPluginConnected(OverlayPlugin plugin, Context pluginContext) {
PhoneStatusBar phoneStatusBar = getComponent(PhoneStatusBar.class);
if (phoneStatusBar != null) {
plugin.setup(phoneStatusBar.getStatusBarWindow(),
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 57857cc..50506a9 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -27,11 +27,13 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Parcelable;
+import android.util.ArrayMap;
import android.view.LayoutInflater;
import android.view.View;
import com.android.settingslib.applications.InterestingConfigChanges;
import com.android.systemui.SystemUIApplication;
+import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginManager;
import java.io.FileDescriptor;
@@ -47,6 +49,7 @@
private final View mRootView;
private final InterestingConfigChanges mConfigChanges = new InterestingConfigChanges();
private final FragmentService mManager;
+ private final PluginFragmentManager mPlugins = new PluginFragmentManager();
private FragmentController mFragments;
private FragmentLifecycleCallbacks mLifecycleCallbacks;
@@ -163,6 +166,10 @@
return mFragments.getFragmentManager();
}
+ PluginFragmentManager getPluginManager() {
+ return mPlugins;
+ }
+
public interface FragmentListener {
void onFragmentViewCreated(String tag, Fragment fragment);
@@ -198,6 +205,11 @@
}
@Override
+ public Fragment instantiate(Context context, String className, Bundle arguments) {
+ return mPlugins.instantiate(context, className, arguments);
+ }
+
+ @Override
public boolean onShouldSaveFragmentState(Fragment fragment) {
return true; // True for now.
}
@@ -237,4 +249,57 @@
return true;
}
}
+
+ class PluginFragmentManager {
+ private final ArrayMap<String, Context> mPluginLookup = new ArrayMap<>();
+
+ public void removePlugin(String tag, String currentClass, String defaultClass) {
+ Fragment fragment = getFragmentManager().findFragmentByTag(tag);
+ mPluginLookup.remove(currentClass);
+ getFragmentManager().beginTransaction()
+ .replace(((View) fragment.getView().getParent()).getId(),
+ instantiate(mContext, defaultClass, null), tag)
+ .commit();
+ reloadFragments();
+ }
+
+ public void setCurrentPlugin(String tag, String currentClass, Context context) {
+ Fragment fragment = getFragmentManager().findFragmentByTag(tag);
+ mPluginLookup.put(currentClass, context);
+ getFragmentManager().beginTransaction()
+ .replace(((View) fragment.getView().getParent()).getId(),
+ instantiate(context, currentClass, null), tag)
+ .commit();
+ reloadFragments();
+ }
+
+ private void reloadFragments() {
+ // Save the old state.
+ Parcelable p = destroyFragmentHost();
+ // Generate a new fragment host and restore its state.
+ createFragmentHost(p);
+ }
+
+ Fragment instantiate(Context context, String className, Bundle arguments) {
+ Context pluginContext = mPluginLookup.get(className);
+ if (pluginContext != null) {
+ Fragment f = Fragment.instantiate(pluginContext, className, arguments);
+ if (f instanceof Plugin) {
+ ((Plugin) f).onCreate(mContext, pluginContext);
+ }
+ return f;
+ }
+ return Fragment.instantiate(context, className, arguments);
+ }
+ }
+
+ private static class PluginState {
+ Context mContext;
+ String mCls;
+
+ private PluginState(String cls, Context context) {
+ mCls = cls;
+ mContext = context;
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
index e107fcd..2e6de4a 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/PluginFragmentListener.java
@@ -15,6 +15,7 @@
package com.android.systemui.fragments;
import android.app.Fragment;
+import android.content.Context;
import android.util.Log;
import android.view.View;
@@ -30,27 +31,19 @@
private final FragmentHostManager mFragmentHostManager;
private final PluginManager mPluginManager;
private final Class<? extends Fragment> mDefaultClass;
- private final int mId;
- private final String mTag;
private final Class<? extends FragmentBase> mExpectedInterface;
+ private final String mTag;
- public PluginFragmentListener(View view, String tag, int id,
- Class<? extends Fragment> defaultFragment,
+ public PluginFragmentListener(View view, String tag, Class<? extends Fragment> defaultFragment,
Class<? extends FragmentBase> expectedInterface) {
+ mTag = tag;
mFragmentHostManager = FragmentHostManager.get(view);
mPluginManager = PluginManager.getInstance(view.getContext());
mExpectedInterface = expectedInterface;
- mTag = tag;
mDefaultClass = defaultFragment;
- mId = id;
}
public void startListening(String action, int version) {
- try {
- setFragment(mDefaultClass.newInstance());
- } catch (InstantiationException | IllegalAccessException e) {
- Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e);
- }
mPluginManager.addPluginListener(action, this, version, false /* Only allow one */);
}
@@ -58,17 +51,13 @@
mPluginManager.removePluginListener(this);
}
- private void setFragment(Fragment fragment) {
- mFragmentHostManager.getFragmentManager().beginTransaction()
- .replace(mId, fragment, mTag)
- .commit();
- }
-
@Override
- public void onPluginConnected(Plugin plugin) {
+ public void onPluginConnected(Plugin plugin, Context pluginContext) {
try {
mExpectedInterface.cast(plugin);
- setFragment((Fragment) plugin);
+ Fragment.class.cast(plugin);
+ mFragmentHostManager.getPluginManager().setCurrentPlugin(mTag,
+ plugin.getClass().getName(), pluginContext);
} catch (ClassCastException e) {
Log.e(TAG, plugin.getClass().getName() + " must be a Fragment and implement "
+ mExpectedInterface.getName(), e);
@@ -77,10 +66,7 @@
@Override
public void onPluginDisconnected(Plugin plugin) {
- try {
- setFragment(mDefaultClass.newInstance());
- } catch (InstantiationException | IllegalAccessException e) {
- Log.e(TAG, "Couldn't instantiate " + mDefaultClass.getName(), e);
- }
+ mFragmentHostManager.getPluginManager().removePlugin(mTag,
+ plugin.getClass().getName(), mDefaultClass.getName());
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 93f72a8..f24e40b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -72,6 +72,7 @@
SystemServicesProxy.getInstance(mContext).registerTaskStackListener(mTaskStackListener);
registerPackageChangeReceivers();
+ createBatteryController();
mCarBatteryController.startListening();
mConnectedDeviceSignalController.startListening();
}
@@ -113,8 +114,7 @@
return statusBarView;
}
- @Override
- protected BatteryController createBatteryController() {
+ private BatteryController createBatteryController() {
mCarBatteryController = new CarBatteryController(mContext);
mCarBatteryController.addBatteryViewHandler(this);
return mCarBatteryController;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index d326787..79120d8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -779,7 +779,7 @@
private final PluginListener<IntentButtonProvider> mRightListener =
new PluginListener<IntentButtonProvider>() {
@Override
- public void onPluginConnected(IntentButtonProvider plugin) {
+ public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
setRightButton(plugin.getIntentButton());
}
@@ -792,7 +792,7 @@
private final PluginListener<IntentButtonProvider> mLeftListener =
new PluginListener<IntentButtonProvider>() {
@Override
- public void onPluginConnected(IntentButtonProvider plugin) {
+ public void onPluginConnected(IntentButtonProvider plugin, Context pluginContext) {
setLeftButton(plugin.getIntentButton());
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index b6feb0e..f04a9ee 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -365,7 +365,7 @@
}
@Override
- public void onPluginConnected(NavBarButtonProvider plugin) {
+ public void onPluginConnected(NavBarButtonProvider plugin, Context context) {
mPlugins.add(plugin);
clearViews();
inflateLayout(mCurrentLayout);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 31c78c8f..319f124 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -765,7 +765,7 @@
}
@Override
- public void onPluginConnected(NavGesture plugin) {
+ public void onPluginConnected(NavGesture plugin, Context context) {
mGestureHelper = plugin.getGestureHelper();
updateTaskSwitchHelper();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index cb9fbb9..3291d59 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -870,7 +870,10 @@
View container = mStatusBarWindow.findViewById(R.id.qs_frame);
if (container != null) {
FragmentHostManager fragmentHostManager = FragmentHostManager.get(container);
- new PluginFragmentListener(container, QS.TAG, R.id.qs_frame, QSFragment.class, QS.class)
+ fragmentHostManager.getFragmentManager().beginTransaction()
+ .replace(R.id.qs_frame, new QSFragment(), QS.TAG)
+ .commit();
+ new PluginFragmentListener(container, QS.TAG, QSFragment.class, QS.class)
.startListening(QS.ACTION, QS.VERSION);
final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
mIconController);
@@ -986,10 +989,6 @@
}
}
- protected BatteryController createBatteryController() {
- return new BatteryControllerImpl(mContext);
- }
-
private void inflateShelf() {
mNotificationShelf =
(NotificationShelf) LayoutInflater.from(mContext).inflate(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
index d529ee1..3715df2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/plugins/PluginInstanceManagerTest.java
@@ -113,8 +113,7 @@
waitForIdleSync(mPluginInstanceManager.mPluginHandler);
waitForIdleSync(mPluginInstanceManager.mMainHandler);
- verify(mMockListener, Mockito.never()).onPluginConnected(
- ArgumentCaptor.forClass(Plugin.class).capture());
+ verify(mMockListener, Mockito.never()).onPluginConnected(any(), any());
}
@Test
@@ -124,7 +123,7 @@
// Verify startup lifecycle
verify(sMockPlugin).onCreate(ArgumentCaptor.forClass(Context.class).capture(),
ArgumentCaptor.forClass(Context.class).capture());
- verify(mMockListener).onPluginConnected(ArgumentCaptor.forClass(Plugin.class).capture());
+ verify(mMockListener).onPluginConnected(any(), any());
}
@Test
@@ -154,8 +153,7 @@
waitForIdleSync(mPluginInstanceManager.mMainHandler);
// Plugin shouldn't be connected because it is the wrong version.
- verify(mMockListener, Mockito.never()).onPluginConnected(
- ArgumentCaptor.forClass(Plugin.class).capture());
+ verify(mMockListener, Mockito.never()).onPluginConnected(any(), any());
verify(nm).notifyAsUser(eq(TestPlugin.class.getName()), eq(SystemMessage.NOTE_PLUGIN),
any(), eq(UserHandle.ALL));
}
@@ -176,8 +174,7 @@
verify(sMockPlugin, Mockito.times(2)).onCreate(
ArgumentCaptor.forClass(Context.class).capture(),
ArgumentCaptor.forClass(Context.class).capture());
- verify(mMockListener, Mockito.times(2)).onPluginConnected(
- ArgumentCaptor.forClass(Plugin.class).capture());
+ verify(mMockListener, Mockito.times(2)).onPluginConnected(any(), any());
}
@Test
@@ -193,8 +190,7 @@
waitForIdleSync(mPluginInstanceManager.mMainHandler);;
// Non-debuggable build should receive no plugins.
- verify(mMockListener, Mockito.never()).onPluginConnected(
- ArgumentCaptor.forClass(Plugin.class).capture());
+ verify(mMockListener, Mockito.never()).onPluginConnected(any(), any());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java
new file mode 100644
index 0000000..d82566f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.keyguard.KeyguardHostView.OnDismissAction;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.BaseStatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PhoneStatusBarTest extends SysuiTestCase {
+
+ StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
+ PhoneStatusBar mPhoneStatusBar;
+
+ @Before
+ public void setup() {
+ mStatusBarKeyguardViewManager = mock(StatusBarKeyguardViewManager.class);
+ mPhoneStatusBar = new TestablePhoneStatusBar(mStatusBarKeyguardViewManager);
+
+ doAnswer(invocation -> {
+ OnDismissAction onDismissAction = (OnDismissAction) invocation.getArguments()[0];
+ onDismissAction.onDismiss();
+ return null;
+ }).when(mStatusBarKeyguardViewManager).dismissWithAction(any(), any(), anyBoolean());
+
+ doAnswer(invocation -> {
+ Runnable runnable = (Runnable) invocation.getArguments()[0];
+ runnable.run();
+ return null;
+ }).when(mStatusBarKeyguardViewManager).addAfterKeyguardGoneRunnable(any());
+ }
+
+ @Test
+ public void executeRunnableDismissingKeyguard_nullRunnable_showingAndOccluded() {
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(true);
+
+ mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+ }
+
+ @Test
+ public void executeRunnableDismissingKeyguard_nullRunnable_showing() {
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(true);
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+
+ mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+ }
+
+ @Test
+ public void executeRunnableDismissingKeyguard_nullRunnable_notShowing() {
+ when(mStatusBarKeyguardViewManager.isShowing()).thenReturn(false);
+ when(mStatusBarKeyguardViewManager.isOccluded()).thenReturn(false);
+
+ mPhoneStatusBar.executeRunnableDismissingKeyguard(null, null, false, false, false);
+ }
+
+ static class TestablePhoneStatusBar extends PhoneStatusBar {
+ public TestablePhoneStatusBar(StatusBarKeyguardViewManager man) {
+ mStatusBarKeyguardViewManager = man;
+ }
+
+ @Override
+ protected BaseStatusBar.H createHandler() {
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 581aa05d..0e07ec0 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -504,8 +504,8 @@
for (int i = alarms.size()-1; i >= 0; i--) {
Alarm alarm = alarms.get(i);
try {
- if (alarm.uid == uid && ActivityManager.getService().getAppStartMode(
- uid, alarm.packageName) == ActivityManager.APP_START_MODE_DISABLED) {
+ if (alarm.uid == uid && ActivityManager.getService().isAppStartModeDisabled(
+ uid, alarm.packageName)) {
alarms.remove(i);
didRemove = true;
if (alarm.alarmClock != null) {
@@ -1089,8 +1089,7 @@
operation, directReceiver, listenerTag, workSource, flags, alarmClock,
callingUid, callingPackage);
try {
- if (ActivityManager.getService().getAppStartMode(callingUid, callingPackage)
- == ActivityManager.APP_START_MODE_DISABLED) {
+ if (ActivityManager.getService().isAppStartModeDisabled(callingUid, callingPackage)) {
Slog.w(TAG, "Not setting alarm from " + callingUid + ":" + a
+ " -- package not allowed to start");
return;
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index f718fa1..bee1f97 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -243,7 +243,6 @@
private PendingIntent mImeSwitchPendingIntent;
private boolean mShowOngoingImeSwitcherForPhones;
private boolean mNotificationShown;
- private final boolean mImeSelectedOnBoot;
static class SessionState {
final ClientState client;
@@ -566,7 +565,7 @@
}
}
- class ImmsBroadcastReceiver extends android.content.BroadcastReceiver {
+ class ImmsBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
@@ -587,6 +586,10 @@
Intent.EXTRA_SETTING_NEW_VALUE);
restoreEnabledInputMethods(mContext, prevValue, newValue);
}
+ } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) {
+ synchronized (mMethodMap) {
+ resetStateIfCurrentLocaleChangedLocked();
+ }
} else {
Slog.w(TAG, "Unexpected intent " + intent);
}
@@ -845,9 +848,11 @@
return;
}
mSettings.switchCurrentUser(currentUserId, !mSystemReady);
- // We need to rebuild IMEs.
- buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
- updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+ if (mSystemReady) {
+ // We need to rebuild IMEs.
+ buildInputMethodListLocked(false /* resetDefaultEnabledIme */);
+ updateInputMethodsFromSettingsLocked(true /* enabledChanged */);
+ }
}
}
@@ -897,13 +902,6 @@
mShowOngoingImeSwitcherForPhones = false;
- final IntentFilter broadcastFilter = new IntentFilter();
- broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
- broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
- broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
- broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED);
- mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
-
mNotificationShown = false;
int userId = 0;
try {
@@ -911,7 +909,6 @@
} catch (RemoteException e) {
Slog.w(TAG, "Couldn't get current user ID; guessing it's 0", e);
}
- mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
// mSettings should be created before buildInputMethodListLocked
mSettings = new InputMethodSettings(
@@ -919,48 +916,8 @@
updateCurrentProfileIds();
mFileManager = new InputMethodFileManager(mMethodMap, userId);
- synchronized (mMethodMap) {
- mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
- mSettings, context);
- }
-
- // Just checking if defaultImiId is empty or not
- final String defaultImiId = mSettings.getSelectedInputMethod();
- if (DEBUG) {
- Slog.d(TAG, "Initial default ime = " + defaultImiId);
- }
- mImeSelectedOnBoot = !TextUtils.isEmpty(defaultImiId);
-
- synchronized (mMethodMap) {
- buildInputMethodListLocked(!mImeSelectedOnBoot /* resetDefaultEnabledIme */);
- }
- mSettings.enableAllIMEsIfThereIsNoEnabledIME();
-
- if (!mImeSelectedOnBoot) {
- Slog.w(TAG, "No IME selected. Choose the most applicable IME.");
- synchronized (mMethodMap) {
- resetDefaultImeLocked(context);
- }
- }
-
- synchronized (mMethodMap) {
- mSettingsObserver.registerContentObserverLocked(userId);
- updateFromSettingsLocked(true);
- }
-
- // IMMS wants to receive Intent.ACTION_LOCALE_CHANGED in order to update the current IME
- // according to the new system locale.
- final IntentFilter filter = new IntentFilter();
- filter.addAction(Intent.ACTION_LOCALE_CHANGED);
- mContext.registerReceiver(
- new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- synchronized(mMethodMap) {
- resetStateIfCurrentLocaleChangedLocked();
- }
- }
- }, filter);
+ mSwitchingController = InputMethodSubtypeSwitchingController.createInstanceLocked(
+ mSettings, context);
}
private void resetDefaultImeLocked(Context context) {
@@ -1089,6 +1046,7 @@
}
if (!mSystemReady) {
mSystemReady = true;
+ mLastSystemLocales = mRes.getConfiguration().getLocales();
final int currentUserId = mSettings.getCurrentUserId();
mSettings.switchCurrentUser(currentUserId,
!mUserManager.isUserUnlockingOrUnlocked(currentUserId));
@@ -1105,14 +1063,25 @@
mWindowManagerInternal.setOnHardKeyboardStatusChangeListener(
mHardKeyboardListener);
}
- if (!mImeSelectedOnBoot) {
- Slog.w(TAG, "Reset the default IME as \"Resource\" is ready here.");
- resetStateIfCurrentLocaleChangedLocked();
- InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
- mSettings.getEnabledInputMethodListLocked(),
- mSettings.getCurrentUserId(), mContext.getBasePackageName());
- }
- mLastSystemLocales = mRes.getConfiguration().getLocales();
+
+ mMyPackageMonitor.register(mContext, null, UserHandle.ALL, true);
+ mSettingsObserver.registerContentObserverLocked(currentUserId);
+
+ final IntentFilter broadcastFilter = new IntentFilter();
+ broadcastFilter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+ broadcastFilter.addAction(Intent.ACTION_USER_ADDED);
+ broadcastFilter.addAction(Intent.ACTION_USER_REMOVED);
+ broadcastFilter.addAction(Intent.ACTION_SETTING_RESTORED);
+ broadcastFilter.addAction(Intent.ACTION_LOCALE_CHANGED);
+ mContext.registerReceiver(new ImmsBroadcastReceiver(), broadcastFilter);
+
+ buildInputMethodListLocked(true /* resetDefaultEnabledIme */);
+ resetDefaultImeLocked(mContext);
+ updateFromSettingsLocked(true);
+ InputMethodUtils.setNonSelectedSystemImesDisabledUntilUsed(mIPackageManager,
+ mSettings.getEnabledInputMethodListLocked(), currentUserId,
+ mContext.getBasePackageName());
+
try {
startInputInnerLocked();
} catch (RuntimeException e) {
@@ -2624,6 +2593,9 @@
// additional input method subtypes to the IME.
if (TextUtils.isEmpty(imiId) || subtypes == null) return;
synchronized (mMethodMap) {
+ if (!mSystemReady) {
+ return;
+ }
final InputMethodInfo imi = mMethodMap.get(imiId);
if (imi == null) return;
final String[] packageInfos;
@@ -3048,6 +3020,10 @@
Slog.d(TAG, "--- re-buildInputMethodList reset = " + resetDefaultEnabledIme
+ " \n ------ caller=" + Debug.getCallers(10));
}
+ if (!mSystemReady) {
+ Slog.e(TAG, "buildInputMethodListLocked is not allowed until system is ready");
+ return;
+ }
mMethodList.clear();
mMethodMap.clear();
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 94acd75..e11dd1a 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -33,6 +33,7 @@
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.app.IActivityManager;
+import android.app.usage.StorageStatsManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -3270,6 +3271,29 @@
}
}
+ @Override
+ public long getCacheQuotaBytes(String volumeUuid, int uid) {
+ if (uid != Binder.getCallingUid()) {
+ mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
+ }
+ // TODO: wire up to cache quota once merged
+ return 64 * TrafficStats.MB_IN_BYTES;
+ }
+
+ @Override
+ public long getCacheSizeBytes(String volumeUuid, int uid) {
+ if (uid != Binder.getCallingUid()) {
+ mContext.enforceCallingPermission(android.Manifest.permission.STORAGE_INTERNAL, TAG);
+ }
+ final long token = Binder.clearCallingIdentity();
+ try {
+ return mContext.getSystemService(StorageStatsManager.class)
+ .queryStatsForUid(volumeUuid, uid).getCacheBytes();
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
private void addObbStateLocked(ObbState obbState) throws RemoteException {
final IBinder binder = obbState.getBinder();
List<ObbState> obbStates = mObbMounts.get(binder);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1bba7ec..5655dc5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -349,8 +349,8 @@
try {
// Before going further -- if this app is not allowed to start services in the
// background, then at this point we aren't going to let it period.
- final int allowed = mAm.checkAllowBackgroundLocked(
- r.appInfo.uid, r.packageName, callingPid, false);
+ final int allowed = mAm.getAppStartModeLocked(r.appInfo.uid, r.packageName,
+ r.appInfo.targetSdkVersion, callingPid, false, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
Slog.w(TAG, "Background start not allowed: service "
+ service + " to " + r.name.flattenToShortString()
@@ -607,8 +607,9 @@
for (int i=services.mServicesByName.size()-1; i>=0; i--) {
ServiceRecord service = services.mServicesByName.valueAt(i);
if (service.appInfo.uid == uid && service.startRequested) {
- if (mAm.checkAllowBackgroundLocked(service.appInfo.uid, service.packageName,
- -1, false) != ActivityManager.APP_START_MODE_NORMAL) {
+ if (mAm.getAppStartModeLocked(service.appInfo.uid, service.packageName,
+ service.appInfo.targetSdkVersion, -1, false, false)
+ != ActivityManager.APP_START_MODE_NORMAL) {
if (stopping == null) {
stopping = new ArrayList<>();
stopping.add(service);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8a0baad..a72950b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22,6 +22,7 @@
import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.Manifest.permission.READ_FRAME_BUFFER;
import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
+import static android.Manifest.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST;
import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -4936,7 +4937,7 @@
}
@Override
- public void crashApplication(int uid, int initialPid, String packageName,
+ public void crashApplication(int uid, int initialPid, String packageName, int userId,
String message) {
if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
!= PackageManager.PERMISSION_GRANTED) {
@@ -4949,7 +4950,7 @@
}
synchronized(this) {
- mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, message);
+ mAppErrors.scheduleAppCrashLocked(uid, initialPid, packageName, userId, message);
}
}
@@ -7284,18 +7285,23 @@
Slog.d(TAG, "tempWhitelistAppForPowerSave(" + callerPid + ", " + callerUid + ", "
+ targetUid + ", " + duration + ")");
}
- synchronized (mPidsSelfLocked) {
- final ProcessRecord pr = mPidsSelfLocked.get(callerPid);
- if (pr == null) {
- Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid " + callerPid);
- return;
- }
- if (!pr.whitelistManager) {
- if (DEBUG_WHITELISTS) {
- Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid + ": pid "
- + callerPid + " is not allowed");
+
+ if (checkPermission(CHANGE_DEVICE_IDLE_TEMP_WHITELIST, callerPid, callerUid)
+ != PackageManager.PERMISSION_GRANTED) {
+ synchronized (mPidsSelfLocked) {
+ final ProcessRecord pr = mPidsSelfLocked.get(callerPid);
+ if (pr == null) {
+ Slog.w(TAG, "tempWhitelistAppForPowerSave() no ProcessRecord for pid "
+ + callerPid);
+ return;
}
- return;
+ if (!pr.whitelistManager) {
+ if (DEBUG_WHITELISTS) {
+ Slog.d(TAG, "tempWhitelistAppForPowerSave() for target " + targetUid
+ + ": pid " + callerPid + " is not allowed");
+ }
+ return;
+ }
}
}
@@ -8020,65 +8026,42 @@
return readMet && writeMet;
}
- public int getAppStartMode(int uid, String packageName) {
+ public boolean isAppStartModeDisabled(int uid, String packageName) {
synchronized (this) {
- return checkAllowBackgroundLocked(uid, packageName, -1, false);
+ return getAppStartModeLocked(uid, packageName, 0, -1, false, true)
+ == ActivityManager.APP_START_MODE_DISABLED;
}
}
// Unified app-op and target sdk check
- int appRestrictedInBackgroundLocked(int uid, String packageName) {
- if (packageName == null) {
- packageName = mPackageManagerInt.getNameForUid(uid);
- if (packageName == null) {
- Slog.w(TAG, "No package known for uid " + uid);
- return ActivityManager.APP_START_MODE_NORMAL;
- }
- }
-
- // !!! TODO: cache the package/versionCode lookups to fast path this
- ApplicationInfo app = getPackageManagerInternalLocked().getApplicationInfo(packageName,
- UserHandle.getUserId(uid));
- if (app != null) {
- // Apps that target O+ are always subject to background check
- if (mEnforceBackgroundCheck && app.targetSdkVersion >= Build.VERSION_CODES.O) {
- if (DEBUG_BACKGROUND_CHECK) {
- Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
- }
- return ActivityManager.APP_START_MODE_DELAYED_RIGID;
- }
- // ...and legacy apps get an AppOp check
- int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
- uid, packageName);
+ int appRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
+ // Apps that target O+ are always subject to background check
+ if (mEnforceBackgroundCheck && packageTargetSdk >= Build.VERSION_CODES.O) {
if (DEBUG_BACKGROUND_CHECK) {
- Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
+ Slog.i(TAG, "App " + uid + "/" + packageName + " targets O+, restricted");
}
- switch (appop) {
- case AppOpsManager.MODE_ALLOWED:
- return ActivityManager.APP_START_MODE_NORMAL;
- case AppOpsManager.MODE_IGNORED:
- return ActivityManager.APP_START_MODE_DELAYED;
- default:
- return ActivityManager.APP_START_MODE_DELAYED_RIGID;
- }
- } else {
- Slog.w(TAG, "Unknown app " + packageName + " / " + uid);
+ return ActivityManager.APP_START_MODE_DELAYED_RIGID;
}
- return ActivityManager.APP_START_MODE_NORMAL;
+ // ...and legacy apps get an AppOp check
+ int appop = mAppOpsService.noteOperation(AppOpsManager.OP_RUN_IN_BACKGROUND,
+ uid, packageName);
+ if (DEBUG_BACKGROUND_CHECK) {
+ Slog.i(TAG, "Legacy app " + uid + "/" + packageName + " bg appop " + appop);
+ }
+ switch (appop) {
+ case AppOpsManager.MODE_ALLOWED:
+ return ActivityManager.APP_START_MODE_NORMAL;
+ case AppOpsManager.MODE_IGNORED:
+ return ActivityManager.APP_START_MODE_DELAYED;
+ default:
+ return ActivityManager.APP_START_MODE_DELAYED_RIGID;
+ }
}
// Service launch is available to apps with run-in-background exemptions but
// some other background operations are not. If we're doing a check
// of service-launch policy, allow those callers to proceed unrestricted.
- int appServicesRestrictedInBackgroundLocked(int uid, String packageName) {
- if (packageName == null) {
- packageName = mPackageManagerInt.getNameForUid(uid);
- if (packageName == null) {
- Slog.w(TAG, "No package known for uid " + uid);
- return ActivityManager.APP_START_MODE_NORMAL;
- }
- }
-
+ int appServicesRestrictedInBackgroundLocked(int uid, String packageName, int packageTargetSdk) {
// Persistent app? NB: expects that persistent uids are always active.
final UidRecord uidRec = mActiveUids.get(uid);
if (uidRec != null && uidRec.persistent) {
@@ -8108,11 +8091,11 @@
}
// None of the service-policy criteria apply, so we apply the common criteria
- return appRestrictedInBackgroundLocked(uid, packageName);
+ return appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk);
}
- int checkAllowBackgroundLocked(int uid, String packageName, int callingPid,
- boolean alwaysRestrict) {
+ int getAppStartModeLocked(int uid, String packageName, int packageTargetSdk,
+ int callingPid, boolean alwaysRestrict, boolean disabledOnly) {
UidRecord uidRec = mActiveUids.get(uid);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid + " pkg="
+ packageName + " rec=" + uidRec + " always=" + alwaysRestrict + " idle="
@@ -8130,27 +8113,37 @@
// We are hard-core about ephemeral apps not running in the background.
return ActivityManager.APP_START_MODE_DISABLED;
} else {
- /** Don't want to allow this exception in the final background check impl?
- if (callingPid >= 0) {
- ProcessRecord proc;
- synchronized (mPidsSelfLocked) {
- proc = mPidsSelfLocked.get(callingPid);
- }
- if (proc != null && proc.curProcState
- < ActivityManager.PROCESS_STATE_RECEIVER) {
- // Whoever is instigating this is in the foreground, so we will allow it
- // to go through.
- return ActivityManager.APP_START_MODE_NORMAL;
- }
+ if (disabledOnly) {
+ // The caller is only interested in whether app starts are completely
+ // disabled for the given package (that is, it is an instant app). So
+ // we don't need to go further, which is all just seeing if we should
+ // apply a "delayed" mode for a regular app.
+ return ActivityManager.APP_START_MODE_NORMAL;
}
- */
-
final int startMode = (alwaysRestrict)
- ? appRestrictedInBackgroundLocked(uid, packageName)
- : appServicesRestrictedInBackgroundLocked(uid, packageName);
+ ? appRestrictedInBackgroundLocked(uid, packageName, packageTargetSdk)
+ : appServicesRestrictedInBackgroundLocked(uid, packageName,
+ packageTargetSdk);
if (DEBUG_BACKGROUND_CHECK) Slog.d(TAG, "checkAllowBackground: uid=" + uid
+ " pkg=" + packageName + " startMode=" + startMode
+ " onwhitelist=" + isOnDeviceIdleWhitelistLocked(uid));
+ if (startMode == ActivityManager.APP_START_MODE_DELAYED) {
+ // This is an old app that has been forced into a "compatible as possible"
+ // mode of background check. To increase compatibility, we will allow other
+ // foreground apps to cause its services to start.
+ if (callingPid >= 0) {
+ ProcessRecord proc;
+ synchronized (mPidsSelfLocked) {
+ proc = mPidsSelfLocked.get(callingPid);
+ }
+ if (proc != null && proc.curProcState
+ < ActivityManager.PROCESS_STATE_RECEIVER) {
+ // Whoever is instigating this is in the foreground, so we will allow it
+ // to go through.
+ return ActivityManager.APP_START_MODE_NORMAL;
+ }
+ }
+ }
return startMode;
}
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index 202868a..1a2a31b 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -167,6 +167,8 @@
return runBugReport(pw);
case "force-stop":
return runForceStop(pw);
+ case "crash":
+ return runCrash(pw);
case "kill":
return runKill(pw);
case "kill-all":
@@ -851,6 +853,32 @@
return 0;
}
+ int runCrash(PrintWriter pw) throws RemoteException {
+ int userId = UserHandle.USER_ALL;
+
+ String opt;
+ while ((opt=getNextOption()) != null) {
+ if (opt.equals("--user")) {
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ } else {
+ getErrPrintWriter().println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ }
+
+ int pid = -1;
+ String packageName = null;
+ final String arg = getNextArgRequired();
+ // The argument is either a pid or a package name
+ try {
+ pid = Integer.parseInt(arg);
+ } catch (NumberFormatException e) {
+ packageName = arg;
+ }
+ mInterface.crashApplication(-1, pid, packageName, userId, "shell-induced crash");
+ return 0;
+ }
+
int runKill(PrintWriter pw) throws RemoteException {
int userId = UserHandle.USER_ALL;
@@ -2480,6 +2508,8 @@
pw.println(" --telephony: will dump only telephony sections.");
pw.println(" force-stop [--user <USER_ID> | all | current] <PACKAGE>");
pw.println(" Completely stop the given application package.");
+ pw.println(" crash [--user <USER_ID>] <PACKAGE|PID>");
+ pw.println(" Induce a VM crash in the specified package or process");
pw.println(" kill [--user <USER_ID> | all | current] <PACKAGE>");
pw.println(" Kill all processes associated with the given application.");
pw.println(" kill-all");
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 739a8c4..384f2f8 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -259,7 +259,16 @@
}
}
- void scheduleAppCrashLocked(int uid, int initialPid, String packageName,
+ /**
+ * Induce a crash in the given app.
+ *
+ * @param uid if nonnegative, the required matching uid of the target to crash
+ * @param initialPid fast-path match for the target to crash
+ * @param packageName fallback match if the stated pid is not found or doesn't match uid
+ * @param userId If nonnegative, required to identify a match by package name
+ * @param message
+ */
+ void scheduleAppCrashLocked(int uid, int initialPid, String packageName, int userId,
String message) {
ProcessRecord proc = null;
@@ -270,14 +279,15 @@
synchronized (mService.mPidsSelfLocked) {
for (int i=0; i<mService.mPidsSelfLocked.size(); i++) {
ProcessRecord p = mService.mPidsSelfLocked.valueAt(i);
- if (p.uid != uid) {
+ if (uid >= 0 && p.uid != uid) {
continue;
}
if (p.pid == initialPid) {
proc = p;
break;
}
- if (p.pkgList.containsKey(packageName)) {
+ if (p.pkgList.containsKey(packageName)
+ && (userId < 0 || p.userId == userId)) {
proc = p;
}
}
@@ -286,7 +296,8 @@
if (proc == null) {
Slog.w(TAG, "crashApplication: nothing for uid=" + uid
+ " initialPid=" + initialPid
- + " packageName=" + packageName);
+ + " packageName=" + packageName
+ + " userId=" + userId);
return;
}
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 61e555b..ee2467a 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -592,22 +592,6 @@
+ " (uid " + r.callingUid + ")");
skip = true;
}
- if (!skip) {
- final int allowed = mService.checkAllowBackgroundLocked(filter.receiverList.uid,
- filter.packageName, -1, false);
- if (false && allowed == ActivityManager.APP_START_MODE_DISABLED) {
- // XXX should we really not allow this? It means that while we are
- // keeping an ephemeral app cached, its registered receivers will stop
- // receiving broadcasts after it goes idle... so if it comes back to
- // the foreground, it won't know what the current state of those broadcasts is.
- Slog.w(TAG, "Background execution not allowed: receiving "
- + r.intent
- + " to " + filter.receiverList.app
- + " (pid=" + filter.receiverList.pid
- + ", uid=" + filter.receiverList.uid + ")");
- skip = true;
- }
- }
if (!mService.mIntentFirewall.checkBroadcast(r.intent, r.callingUid,
r.callingPid, r.resolvedType, filter.receiverList.uid)) {
@@ -1156,13 +1140,14 @@
info.activityInfo.applicationInfo.uid, false);
if (!skip) {
- final int allowed = mService.checkAllowBackgroundLocked(
- info.activityInfo.applicationInfo.uid, info.activityInfo.packageName, -1, true);
+ final int allowed = mService.getAppStartModeLocked(
+ info.activityInfo.applicationInfo.uid, info.activityInfo.packageName,
+ info.activityInfo.applicationInfo.targetSdkVersion, -1, true, false);
if (allowed != ActivityManager.APP_START_MODE_NORMAL) {
// We won't allow this receiver to be launched if the app has been
// completely disabled from launches, or it was not explicitly sent
// to it and the app is in a state that should not receive it
- // (depending on how checkAllowBackgroundLocked has determined that).
+ // (depending on how getAppStartModeLocked has determined that).
if (allowed == ActivityManager.APP_START_MODE_DISABLED) {
Slog.w(TAG, "Background execution disabled: receiving "
+ r.intent + " to "
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 71c7fd3..82b00da 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -534,7 +534,7 @@
// get to be foreground.
ams.setServiceForeground(name, ServiceRecord.this,
0, null, 0);
- ams.crashApplication(appUid, appPid, localPackageName,
+ ams.crashApplication(appUid, appPid, localPackageName, -1,
"Bad notification for startForeground: " + e);
}
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 11a3f11..5b539ff 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1019,8 +1019,7 @@
final int owningUid = syncAdapterInfo.uid;
final String owningPackage = syncAdapterInfo.componentName.getPackageName();
try {
- if (ActivityManager.getService().getAppStartMode(owningUid,
- owningPackage) == ActivityManager.APP_START_MODE_DISABLED) {
+ if (ActivityManager.getService().isAppStartModeDisabled(owningUid, owningPackage)) {
Slog.w(TAG, "Not scheduling job " + syncAdapterInfo.uid + ":"
+ syncAdapterInfo.componentName
+ " -- package not allowed to start");
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index f42c5be..a748013 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -566,8 +566,8 @@
String tag) {
JobStatus jobStatus = JobStatus.createFromJobInfo(job, uId, packageName, userId, tag);
try {
- if (ActivityManager.getService().getAppStartMode(uId,
- job.getService().getPackageName()) == ActivityManager.APP_START_MODE_DISABLED) {
+ if (ActivityManager.getService().isAppStartModeDisabled(uId,
+ job.getService().getPackageName())) {
Slog.w(TAG, "Not scheduling job " + uId + ":" + job.toString()
+ " -- package not allowed to start");
return JobScheduler.RESULT_FAILURE;
@@ -1201,9 +1201,8 @@
public void process(JobStatus job) {
if (isReadyToBeExecutedLocked(job)) {
try {
- if (ActivityManager.getService().getAppStartMode(job.getUid(),
- job.getJob().getService().getPackageName())
- == ActivityManager.APP_START_MODE_DISABLED) {
+ if (ActivityManager.getService().isAppStartModeDisabled(job.getUid(),
+ job.getJob().getService().getPackageName())) {
Slog.w(TAG, "Aborting job " + job.getUid() + ":"
+ job.getJob().toString() + " -- package not allowed to start");
mHandler.obtainMessage(MSG_STOP_JOB, job).sendToTarget();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 323b468..168884d 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -605,7 +605,7 @@
REASON_DELEGATE_ERROR, null);
long ident = Binder.clearCallingIdentity();
try {
- ActivityManager.getService().crashApplication(uid, initialPid, pkg,
+ ActivityManager.getService().crashApplication(uid, initialPid, pkg, -1,
"Bad notification posted from package " + pkg
+ ": " + message);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 6044561..63a5d14 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -9391,8 +9391,7 @@
}
// A package name must be unique; don't allow duplicates
- if (mPackages.containsKey(pkg.packageName)
- || mSharedLibraries.containsKey(pkg.packageName)) {
+ if (mPackages.containsKey(pkg.packageName)) {
throw new PackageManagerException(INSTALL_FAILED_DUPLICATE_PACKAGE,
"Application package " + pkg.packageName
+ " already installed. Skipping duplicate.");
@@ -17704,6 +17703,13 @@
return false;
}
+ try {
+ // update shared libraries for the newly re-installed system package
+ updateSharedLibrariesLPr(newPkg, null);
+ } catch (PackageManagerException e) {
+ Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+ }
+
prepareAppDataAfterInstallLIF(newPkg);
// writer
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index ae709fe..56d679ef 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1529,10 +1529,11 @@
if (UserHandle.getUserId(callingUid) != userId) {
throw new SecurityException("Invalid user-ID");
}
- if (injectGetPackageUid(packageName, userId) == callingUid) {
- return; // Caller is valid.
+ if (injectGetPackageUid(packageName, userId) != callingUid) {
+ throw new SecurityException("Calling package name mismatch");
}
- throw new SecurityException("Calling package name mismatch");
+ Preconditions.checkState(!isEphemeralApp(packageName, userId),
+ "Ephemeral apps can't use ShortcutManager");
}
// Overridden in unit tests to execute r synchronously.
@@ -3073,6 +3074,10 @@
return (ai != null) && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;
}
+ private static boolean isEphemeralApp(@Nullable ApplicationInfo ai) {
+ return (ai != null) && ai.isEphemeralApp();
+ }
+
private static boolean isInstalled(@Nullable PackageInfo pi) {
return (pi != null) && isInstalled(pi.applicationInfo);
}
@@ -3097,6 +3102,10 @@
return getApplicationInfo(packageName, userId) != null;
}
+ boolean isEphemeralApp(String packageName, int userId) {
+ return isEphemeralApp(getApplicationInfo(packageName, userId));
+ }
+
@Nullable
XmlResourceParser injectXmlMetaData(ActivityInfo activityInfo, String key) {
return activityInfo.loadXmlMetaData(mContext.getPackageManager(), key);
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index 2fd0603..74af639 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -81,7 +81,7 @@
// TODO(b/31632518)
if (gLight == nullptr) {
- gLight = ILight::getService("light");
+ gLight = ILight::getService();
}
if (gLight == nullptr) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 623a0a5..f3b0131 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -5574,7 +5574,7 @@
}
/**
- * Set whether auto time is required by the specified admin (must be device owner).
+ * Set whether auto time is required by the specified admin (must be device or profile owner).
*/
@Override
public void setAutoTimeRequired(ComponentName who, boolean required) {
@@ -5585,7 +5585,7 @@
final int userHandle = UserHandle.getCallingUserId();
synchronized (this) {
ActiveAdmin admin = getActiveAdminForCallerLocked(who,
- DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
+ DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
if (admin.requireAutoTime != required) {
admin.requireAutoTime = required;
saveSettingsLocked(userHandle);
@@ -5604,7 +5604,7 @@
}
/**
- * Returns whether or not auto time is required by the device owner.
+ * Returns whether or not auto time is required by the device owner or any profile owner.
*/
@Override
public boolean getAutoTimeRequired() {
@@ -5613,7 +5613,20 @@
}
synchronized (this) {
ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
- return (deviceOwner != null) ? deviceOwner.requireAutoTime : false;
+ if (deviceOwner != null && deviceOwner.requireAutoTime) {
+ // If the device owner enforces auto time, we don't need to check the PO's
+ return true;
+ }
+
+ // Now check to see if any profile owner on any user enforces auto time
+ for (Integer userId : mOwners.getProfileOwnerKeys()) {
+ ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
+ if (profileOwner != null && profileOwner.requireAutoTime) {
+ return true;
+ }
+ }
+
+ return false;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index ee49a00..a600e69 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -76,6 +76,7 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -94,6 +95,7 @@
@Mock private DevicePolicyManager mMockDevicePolicyManager;
@Mock private IAccountManagerResponse mMockAccountManagerResponse;
@Mock private IBinder mMockBinder;
+ @Mock private INotificationManager mMockNotificationManager;
@Captor private ArgumentCaptor<Intent> mIntentCaptor;
@Captor private ArgumentCaptor<Bundle> mBundleCaptor;
@@ -129,7 +131,7 @@
Context realTestContext = getContext();
MyMockContext mockContext = new MyMockContext(realTestContext, mMockContext);
setContext(mockContext);
- mTestInjector = new TestInjector(realTestContext, mockContext);
+ mTestInjector = new TestInjector(realTestContext, mockContext, mMockNotificationManager);
mAms = new AccountManagerService(mTestInjector);
}
@@ -500,7 +502,7 @@
}
@SmallTest
- public void testStartAddAccountSessionUserSuccessWithoutPasswordForwarding() throws Exception {
+ public void testStartAddAccountSessionSuccessWithoutPasswordForwarding() throws Exception {
unlockSystemUser();
when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
PackageManager.PERMISSION_DENIED);
@@ -531,7 +533,7 @@
}
@SmallTest
- public void testStartAddAccountSessionUserSuccessWithPasswordForwarding() throws Exception {
+ public void testStartAddAccountSessionSuccessWithPasswordForwarding() throws Exception {
unlockSystemUser();
when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
PackageManager.PERMISSION_GRANTED);
@@ -564,7 +566,7 @@
}
@SmallTest
- public void testStartAddAccountSessionUserReturnWithInvalidIntent() throws Exception {
+ public void testStartAddAccountSessionReturnWithInvalidIntent() throws Exception {
unlockSystemUser();
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = new ActivityInfo();
@@ -593,7 +595,7 @@
}
@SmallTest
- public void testStartAddAccountSessionUserReturnWithValidIntent() throws Exception {
+ public void testStartAddAccountSessionReturnWithValidIntent() throws Exception {
unlockSystemUser();
ResolveInfo resolveInfo = new ResolveInfo();
resolveInfo.activityInfo = new ActivityInfo();
@@ -626,7 +628,7 @@
}
@SmallTest
- public void testStartAddAccountSessionUserError() throws Exception {
+ public void testStartAddAccountSessionError() throws Exception {
unlockSystemUser();
Bundle options = createOptionsWithAccountName(
AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR);
@@ -650,14 +652,629 @@
verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
}
+ @SmallTest
+ public void testStartUpdateCredentialsSessionWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.startUpdateCredentialsSession(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType",
+ true, // expectActivityLaunch
+ null); // optionsIn
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ } catch(Exception e){
+ fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ }
+ }
+
+ @SmallTest
+ public void testStartUpdateCredentialsSessionWithNullAccount() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.startUpdateCredentialsSession(
+ mMockAccountManagerResponse, // response
+ null,
+ "authTokenType",
+ true, // expectActivityLaunch
+ null); // optionsIn
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ } catch(Exception e){
+ fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ }
+ }
+
+ @SmallTest
+ public void testStartUpdateCredentialsSessionSuccessWithoutPasswordForwarding()
+ throws Exception {
+ unlockSystemUser();
+ when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+ PackageManager.PERMISSION_DENIED);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ Bundle options = createOptionsWithAccountName(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+ mAms.startUpdateCredentialsSession(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType",
+ false, // expectActivityLaunch
+ options); // optionsIn
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(sessionBundle);
+ // Assert that session bundle is encrypted and hence data not visible.
+ assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+ // Assert password is not returned
+ assertNull(result.getString(AccountManager.KEY_PASSWORD));
+ assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN,
+ result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ }
+
+ @SmallTest
+ public void testStartUpdateCredentialsSessionSuccessWithPasswordForwarding() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+ PackageManager.PERMISSION_GRANTED);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ Bundle options = createOptionsWithAccountName(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+ mAms.startUpdateCredentialsSession(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ "authTokenType",
+ false, // expectActivityLaunch
+ options); // optionsIn
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(sessionBundle);
+ // Assert that session bundle is encrypted and hence data not visible.
+ assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+ // Assert password is returned
+ assertEquals(result.getString(AccountManager.KEY_PASSWORD),
+ AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+ assertNull(result.getString(AccountManager.KEY_AUTHTOKEN));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN,
+ result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ }
+
+ @SmallTest
+ public void testStartUpdateCredentialsSessionReturnWithInvalidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ Bundle options = createOptionsWithAccountName(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+
+ mAms.startUpdateCredentialsSession(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ "authTokenType",
+ true, // expectActivityLaunch
+ options); // optionsIn
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+ }
+
+ @SmallTest
+ public void testStartUpdateCredentialsSessionReturnWithValidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ Bundle options = createOptionsWithAccountName(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+
+ mAms.startUpdateCredentialsSession(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_INTERVENE,
+ "authTokenType",
+ true, // expectActivityLaunch
+ options); // optionsIn
+
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(intent);
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+ }
+
+ @SmallTest
+ public void testStartUpdateCredentialsSessionError() throws Exception {
+ unlockSystemUser();
+ Bundle options = createOptionsWithAccountName(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR);
+ options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+ options.putString(AccountManager.KEY_ERROR_MESSAGE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.startUpdateCredentialsSession(
+ response, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_ERROR,
+ "authTokenType",
+ true, // expectActivityLaunch
+ options); // optionsIn
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.finishSessionAsUser(
+ null, // response
+ createEncryptedSessionBundle(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ UserHandle.USER_SYSTEM);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ } catch(Exception e){
+ fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ }
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserWithNullSessionBundle() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.finishSessionAsUser(
+ mMockAccountManagerResponse, // response
+ null, // sessionBundle
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ UserHandle.USER_SYSTEM);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ } catch(Exception e){
+ fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ }
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserUserCannotModifyAccountNoDPM() throws Exception {
+ unlockSystemUser();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+ when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+ mAms.finishSessionAsUser(
+ mMockAccountManagerResponse, // response
+ createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ 2); // fake user id
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+ verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.of(2)));
+
+ // verify the intent for default CantAddAccountActivity is sent.
+ Intent intent = mIntentCaptor.getValue();
+ assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+ assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+ AccountManager.ERROR_CODE_USER_RESTRICTED);
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserUserCannotModifyAccountWithDPM() throws Exception {
+ unlockSystemUser();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+ when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ LocalServices.addService(
+ DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+ when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+ anyInt(), anyString())).thenReturn(new Intent());
+ when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+ anyInt(), anyBoolean())).thenReturn(new Intent());
+
+ mAms.finishSessionAsUser(
+ mMockAccountManagerResponse, // response
+ createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ 2); // fake user id
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+ verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.of(2)));
+ verify(mMockDevicePolicyManagerInternal).createUserRestrictionSupportIntent(
+ anyInt(), anyString());
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserWithBadSessionBundle() throws Exception {
+ unlockSystemUser();
+
+ Bundle badSessionBundle = new Bundle();
+ badSessionBundle.putString("any", "any");
+ mAms.finishSessionAsUser(
+ mMockAccountManagerResponse, // response
+ badSessionBundle, // sessionBundle
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ 2); // fake user id
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_BAD_REQUEST), anyString());
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserWithBadAccountType() throws Exception {
+ unlockSystemUser();
+
+ mAms.finishSessionAsUser(
+ mMockAccountManagerResponse, // response
+ createEncryptedSessionBundleWithNoAccountType(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ 2); // fake user id
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_BAD_ARGUMENTS), anyString());
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserUserCannotModifyAccountForTypeNoDPM() throws Exception {
+ unlockSystemUser();
+ when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+ .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+ mAms.finishSessionAsUser(
+ mMockAccountManagerResponse, // response
+ createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ 2); // fake user id
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+ verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.of(2)));
+
+ // verify the intent for default CantAddAccountActivity is sent.
+ Intent intent = mIntentCaptor.getValue();
+ assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+ assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+ AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE);
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserUserCannotModifyAccountForTypeWithDPM() throws Exception {
+ unlockSystemUser();
+ when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+ mMockDevicePolicyManager);
+ when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+ .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+
+ LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+ LocalServices.addService(
+ DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+ when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+ anyInt(), anyString())).thenReturn(new Intent());
+ when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+ anyInt(), anyBoolean())).thenReturn(new Intent());
+
+ mAms.finishSessionAsUser(
+ mMockAccountManagerResponse, // response
+ createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ 2); // fake user id
+
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+ verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.of(2)));
+ verify(mMockDevicePolicyManagerInternal).createShowAdminSupportIntent(
+ anyInt(), anyBoolean());
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserSuccess() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+ mAms.finishSessionAsUser(
+ response, // response
+ createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS),
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+ // Verify notification is cancelled
+ verify(mMockNotificationManager).cancelNotificationWithTag(
+ anyString(), anyString(), anyInt(), anyInt());
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(sessionBundle);
+ // Assert that session bundle is decrypted and hence data is visible.
+ assertEquals(AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1,
+ sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+ // Assert finishSessionAsUser added calling uid and pid into the sessionBundle
+ assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_UID));
+ assertTrue(sessionBundle.containsKey(AccountManager.KEY_CALLER_PID));
+ // Assert App bundle data overrides sessionBundle data
+ assertEquals(sessionBundle.getString(
+ AccountManager.KEY_ANDROID_PACKAGE_NAME), "APCT.package");
+
+ // Verify response data
+ assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_NAME,
+ result.getString(AccountManager.KEY_ACCOUNT_NAME));
+ assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+ result.getString(AccountManager.KEY_ACCOUNT_TYPE));
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserReturnWithInvalidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.finishSessionAsUser(
+ response, // response
+ createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE),
+ true, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ verify(mMockAccountManagerResponse).onError(
+ eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserReturnWithValidIntent() throws Exception {
+ unlockSystemUser();
+ ResolveInfo resolveInfo = new ResolveInfo();
+ resolveInfo.activityInfo = new ActivityInfo();
+ resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+ when(mMockPackageManager.resolveActivityAsUser(
+ any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+ when(mMockPackageManager.checkSignatures(
+ anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.finishSessionAsUser(
+ response, // response
+ createEncryptedSessionBundle(AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE),
+ true, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(intent);
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+ assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+ }
+
+ @SmallTest
+ public void testFinishSessionAsUserError() throws Exception {
+ unlockSystemUser();
+ Bundle sessionBundle = createEncryptedSessionBundleWithError(
+ AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.finishSessionAsUser(
+ response, // response
+ sessionBundle,
+ false, // expectActivityLaunch
+ createAppBundle(), // appInfo
+ UserHandle.USER_SYSTEM);
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testIsCredentialsUpdatedSuggestedWithNullResponse() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.isCredentialsUpdateSuggested(
+ null, // response
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ } catch(Exception e){
+ fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ }
+ }
+
+ @SmallTest
+ public void testIsCredentialsUpdatedSuggestedWithNullAccount() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.isCredentialsUpdateSuggested(
+ mMockAccountManagerResponse,
+ null, // account
+ AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ } catch(Exception e){
+ fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ }
+ }
+
+ @SmallTest
+ public void testIsCredentialsUpdatedSuggestedWithEmptyStatusToken() throws Exception {
+ unlockSystemUser();
+ try {
+ mAms.isCredentialsUpdateSuggested(
+ mMockAccountManagerResponse,
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ null);
+ fail("IllegalArgumentException expected. But no exception was thrown.");
+ } catch (IllegalArgumentException e) {
+ } catch(Exception e){
+ fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+ }
+ }
+
+ @SmallTest
+ public void testIsCredentialsUpdatedSuggestedError() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.isCredentialsUpdateSuggested(
+ response,
+ AccountManagerServiceTestFixtures.ACCOUNT_ERROR,
+ AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+ }
+
+ @SmallTest
+ public void testIsCredentialsUpdatedSuggestedSuccess() throws Exception {
+ unlockSystemUser();
+ final CountDownLatch latch = new CountDownLatch(1);
+ Response response = new Response(latch, mMockAccountManagerResponse);
+
+ mAms.isCredentialsUpdateSuggested(
+ response,
+ AccountManagerServiceTestFixtures.ACCOUNT_SUCCESS,
+ AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+
+ waitForLatch(latch);
+ verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+ Bundle result = mBundleCaptor.getValue();
+ boolean needUpdate = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
+ assertTrue(needUpdate);
+ }
+
private void waitForLatch(CountDownLatch latch) {
try {
latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
- fail("should not throw an InterruptedException");
+ throw new IllegalStateException("Should not throw an InterruptedException", e);
}
}
+ private Bundle encryptBundleWithCryptoHelper(Bundle sessionBundle) {
+ Bundle encryptedBundle = null;
+ try {
+ CryptoHelper cryptoHelper = CryptoHelper.getInstance();
+ encryptedBundle = cryptoHelper.encryptBundle(sessionBundle);
+ } catch (GeneralSecurityException e) {
+ throw new IllegalStateException("Failed to encrypt session bundle.", e);
+ }
+ return encryptedBundle;
+ }
+
+ private Bundle createEncryptedSessionBundle(final String accountName) {
+ Bundle sessionBundle = new Bundle();
+ sessionBundle.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+ sessionBundle.putString(
+ AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1,
+ AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1);
+ sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+ sessionBundle.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, "APCT.session.package");
+ return encryptBundleWithCryptoHelper(sessionBundle);
+ }
+
+ private Bundle createEncryptedSessionBundleWithError(final String accountName) {
+ Bundle sessionBundle = new Bundle();
+ sessionBundle.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+ sessionBundle.putString(
+ AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1,
+ AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1);
+ sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE,
+ AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+ sessionBundle.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, "APCT.session.package");
+ sessionBundle.putInt(
+ AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+ sessionBundle.putString(AccountManager.KEY_ERROR_MESSAGE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+ return encryptBundleWithCryptoHelper(sessionBundle);
+ }
+
+ private Bundle createEncryptedSessionBundleWithNoAccountType(final String accountName) {
+ Bundle sessionBundle = new Bundle();
+ sessionBundle.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+ sessionBundle.putString(
+ AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1,
+ AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1);
+ sessionBundle.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, "APCT.session.package");
+ return encryptBundleWithCryptoHelper(sessionBundle);
+ }
+
+ private Bundle createAppBundle() {
+ Bundle appBundle = new Bundle();
+ appBundle.putString(AccountManager.KEY_ANDROID_PACKAGE_NAME, "APCT.package");
+ return appBundle;
+ }
+
private Bundle createOptionsWithAccountName(final String accountName) {
Bundle sessionBundle = new Bundle();
sessionBundle.putString(
@@ -784,9 +1401,13 @@
static class TestInjector extends AccountManagerService.Injector {
private Context mRealContext;
- TestInjector(Context realContext, Context mockContext) {
+ private INotificationManager mMockNotificationManager;
+ TestInjector(Context realContext,
+ Context mockContext,
+ INotificationManager mockNotificationManager) {
super(mockContext);
mRealContext = realContext;
+ mMockNotificationManager = mockNotificationManager;
}
@Override
@@ -820,7 +1441,7 @@
@Override
INotificationManager getNotificationManager() {
- return mock(INotificationManager.class);
+ return mMockNotificationManager;
}
}
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
index 0db11e0c..8ec6176 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
@@ -197,7 +197,8 @@
result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
- result.putString(AccountManager.KEY_PASSWORD, "doesn't matter");
+ result.putString(AccountManager.KEY_PASSWORD,
+ AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
result.putString(AccountManager.KEY_AUTHTOKEN,
Integer.toString(mTokenCounter.incrementAndGet()));
} else if (accountName.equals(
@@ -243,6 +244,8 @@
Bundle result = new Bundle();
if (accountName.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+ // add sessionBundle into result for verification purpose
+ result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
// fill bundle with a success result.
result.putString(AccountManager.KEY_ACCOUNT_NAME,
AccountManagerServiceTestFixtures.ACCOUNT_NAME);
@@ -288,7 +291,9 @@
} else {
// fill with error
fillResultWithError(
- result, AccountManager.ERROR_CODE_INVALID_RESPONSE, "Default Error Message");
+ result,
+ AccountManager.ERROR_CODE_INVALID_RESPONSE,
+ AccountManagerServiceTestFixtures.ERROR_MESSAGE);
}
response.onResult(result);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 167b33a..9835c88 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -566,6 +566,7 @@
protected Map<String, PackageInfo> mInjectedPackages;
protected Set<PackageWithUser> mUninstalledPackages;
+ protected Set<PackageWithUser> mEphemeralPackages;
protected Set<String> mSystemPackages;
protected PackageManager mMockPackageManager;
@@ -731,6 +732,7 @@
mUninstalledPackages = new HashSet<>();
mSystemPackages = new HashSet<>();
+ mEphemeralPackages = new HashSet<>();
mInjectedFilePathRoot = new File(getTestContext().getCacheDir(), "test-files");
@@ -1034,6 +1036,9 @@
if (mUninstalledPackages.contains(PackageWithUser.of(userId, packageName))) {
ret.applicationInfo.flags &= ~ApplicationInfo.FLAG_INSTALLED;
}
+ if (mEphemeralPackages.contains(PackageWithUser.of(userId, packageName))) {
+ ret.applicationInfo.privateFlags |= ApplicationInfo.PRIVATE_FLAG_EPHEMERAL;
+ }
if (mSystemPackages.contains(packageName)) {
ret.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
index d25923c..562de414 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest2.java
@@ -46,6 +46,7 @@
import com.android.frameworks.servicestests.R;
import com.android.server.pm.ShortcutService.ConfigConstants;
+import com.android.server.pm.ShortcutUser.PackageWithUser;
import java.io.File;
import java.io.FileWriter;
@@ -2037,4 +2038,32 @@
assertFalse(mService.isUserUnlockedL(USER_0));
assertFalse(mService.isUserUnlockedL(USER_10));
}
+
+ public void testEphemeralApp() {
+ mRunningUsers.put(USER_10, true); // this test needs user 10.
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertWith(mManager.getDynamicShortcuts()).isEmpty();
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(mManager.getDynamicShortcuts()).isEmpty();
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertWith(mManager.getDynamicShortcuts()).isEmpty();
+ });
+ // Make package 1 ephemeral.
+ mEphemeralPackages.add(PackageWithUser.of(USER_0, CALLING_PACKAGE_1));
+
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertExpectException(IllegalStateException.class, "Ephemeral apps", () -> {
+ mManager.getDynamicShortcuts();
+ });
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_10, () -> {
+ assertWith(mManager.getDynamicShortcuts()).isEmpty();
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertWith(mManager.getDynamicShortcuts()).isEmpty();
+ });
+ }
}
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 68765b6..6826975 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -37,6 +37,7 @@
import android.util.Slog;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.Preconditions;
import com.android.server.SystemService;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
@@ -46,8 +47,6 @@
private static final String PROP_VERIFY_STORAGE = "fw.verify_storage";
- // TODO: pivot all methods to manual mode when quota isn't supported
-
public static class Lifecycle extends SystemService {
private StorageStatsService mService;
@@ -71,11 +70,11 @@
private final Installer mInstaller;
public StorageStatsService(Context context) {
- mContext = context;
- mAppOps = context.getSystemService(AppOpsManager.class);
- mUser = context.getSystemService(UserManager.class);
- mPackage = context.getSystemService(PackageManager.class);
- mStorage = context.getSystemService(StorageManager.class);
+ mContext = Preconditions.checkNotNull(context);
+ mAppOps = Preconditions.checkNotNull(context.getSystemService(AppOpsManager.class));
+ mUser = Preconditions.checkNotNull(context.getSystemService(UserManager.class));
+ mPackage = Preconditions.checkNotNull(context.getPackageManager());
+ mStorage = Preconditions.checkNotNull(context.getSystemService(StorageManager.class));
mInstaller = new Installer(context);
mInstaller.onStart();
@@ -107,7 +106,7 @@
case AppOpsManager.MODE_ALLOWED:
return;
case AppOpsManager.MODE_DEFAULT:
- mContext.enforceCallingPermission(
+ mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.PACKAGE_USAGE_STATS, TAG);
return;
default:
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index db7a31a..fbbe636 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -656,6 +656,7 @@
// send a sticky broadcast containing current USB state
Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+ | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
| Intent.FLAG_RECEIVER_FOREGROUND);
intent.putExtra(UsbManager.USB_CONNECTED, mConnected);
intent.putExtra(UsbManager.USB_HOST_CONNECTED, mHostConnected);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c0a86d6..a853d5c 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -598,6 +598,38 @@
"vvm_cellular_data_required_bool";
/**
+ * The default OMTP visual voicemail client prefix to use. Defaulted to "//VVM"
+ */
+ public static final String KEY_VVM_CLIENT_PREFIX_STRING =
+ "vvm_client_prefix_string";
+
+ /**
+ * Whether to use SSL to connect to the visual voicemail IMAP server. Defaulted to false.
+ */
+ public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
+
+ /**
+ * A set of capabilities that should not be used even if it is reported by the visual voicemail
+ * IMAP CAPABILITY command.
+ */
+ public static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY =
+ "vvm_disabled_capabilities_string_array";
+
+ /**
+ * Whether legacy mode should be used when the visual voicemail client is disabled.
+ *
+ * <p>Legacy mode is a mode that on the carrier side visual voicemail is still activated, but on
+ * the client side all network operations are disabled. SMSs are still monitored so a new
+ * message SYNC SMS will be translated to show a message waiting indicator, like traditional
+ * voicemails.
+ *
+ * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to
+ * function without the data cost.
+ */
+ public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL =
+ "vvm_legacy_mode_enabled_bool";
+
+ /**
* Whether to prefetch audio data on new voicemail arrival, defaulted to true.
*/
public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
@@ -605,10 +637,20 @@
/**
* The package name of the carrier's visual voicemail app to ensure that dialer visual voicemail
* and carrier visual voicemail are not active at the same time.
+ *
+ * @deprecated use {@link #KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY}.
*/
+ @Deprecated
public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
/**
+ * A list of the carrier's visual voicemail app package names to ensure that dialer visual
+ * voicemail and carrier visual voicemail are not active at the same time.
+ */
+ public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY =
+ "carrier_vvm_package_name_string_array";
+
+ /**
* Flag specifying whether ICCID is showed in SIM Status screen, default to false.
*/
public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -1308,8 +1350,13 @@
sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
sDefaults.putString(KEY_VVM_TYPE_STRING, "");
sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false);
+ sDefaults.putString(KEY_VVM_CLIENT_PREFIX_STRING,"//VVM");
+ sDefaults.putBoolean(KEY_VVM_SSL_ENABLED_BOOL,false);
+ sDefaults.putStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY, null);
+ sDefaults.putBoolean(KEY_VVM_LEGACY_MODE_ENABLED_BOOL,false);
sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOL, true);
sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
+ sDefaults.putStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");