Merge "Avoid allocation in methods of Outline" into nyc-dev
diff --git a/Android.mk b/Android.mk
index 165aed9..cf6d946 100644
--- a/Android.mk
+++ b/Android.mk
@@ -42,7 +42,7 @@
# EventLogTags files.
LOCAL_SRC_FILES += \
- core/java/android/auditing/SecurityLogTags.logtags \
+ core/java/android/app/admin/SecurityLogTags.logtags \
core/java/android/content/EventLogTags.logtags \
core/java/android/speech/tts/EventLogTags.logtags \
core/java/android/webkit/EventLogTags.logtags \
diff --git a/api/current.txt b/api/current.txt
index 27d53fd..672eb4d9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -559,6 +559,7 @@
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillColor = 16843780; // 0x1010404
field public static final int fillEnabled = 16843343; // 0x101024f
+ field public static final int fillType = 16844064; // 0x1010520
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -3536,7 +3537,6 @@
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public void onProvideAssistContent(android.app.assist.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public android.net.Uri onProvideReferrer();
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method protected void onRestart();
@@ -4218,7 +4218,6 @@
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPrepareOptionsMenu(android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public void onRestoreInstanceState(android.os.Bundle);
method public android.os.Bundle onSaveInstanceState();
method public boolean onSearchRequested(android.view.SearchEvent);
@@ -5852,7 +5851,6 @@
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
- method public boolean getDeviceLoggingEnabled(android.content.ComponentName);
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -5901,6 +5899,7 @@
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isProfileOwnerApp(java.lang.String);
method public boolean isProvisioningAllowed(java.lang.String);
+ method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
method public void reboot(android.content.ComponentName);
@@ -5910,8 +5909,8 @@
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean requestBugreport(android.content.ComponentName);
method public boolean resetPassword(java.lang.String, int);
- method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrieveDeviceLogs(android.content.ComponentName);
- method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrievePreviousDeviceLogs(android.content.ComponentName);
+ method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
+ method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
@@ -5923,7 +5922,6 @@
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public void setDeviceLoggingEnabled(android.content.ComponentName, boolean);
method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
@@ -5956,6 +5954,7 @@
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
@@ -6041,6 +6040,27 @@
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
+ public class SecurityLog {
+ ctor public SecurityLog();
+ field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
+ field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
+ field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
+ field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+ field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
+ field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
+ field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
+ }
+
+ public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.Object getData();
+ method public int getTag();
+ method public long getTimeNanos();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
+ }
+
public class SystemUpdatePolicy implements android.os.Parcelable {
method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -6245,6 +6265,8 @@
method public long getIntervalMillis();
method public long getMaxExecutionDelayMillis();
method public long getMinLatencyMillis();
+ method public static final long getMinimumFlex();
+ method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
@@ -6258,8 +6280,6 @@
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
- field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
- field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -6581,31 +6601,6 @@
}
-package android.auditing {
-
- public class SecurityLog {
- ctor public SecurityLog();
- field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
- field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
- field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
- field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
- field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
- field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
- field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
- field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
- }
-
- public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
- method public int describeContents();
- method public java.lang.Object getData();
- method public int getTag();
- method public long getTimeNanos();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.auditing.SecurityLog.SecurityEvent> CREATOR;
- }
-
-}
-
package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
@@ -36833,6 +36828,7 @@
field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
+ field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
@@ -42597,7 +42593,7 @@
method public void onStartTemporaryDetach();
method public boolean onTouchEvent(android.view.MotionEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
- method public void onVisibilityAggregated(android.view.View, int);
+ method public void onVisibilityAggregated(boolean);
method protected void onVisibilityChanged(android.view.View, int);
method public void onWindowFocusChanged(boolean);
method public void onWindowSystemUiVisibilityChanged(int);
@@ -43694,7 +43690,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -57460,6 +57456,10 @@
method public static void parallelSort(T[], int, int);
method public static void parallelSort(T[], java.util.Comparator<? super T>);
method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+ method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+ method public static void setAll(int[], java.util.function.IntUnaryOperator);
+ method public static void setAll(long[], java.util.function.IntToLongFunction);
+ method public static void setAll(double[], java.util.function.IntToDoubleFunction);
method public static void sort(int[]);
method public static void sort(int[], int, int);
method public static void sort(long[]);
diff --git a/api/system-current.txt b/api/system-current.txt
index 32fb87f..77545c2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -654,6 +654,7 @@
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillColor = 16843780; // 0x1010404
field public static final int fillEnabled = 16843343; // 0x101024f
+ field public static final int fillType = 16844064; // 0x1010520
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -3653,7 +3654,6 @@
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public void onProvideAssistContent(android.app.assist.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public android.net.Uri onProvideReferrer();
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method protected void onRestart();
@@ -4350,7 +4350,6 @@
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPrepareOptionsMenu(android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public void onRestoreInstanceState(android.os.Bundle);
method public android.os.Bundle onSaveInstanceState();
method public boolean onSearchRequested(android.view.SearchEvent);
@@ -5991,7 +5990,6 @@
method public int getCurrentFailedPasswordAttempts();
method public deprecated java.lang.String getDeviceInitializerApp();
method public deprecated android.content.ComponentName getDeviceInitializerComponent();
- method public boolean getDeviceLoggingEnabled(android.content.ComponentName);
method public java.lang.String getDeviceOwner();
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.lang.String getDeviceOwnerNameOnAnyUser();
@@ -6047,6 +6045,7 @@
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isProfileOwnerApp(java.lang.String);
method public boolean isProvisioningAllowed(java.lang.String);
+ method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
method public void notifyPendingSystemUpdate(long);
@@ -6057,8 +6056,8 @@
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean requestBugreport(android.content.ComponentName);
method public boolean resetPassword(java.lang.String, int);
- method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrieveDeviceLogs(android.content.ComponentName);
- method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrievePreviousDeviceLogs(android.content.ComponentName);
+ method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
+ method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public deprecated boolean setActiveProfileOwner(android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException;
method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
@@ -6071,7 +6070,6 @@
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public void setDeviceLoggingEnabled(android.content.ComponentName, boolean);
method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
@@ -6104,6 +6102,7 @@
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
@@ -6198,6 +6197,27 @@
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
+ public class SecurityLog {
+ ctor public SecurityLog();
+ field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
+ field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
+ field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
+ field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+ field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
+ field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
+ field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
+ }
+
+ public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.Object getData();
+ method public int getTag();
+ method public long getTimeNanos();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
+ }
+
public class SystemUpdatePolicy implements android.os.Parcelable {
method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -6511,6 +6531,8 @@
method public long getIntervalMillis();
method public long getMaxExecutionDelayMillis();
method public long getMinLatencyMillis();
+ method public static final long getMinimumFlex();
+ method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
@@ -6524,8 +6546,6 @@
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
- field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
- field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -6848,31 +6868,6 @@
}
-package android.auditing {
-
- public class SecurityLog {
- ctor public SecurityLog();
- field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
- field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
- field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
- field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
- field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
- field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
- field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
- field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
- }
-
- public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
- method public int describeContents();
- method public java.lang.Object getData();
- method public int getTag();
- method public long getTimeNanos();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.auditing.SecurityLog.SecurityEvent> CREATOR;
- }
-
-}
-
package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
@@ -9934,6 +9929,7 @@
method public void setAppIcon(android.graphics.Bitmap);
method public void setAppLabel(java.lang.CharSequence);
method public void setAppPackageName(java.lang.String);
+ method public void setDontKillApp(boolean);
method public void setGrantedRuntimePermissions(java.lang.String[]);
method public void setInstallLocation(int);
method public void setOriginatingUid(int);
@@ -15283,7 +15279,7 @@
}
public final class ContextHubManager {
- method public java.lang.Integer[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
+ method public int[] findNanoAppOnHub(int, android.hardware.location.NanoAppFilter);
method public int[] getContextHubHandles();
method public android.hardware.location.ContextHubInfo getContextHubInfo(int);
method public android.hardware.location.NanoAppInstanceInfo getNanoAppInstanceInfo(int);
@@ -15299,8 +15295,9 @@
field public static final int MSG_UNLOAD_NANO_APP = 2; // 0x2
}
- public abstract class ContextHubManager.ContextHubCallback {
- ctor public ContextHubManager.ContextHubCallback();
+ public static abstract class ContextHubManager.ContextHubCallback {
+ ctor protected ContextHubManager.ContextHubCallback();
+ method public abstract void onMessageReceipt(int, int, android.hardware.location.ContextHubMessage);
}
public class ContextHubMessage {
@@ -39523,6 +39520,7 @@
field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
+ field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
@@ -45351,7 +45349,7 @@
method public void onStartTemporaryDetach();
method public boolean onTouchEvent(android.view.MotionEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
- method public void onVisibilityAggregated(android.view.View, int);
+ method public void onVisibilityAggregated(boolean);
method protected void onVisibilityChanged(android.view.View, int);
method public void onWindowFocusChanged(boolean);
method public void onWindowSystemUiVisibilityChanged(int);
@@ -46449,7 +46447,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -48703,12 +48701,13 @@
ctor public WebViewFactory();
method public static android.content.pm.PackageInfo getLoadedPackageInfo();
method public static java.lang.String getWebViewPackageName();
- method public static int loadWebViewNativeLibraryFromPackage(java.lang.String);
+ method public static int loadWebViewNativeLibraryFromPackage(java.lang.String, java.lang.ClassLoader);
method public static void prepareWebViewInZygote();
field public static final java.lang.String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = "persist.sys.webview.vmsize";
field public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; // 0x2
field public static final int LIBLOAD_FAILED_JNI_CALL = 7; // 0x7
field public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4; // 0x4
+ field public static final int LIBLOAD_FAILED_TO_FIND_NAMESPACE = 10; // 0xa
field public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6; // 0x6
field public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5; // 0x5
field public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3; // 0x3
@@ -60551,6 +60550,10 @@
method public static void parallelSort(T[], int, int);
method public static void parallelSort(T[], java.util.Comparator<? super T>);
method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+ method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+ method public static void setAll(int[], java.util.function.IntUnaryOperator);
+ method public static void setAll(long[], java.util.function.IntToLongFunction);
+ method public static void setAll(double[], java.util.function.IntToDoubleFunction);
method public static void sort(int[]);
method public static void sort(int[], int, int);
method public static void sort(long[]);
diff --git a/api/test-current.txt b/api/test-current.txt
index 45ef839..55d6ecd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -559,6 +559,7 @@
field public static final int fillBefore = 16843196; // 0x10101bc
field public static final int fillColor = 16843780; // 0x1010404
field public static final int fillEnabled = 16843343; // 0x101024f
+ field public static final int fillType = 16844064; // 0x1010520
field public static final int fillViewport = 16843130; // 0x101017a
field public static final int filter = 16843035; // 0x101011b
field public static final int filterTouchesWhenObscured = 16843460; // 0x10102c4
@@ -3536,7 +3537,6 @@
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
method public void onProvideAssistContent(android.app.assist.AssistContent);
method public void onProvideAssistData(android.os.Bundle);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public android.net.Uri onProvideReferrer();
method public void onRequestPermissionsResult(int, java.lang.String[], int[]);
method protected void onRestart();
@@ -4218,7 +4218,6 @@
method public void onPanelClosed(int, android.view.Menu);
method public boolean onPrepareOptionsMenu(android.view.Menu);
method public boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public void onRestoreInstanceState(android.os.Bundle);
method public android.os.Bundle onSaveInstanceState();
method public boolean onSearchRequested(android.view.SearchEvent);
@@ -5856,7 +5855,6 @@
method public boolean getCrossProfileContactsSearchDisabled(android.content.ComponentName);
method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
method public int getCurrentFailedPasswordAttempts();
- method public boolean getDeviceLoggingEnabled(android.content.ComponentName);
method public java.lang.String getDeviceOwnerLockScreenInfo();
method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -5905,6 +5903,7 @@
method public boolean isMasterVolumeMuted(android.content.ComponentName);
method public boolean isProfileOwnerApp(java.lang.String);
method public boolean isProvisioningAllowed(java.lang.String);
+ method public boolean isSecurityLoggingEnabled(android.content.ComponentName);
method public boolean isUninstallBlocked(android.content.ComponentName, java.lang.String);
method public void lockNow();
method public void reboot(android.content.ComponentName);
@@ -5914,8 +5913,8 @@
method public boolean removeUser(android.content.ComponentName, android.os.UserHandle);
method public boolean requestBugreport(android.content.ComponentName);
method public boolean resetPassword(java.lang.String, int);
- method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrieveDeviceLogs(android.content.ComponentName);
- method public java.util.List<android.auditing.SecurityLog.SecurityEvent> retrievePreviousDeviceLogs(android.content.ComponentName);
+ method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrievePreRebootSecurityLogs(android.content.ComponentName);
+ method public java.util.List<android.app.admin.SecurityLog.SecurityEvent> retrieveSecurityLogs(android.content.ComponentName);
method public void setAccountManagementDisabled(android.content.ComponentName, java.lang.String, boolean);
method public boolean setAlwaysOnVpnPackage(android.content.ComponentName, java.lang.String);
method public boolean setApplicationHidden(android.content.ComponentName, java.lang.String, boolean);
@@ -5927,7 +5926,6 @@
method public void setCertInstallerPackage(android.content.ComponentName, java.lang.String) throws java.lang.SecurityException;
method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
method public void setCrossProfileContactsSearchDisabled(android.content.ComponentName, boolean);
- method public void setDeviceLoggingEnabled(android.content.ComponentName, boolean);
method public boolean setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.String);
method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
@@ -5960,6 +5958,7 @@
method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+ method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
method public int setStorageEncryption(android.content.ComponentName, boolean);
@@ -6045,6 +6044,27 @@
field public static final int WIPE_RESET_PROTECTION_DATA = 2; // 0x2
}
+ public class SecurityLog {
+ ctor public SecurityLog();
+ field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
+ field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
+ field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
+ field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
+ field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
+ field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
+ field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
+ field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
+ }
+
+ public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
+ method public int describeContents();
+ method public java.lang.Object getData();
+ method public int getTag();
+ method public long getTimeNanos();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.app.admin.SecurityLog.SecurityEvent> CREATOR;
+ }
+
public class SystemUpdatePolicy implements android.os.Parcelable {
method public static android.app.admin.SystemUpdatePolicy createAutomaticInstallPolicy();
method public static android.app.admin.SystemUpdatePolicy createPostponeInstallPolicy();
@@ -6249,6 +6269,8 @@
method public long getIntervalMillis();
method public long getMaxExecutionDelayMillis();
method public long getMinLatencyMillis();
+ method public static final long getMinimumFlex();
+ method public static final long getMinimumPeriod();
method public int getNetworkType();
method public android.content.ComponentName getService();
method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
@@ -6262,8 +6284,6 @@
field public static final android.os.Parcelable.Creator<android.app.job.JobInfo> CREATOR;
field public static final long DEFAULT_INITIAL_BACKOFF_MILLIS = 30000L; // 0x7530L
field public static final long MAX_BACKOFF_DELAY_MILLIS = 18000000L; // 0x112a880L
- field public static final long MIN_FLEX_MILLIS = 300000L; // 0x493e0L
- field public static final long MIN_PERIOD_MILLIS = 3600000L; // 0x36ee80L
field public static final int NETWORK_TYPE_ANY = 1; // 0x1
field public static final int NETWORK_TYPE_NONE = 0; // 0x0
field public static final int NETWORK_TYPE_UNMETERED = 2; // 0x2
@@ -6585,31 +6605,6 @@
}
-package android.auditing {
-
- public class SecurityLog {
- ctor public SecurityLog();
- field public static final int TAG_ADB_SHELL_CMD = 210002; // 0x33452
- field public static final int TAG_ADB_SHELL_INTERACTIVE = 210001; // 0x33451
- field public static final int TAG_APP_PROCESS_START = 210005; // 0x33455
- field public static final int TAG_KEYGUARD_DISMISSED = 210006; // 0x33456
- field public static final int TAG_KEYGUARD_DISMISS_AUTH_ATTEMPT = 210007; // 0x33457
- field public static final int TAG_KEYGUARD_SECURED = 210008; // 0x33458
- field public static final int TAG_SYNC_RECV_FILE = 210003; // 0x33453
- field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
- }
-
- public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
- method public int describeContents();
- method public java.lang.Object getData();
- method public int getTag();
- method public long getTimeNanos();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final android.os.Parcelable.Creator<android.auditing.SecurityLog.SecurityEvent> CREATOR;
- }
-
-}
-
package android.bluetooth {
public final class BluetoothA2dp implements android.bluetooth.BluetoothProfile {
@@ -36905,6 +36900,7 @@
field public static final java.lang.String KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL = "require_entitlement_checks_bool";
field public static final java.lang.String KEY_SHOW_APN_SETTING_CDMA_BOOL = "show_apn_setting_cdma_bool";
field public static final java.lang.String KEY_SHOW_CDMA_CHOICES_BOOL = "show_cdma_choices_bool";
+ field public static final java.lang.String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
@@ -42671,7 +42667,7 @@
method public void onStartTemporaryDetach();
method public boolean onTouchEvent(android.view.MotionEvent);
method public boolean onTrackballEvent(android.view.MotionEvent);
- method public void onVisibilityAggregated(android.view.View, int);
+ method public void onVisibilityAggregated(boolean);
method protected void onVisibilityChanged(android.view.View, int);
method public void onWindowFocusChanged(boolean);
method public void onWindowSystemUiVisibilityChanged(int);
@@ -43768,7 +43764,7 @@
method public abstract boolean onMenuOpened(int, android.view.Menu);
method public abstract void onPanelClosed(int, android.view.Menu);
method public abstract boolean onPreparePanel(int, android.view.View, android.view.Menu);
- method public abstract void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
+ method public default void onProvideKeyboardShortcuts(java.util.List<android.view.KeyboardShortcutGroup>, android.view.Menu);
method public abstract boolean onSearchRequested();
method public abstract boolean onSearchRequested(android.view.SearchEvent);
method public abstract void onWindowAttributesChanged(android.view.WindowManager.LayoutParams);
@@ -57534,6 +57530,10 @@
method public static void parallelSort(T[], int, int);
method public static void parallelSort(T[], java.util.Comparator<? super T>);
method public static void parallelSort(T[], int, int, java.util.Comparator<? super T>);
+ method public static void setAll(T[], java.util.function.IntFunction<? extends T>);
+ method public static void setAll(int[], java.util.function.IntUnaryOperator);
+ method public static void setAll(long[], java.util.function.IntToLongFunction);
+ method public static void setAll(double[], java.util.function.IntToDoubleFunction);
method public static void sort(int[]);
method public static void sort(int[], int, int);
method public static void sort(long[]);
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index f178455..a6e7d67 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -710,6 +710,10 @@
/** @hide */
public ActivityOptions(Bundle opts) {
+ // If the remote side sent us bad parcelables, they won't get the
+ // results they want, which is their loss.
+ opts.setDefusable(true);
+
mPackageName = opts.getString(KEY_PACKAGE_NAME);
try {
mUsageTimeReport = opts.getParcelable(KEY_USAGE_TIME_REPORT);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index cefb22d..5ef03d1 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -2025,6 +2025,15 @@
}
@Override
+ public void flushPackageRestrictionsAsUser(int userId) {
+ try {
+ mPM.flushPackageRestrictionsAsUser(userId);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ @Override
public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
UserHandle user) {
try {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 32ace14..4fccbc9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1332,9 +1332,14 @@
}
}
try {
- return ActivityManagerNative.getDefault().registerReceiver(
+ final Intent intent = ActivityManagerNative.getDefault().registerReceiver(
mMainThread.getApplicationThread(), mBasePackageName,
rd, filter, broadcastPermission, userId);
+ if (intent != null) {
+ intent.setExtrasClassLoader(getClassLoader());
+ intent.prepareToEnterProcess();
+ }
+ return intent;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index a03fd72..c68fd65 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -913,6 +913,8 @@
mDispatcher = new WeakReference<LoadedApk.ReceiverDispatcher>(rd);
mStrongRef = strong ? rd : null;
}
+
+ @Override
public void performReceive(Intent intent, int resultCode, String data,
Bundle extras, boolean ordered, boolean sticky, int sendingUser) {
LoadedApk.ReceiverDispatcher rd = mDispatcher.get();
@@ -996,6 +998,7 @@
try {
ClassLoader cl = mReceiver.getClass().getClassLoader();
intent.setExtrasClassLoader(cl);
+ intent.prepareToEnterProcess();
setExtrasClassLoader(cl);
receiver.setPendingResult(this);
receiver.onReceive(mContext, intent);
diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java
index 3be2cdc..dd70b5d 100644
--- a/core/java/android/app/admin/DeviceAdminReceiver.java
+++ b/core/java/android/app/admin/DeviceAdminReceiver.java
@@ -268,7 +268,7 @@
"android.app.action.BUGREPORT_SHARE";
/**
- * Broadcast action: notify that a new batch of device logs is ready to be collected.
+ * Broadcast action: notify that a new batch of security logs is ready to be collected.
* @hide
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -623,13 +623,13 @@
}
/**
- * Called when a new batch of device logs can be retrieved.
+ * Called when a new batch of security logs can be retrieved.
*
* <p>This callback is only applicable to device owners.
*
* @param context The running context as per {@link #onReceive}.
* @param intent The received intent as per {@link #onReceive}.
- * @see DevicePolicyManager#retrieveDeviceLogs(ComponentName)
+ * @see DevicePolicyManager#retrieveSecurityLogs(ComponentName)
*/
public void onSecurityLogsAvailable(Context context, Intent intent) {
}
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 9094912..b7d9b80 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -25,7 +25,7 @@
import android.annotation.SystemApi;
import android.annotation.UserIdInt;
import android.app.Activity;
-import android.auditing.SecurityLog.SecurityEvent;
+import android.app.admin.SecurityLog.SecurityEvent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
@@ -5787,63 +5787,80 @@
}
/**
- * Called by device owner to control the device logging feature. Logging can only be enabled on
- * single user devices where the sole user is managed by the device owner.
- * <p>
- * Device logs contain various information intended for security auditing purposes. See
- * {@link SecurityEvent} for details.
- * <p>
- * There must be only one user on the device, managed by the device owner. Otherwise a
- * {@link SecurityException} will be thrown.
+ * Called by device owner to control the security logging feature. Logging can only be
+ * enabled on single user devices where the sole user is managed by the device owner.
+ *
+ * <p> Security logs contain various information intended for security auditing purposes.
+ * See {@link SecurityEvent} for details.
+ *
+ * <p>There must be only one user on the device, managed by the device owner.
+ * Otherwise a {@link SecurityException} will be thrown.
*
* @param admin Which device owner this request is associated with.
- * @param enabled whether device logging should be enabled or not.
+ * @param enabled whether security logging should be enabled or not.
* @throws SecurityException if {@code admin} is not a device owner.
- * @see #retrieveDeviceLogs
+ * @see #retrieveSecurityLogs
+ */
+ public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
+ try {
+ mService.setSecurityLoggingEnabled(admin, enabled);
+ } catch (RemoteException re) {
+ throw re.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Temporary // STOPSHIP TODO(mkarpinski): remove those once change to TestDPC is pushed
+ * @hide
*/
public void setDeviceLoggingEnabled(@NonNull ComponentName admin, boolean enabled) {
+ setSecurityLoggingEnabled(admin, enabled);
+ }
+
+ /**
+ * Return whether security logging is enabled or not by the device owner.
+ *
+ * <p>Can only be called by the device owner, otherwise a {@link SecurityException} will be
+ * thrown.
+ *
+ * @param admin Which device owner this request is associated with.
+ * @return {@code true} if security logging is enabled by device owner, {@code false} otherwise.
+ * @throws SecurityException if {@code admin} is not a device owner.
+ */
+ public boolean isSecurityLoggingEnabled(@NonNull ComponentName admin) {
try {
- mService.setDeviceLoggingEnabled(admin, enabled);
+ return mService.isSecurityLoggingEnabled(admin);
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
}
}
/**
- * Return whether device logging is enabled or not by the device owner.
- * <p>
- * Can only be called by the device owner, otherwise a {@link SecurityException} will be thrown.
- *
- * @param admin Which device owner this request is associated with.
- * @return {@code true} if device logging is enabled by device owner, {@code false} otherwise.
- * @throws SecurityException if {@code admin} is not a device owner.
+ * Temporary // STOPSHIP TODO(mkarpinski): remove those once change to TestDPC is pushed
+ * @hide
*/
public boolean getDeviceLoggingEnabled(@NonNull ComponentName admin) {
- try {
- return mService.getDeviceLoggingEnabled(admin);
- } catch (RemoteException re) {
- throw re.rethrowFromSystemServer();
- }
+ return isSecurityLoggingEnabled(admin);
}
/**
- * Called by device owner to retrieve all new device logging entries since the last call to this
- * API after device boots.
- * <p>
- * Access to the logs is rate limited and it will only return new logs after the device owner
- * has been notified via {@link DeviceAdminReceiver#onSecurityLogsAvailable}.
- * <p>
- * There must be only one user on the device, managed by the device owner. Otherwise a
- * {@link SecurityException} will be thrown.
+ * Called by device owner to retrieve all new security logging entries since the last call to
+ * this API after device boots.
+ *
+ * <p> Access to the logs is rate limited and it will only return new logs after the device
+ * owner has been notified via {@link DeviceAdminReceiver#onSecurityLogsAvailable}.
+ *
+ * <p>There must be only one user on the device, managed by the device owner.
+ * Otherwise a {@link SecurityException} will be thrown.
*
* @param admin Which device owner this request is associated with.
- * @return the new batch of device logs which is a list of {@link SecurityEvent}, or
- * {@code null} if rate limitation is exceeded or if logging is currently disabled.
+ * @return the new batch of security logs which is a list of {@link SecurityEvent},
+ * or {@code null} if rate limitation is exceeded or if logging is currently disabled.
* @throws SecurityException if {@code admin} is not a device owner.
*/
- public List<SecurityEvent> retrieveDeviceLogs(@NonNull ComponentName admin) {
+ public List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) {
try {
- ParceledListSlice<SecurityEvent> list = mService.retrieveDeviceLogs(admin);
+ ParceledListSlice<SecurityEvent> list = mService.retrieveSecurityLogs(admin);
if (list != null) {
return list.getList();
} else {
@@ -5856,6 +5873,14 @@
}
/**
+ * Temporary // STOPSHIP TODO(mkarpinski): remove those once change to TestDPC is pushed
+ * @hide
+ */
+ public List<SecurityEvent> retrieveDeviceLogs(@NonNull ComponentName admin) {
+ return retrieveSecurityLogs(admin);
+ }
+
+ /**
* Called by the system to obtain a {@link DevicePolicyManager} whose calls act on the parent
* profile.
*
@@ -5886,9 +5911,9 @@
* @return Device logs from before the latest reboot of the system.
* @throws SecurityException if {@code admin} is not a device owner.
*/
- public List<SecurityEvent> retrievePreviousDeviceLogs(@NonNull ComponentName admin) {
+ public List<SecurityEvent> retrievePreRebootSecurityLogs(@NonNull ComponentName admin) {
try {
- ParceledListSlice<SecurityEvent> list = mService.retrievePreviousDeviceLogs(admin);
+ ParceledListSlice<SecurityEvent> list = mService.retrievePreRebootSecurityLogs(admin);
return list.getList();
} catch (RemoteException re) {
throw re.rethrowFromSystemServer();
@@ -5896,6 +5921,14 @@
}
/**
+ * Temporary // STOPSHIP TODO(mkarpinski): remove those once change to TestDPC is pushed
+ * @hide
+ */
+ public List<SecurityEvent> retrievePreviousDeviceLogs(@NonNull ComponentName admin) {
+ return retrievePreRebootSecurityLogs(admin);
+ }
+
+ /**
* Called by a profile owner of a managed profile to set the color used for customization. This
* color is used as background color of the confirm credentials screen for that user. The
* default color is {@link android.graphics.Color#GRAY}.
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index c38496d..3ba5bd8 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -290,10 +290,10 @@
void setAffiliationIds(in ComponentName admin, in List<String> ids);
boolean isAffiliatedUser();
- void setDeviceLoggingEnabled(in ComponentName admin, boolean enabled);
- boolean getDeviceLoggingEnabled(in ComponentName admin);
- ParceledListSlice retrieveDeviceLogs(in ComponentName admin);
- ParceledListSlice retrievePreviousDeviceLogs(in ComponentName admin);
+ void setSecurityLoggingEnabled(in ComponentName admin, boolean enabled);
+ boolean isSecurityLoggingEnabled(in ComponentName admin);
+ ParceledListSlice retrieveSecurityLogs(in ComponentName admin);
+ ParceledListSlice retrievePreRebootSecurityLogs(in ComponentName admin);
boolean isUninstallInQueue(String packageName);
void uninstallPackageWithActiveAdmins(String packageName);
diff --git a/core/java/android/auditing/SecurityLog.java b/core/java/android/app/admin/SecurityLog.java
similarity index 98%
rename from core/java/android/auditing/SecurityLog.java
rename to core/java/android/app/admin/SecurityLog.java
index 13823a2..001a81d 100644
--- a/core/java/android/auditing/SecurityLog.java
+++ b/core/java/android/app/admin/SecurityLog.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.auditing;
+package android.app.admin;
import android.annotation.IntDef;
import android.os.Parcel;
@@ -92,7 +92,7 @@
public static final int TAG_KEYGUARD_SECURED = SecurityLogTags.SECURITY_KEYGUARD_SECURED;
/**
- * Returns if device logging is enabled. Log producers should only write new logs if this is
+ * Returns if security logging is enabled. Log producers should only write new logs if this is
* true. Under the hood this is the logical AND of whether device owner exists and whether
* it enables logging by setting the system property {@link #PROPERTY_LOGGING_ENABLED}.
* @hide
diff --git a/core/java/android/auditing/SecurityLogTags.logtags b/core/java/android/app/admin/SecurityLogTags.logtags
similarity index 93%
rename from core/java/android/auditing/SecurityLogTags.logtags
rename to core/java/android/app/admin/SecurityLogTags.logtags
index ccc3799..39371c7 100644
--- a/core/java/android/auditing/SecurityLogTags.logtags
+++ b/core/java/android/app/admin/SecurityLogTags.logtags
@@ -1,6 +1,6 @@
# See system/core/logcat/event.logtags for a description of the format of this file.
-option java_package android.auditing
+option java_package android.app.admin
210001 security_adb_shell_interactive
210002 security_adb_shell_command (command|3)
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index bbfec41..828ac38 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -73,9 +73,32 @@
public static final int BACKOFF_POLICY_EXPONENTIAL = 1;
/* Minimum interval for a periodic job, in milliseconds. */
- public static final long MIN_PERIOD_MILLIS = 60 * 60 * 1000L; // 60 minutes
+ private static final long MIN_PERIOD_MILLIS = 15 * 60 * 1000L; // 15 minutes
+
/* Minimum flex for a periodic job, in milliseconds. */
- public static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
+ private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
+
+ /**
+ * Query the minimum interval allowed for periodic scheduled jobs. Attempting
+ * to declare a smaller period that this when scheduling a job will result in a
+ * job that is still periodic, but will run with this effective period.
+ *
+ * @return The minimum available interval for scheduling periodic jobs, in milliseconds.
+ */
+ public static final long getMinimumPeriod() {
+ return MIN_PERIOD_MILLIS;
+ }
+
+ /**
+ * Query the minimum flex time allowed for periodic scheduled jobs. Attempting
+ * to declare a shorter flex time than this when scheduling such a job will
+ * result in this amount as the effective flex time for the job.
+ *
+ * @return The minimum available flex time for scheduling periodic jobs, in milliseconds.
+ */
+ public static final long getMinimumFlex() {
+ return MIN_FLEX_MILLIS;
+ }
/**
* Default type of backoff.
@@ -227,7 +250,7 @@
* job does not recur periodically.
*/
public long getIntervalMillis() {
- return intervalMillis >= MIN_PERIOD_MILLIS ? intervalMillis : MIN_PERIOD_MILLIS;
+ return intervalMillis >= getMinimumPeriod() ? intervalMillis : getMinimumPeriod();
}
/**
@@ -236,7 +259,7 @@
public long getFlexMillis() {
long interval = getIntervalMillis();
long percentClamp = 5 * interval / 100;
- long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, MIN_FLEX_MILLIS));
+ long clampedFlex = Math.max(flexMillis, Math.max(percentClamp, getMinimumFlex()));
return clampedFlex <= interval ? clampedFlex : interval;
}
@@ -565,9 +588,9 @@
* Specify that this job should recur with the provided interval and flex. The job can
* execute at any time in a window of flex length at the end of the period.
* @param intervalMillis Millisecond interval for which this job will repeat. A minimum
- * value of {@link #MIN_PERIOD_MILLIS} is enforced.
+ * value of {@link #getMinimumPeriod()} is enforced.
* @param flexMillis Millisecond flex for this job. Flex is clamped to be at least
- * {@link #MIN_FLEX_MILLIS} or 5 percent of the period, whichever is
+ * {@link #getMinimumFlex()} or 5 percent of the period, whichever is
* higher.
*/
public Builder setPeriodic(long intervalMillis, long flexMillis) {
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 0ec58ea..58630b0 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -836,6 +836,17 @@
}
}
+ /** {@hide} */
+ public void prepareToEnterProcess() {
+ final int size = mItems.size();
+ for (int i = 0; i < size; i++) {
+ final Item item = mItems.get(i);
+ if (item.mIntent != null) {
+ item.mIntent.prepareToEnterProcess();
+ }
+ }
+ }
+
/** @hide */
public void fixUris(int contentUserHint) {
final int size = mItems.size();
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 35dbc34..09aad3b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -6037,13 +6037,20 @@
return mExtras != null && mExtras.hasFileDescriptors();
}
- /** @hide */
+ /** {@hide} */
public void setAllowFds(boolean allowFds) {
if (mExtras != null) {
mExtras.setAllowFds(allowFds);
}
}
+ /** {@hide} */
+ public void setDefusable(boolean defusable) {
+ if (mExtras != null) {
+ mExtras.setDefusable(defusable);
+ }
+ }
+
/**
* Retrieve extended data from the intent.
*
@@ -8938,6 +8945,17 @@
* @hide
*/
public void prepareToEnterProcess() {
+ // We just entered destination process, so we should be able to read all
+ // parcelables inside.
+ setDefusable(true);
+
+ if (mSelector != null) {
+ mSelector.prepareToEnterProcess();
+ }
+ if (mClipData != null) {
+ mClipData.prepareToEnterProcess();
+ }
+
if (mContentUserHint != UserHandle.USER_CURRENT) {
if (UserHandle.getAppId(Process.myUid()) != Process.SYSTEM_UID) {
fixUris(mContentUserHint);
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c684447..dabc652 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -291,6 +291,8 @@
*/
ComponentName getHomeActivities(out List<ResolveInfo> outHomeCandidates);
+ void setHomeActivity(in ComponentName className, int userId);
+
/**
* As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.
*/
@@ -314,6 +316,11 @@
int getApplicationEnabledSetting(in String packageName, int userId);
/**
+ * As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}.
+ */
+ void flushPackageRestrictionsAsUser(in int userId);
+
+ /**
* Set whether the given package should be considered stopped, making
* it not visible to implicit intents that filter out stopped packages.
*/
@@ -535,5 +542,4 @@
boolean isPackageDeviceAdminOnAnyUser(String packageName);
List<String> getPreviousCodePaths(in String packageName);
-
}
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 6f2786a..ed8143e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -37,7 +37,6 @@
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.ExceptionUtils;
-import android.util.Log;
import com.android.internal.util.IndentingPrintWriter;
@@ -47,7 +46,6 @@
import java.io.OutputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -393,13 +391,6 @@
* Return list of all known install sessions, regardless of the installer.
*/
public @NonNull List<SessionInfo> getAllSessions() {
- final ApplicationInfo info = mContext.getApplicationInfo();
- if ("com.google.android.googlequicksearchbox".equals(info.packageName)
- && info.versionCode <= 300400110) {
- Log.d(TAG, "Ignoring callback request from old prebuilt");
- return Collections.EMPTY_LIST;
- }
-
try {
return mInstaller.getAllSessions(mUserId).getList();
} catch (RemoteException e) {
@@ -597,14 +588,6 @@
* calling thread.
*/
public void registerSessionCallback(@NonNull SessionCallback callback, @NonNull Handler handler) {
- // TODO: remove this temporary guard once we have new prebuilts
- final ApplicationInfo info = mContext.getApplicationInfo();
- if ("com.google.android.googlequicksearchbox".equals(info.packageName)
- && info.versionCode <= 300400110) {
- Log.d(TAG, "Ignoring callback request from old prebuilt");
- return;
- }
-
synchronized (mDelegates) {
final SessionCallbackDelegate delegate = new SessionCallbackDelegate(callback,
handler.getLooper());
@@ -1074,8 +1057,13 @@
}
/** {@hide} */
- public void setInstallFlagsDontKillApp() {
- installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
+ @SystemApi
+ public void setDontKillApp(boolean dontKillApp) {
+ if (dontKillApp) {
+ installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
+ } else {
+ installFlags &= ~PackageManager.INSTALL_DONT_KILL_APP;
+ }
}
/** {@hide} */
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c1017fb..c179596 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -5225,7 +5225,6 @@
public abstract void setComponentEnabledSetting(ComponentName componentName,
int newState, int flags);
-
/**
* Return the enabled setting for a package component (activity,
* receiver, service, provider). This returns the last value set by
@@ -5283,6 +5282,16 @@
public abstract int getApplicationEnabledSetting(String packageName);
/**
+ * Flush the package restrictions for a given user to disk. This forces the package restrictions
+ * like component and package enabled settings to be written to disk and avoids the delay that
+ * is otherwise present when changing those settings.
+ *
+ * @param userId Ther userId of the user whose restrictions are to be flushed.
+ * @hide
+ */
+ public abstract void flushPackageRestrictionsAsUser(int userId);
+
+ /**
* Puts the package in a hidden state, which is almost like an uninstalled state,
* making the package unavailable, but it doesn't remove the data or the actual
* package file. Application can be unhidden by either resetting the hidden state
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index 6cc7fec..dfa19b0 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -1196,7 +1196,7 @@
*
* <p>In particular these formats are converted:
* <ul>
- * <li>ImageFormat.JPEG => HAL_DATASPACE_JFIF
+ * <li>ImageFormat.JPEG => HAL_DATASPACE_V0_JFIF
* <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_DATASPACE_DEPTH
* <li>ImageFormat.DEPTH16 => HAL_DATASPACE_DEPTH
* <li>others => HAL_DATASPACE_UNKNOWN
@@ -1223,7 +1223,7 @@
static int imageFormatToDataspace(int format) {
switch (format) {
case ImageFormat.JPEG:
- return HAL_DATASPACE_JFIF;
+ return HAL_DATASPACE_V0_JFIF;
case ImageFormat.DEPTH_POINT_CLOUD:
case ImageFormat.DEPTH16:
return HAL_DATASPACE_DEPTH;
@@ -1633,8 +1633,16 @@
private static final int HAL_PIXEL_FORMAT_Y16 = 0x20363159;
+ private static final int HAL_DATASPACE_STANDARD_SHIFT = 16;
+ private static final int HAL_DATASPACE_TRANSFER_SHIFT = 22;
+ private static final int HAL_DATASPACE_RANGE_SHIFT = 27;
+
private static final int HAL_DATASPACE_UNKNOWN = 0x0;
- private static final int HAL_DATASPACE_JFIF = 0x101;
+ private static final int HAL_DATASPACE_V0_JFIF =
+ (2 << HAL_DATASPACE_STANDARD_SHIFT) |
+ (3 << HAL_DATASPACE_TRANSFER_SHIFT) |
+ (1 << HAL_DATASPACE_RANGE_SHIFT);
+
private static final int HAL_DATASPACE_DEPTH = 0x1000;
private static final long DURATION_20FPS_NS = 50000000L;
diff --git a/core/java/android/hardware/location/ContextHubManager.java b/core/java/android/hardware/location/ContextHubManager.java
index 38a760a..8deded2 100644
--- a/core/java/android/hardware/location/ContextHubManager.java
+++ b/core/java/android/hardware/location/ContextHubManager.java
@@ -15,13 +15,8 @@
*/
package android.hardware.location;
-import android.Manifest;
import android.annotation.SystemApi;
-import android.content.ComponentName;
import android.content.Context;
-import android.content.ServiceConnection;
-import android.hardware.location.ContextHubService;
-import android.hardware.location.NanoAppInstanceInfo;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
@@ -29,19 +24,11 @@
import android.os.ServiceManager;
import android.util.Log;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
/**
- * A class that exposes the Context hubs on a device to
- * applicaions.
+ * A class that exposes the Context hubs on a device to applications.
*
- * Please not that this class is not expected to be used by
- * unbundled applications. Also, calling applications are
- * expected to have LOCTION_HARDWARE premissions to use this
- * class.
+ * Please note that this class is not expected to be used by unbundled applications. Also, calling
+ * applications are expected to have LOCATION_HARDWARE permissions to use this class.
*
* @hide
*/
@@ -49,21 +36,14 @@
public final class ContextHubManager {
private static final String TAG = "ContextHubManager";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
- private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
- private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
- + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
- private final Context mContext;
private final Looper mMainLooper;
private IContextHubService mContextHubService;
- private boolean mContextHubConnected;
private ContextHubCallback mCallback;
private Handler mCallbackHandler;
/**
- * A special context hub identifer meaning any possible hub on
- * the system.
+ * A special context hub identifier meaning any possible hub on the system.
*/
public static final int ANY_HUB = -1;
/**
@@ -80,19 +60,24 @@
public static final int MSG_DATA_SEND = 3;
/**
- * an interface to receive asynchronous communication from the context hub
+ * An interface to receive asynchronous communication from the context hub.
*/
- public abstract class ContextHubCallback {
+ public abstract static class ContextHubCallback {
+ protected ContextHubCallback() {}
+
/**
- * callback function called on message receipt from context hub
+ * Callback function called on message receipt from context hub.
*
- * @param hubId id of the hub of the message
- * @param nanoAppId identifier for the app that sent the message
- * @param msg the context hub message
+ * @param hubHandle Handle (system-wide unique identifier) of the hub of the message.
+ * @param nanoAppHandle Handle (unique identifier) for the app that sent the message.
+ * @param message The context hub message.
*
* @see ContextHubMessage
*/
- abstract void onMessageReceipt(int hubId, int nanoAppId, ContextHubMessage msg);
+ public abstract void onMessageReceipt(
+ int hubHandle,
+ int nanoAppHandle,
+ ContextHubMessage message);
}
/**
@@ -104,7 +89,7 @@
try {
retVal = getBinder().getContextHubHandles();
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch context hub handles :" + e.toString());
+ Log.e(TAG, "Could not fetch context hub handles : " + e);
}
return retVal;
}
@@ -112,25 +97,24 @@
/**
* Get more information about a specific hub.
*
- * @param contexthubHandle Handle of context hub
- *
- * @return ContextHubInfo returned information about the hub
+ * @param hubHandle Handle (system-wide unique identifier) of a context hub.
+ * @return ContextHubInfo Information about the requested context hub.
*
* @see ContextHubInfo
*/
- public ContextHubInfo getContextHubInfo(int contexthubHandle) {
+ public ContextHubInfo getContextHubInfo(int hubHandle) {
ContextHubInfo retVal = null;
try {
- retVal = getBinder().getContextHubInfo(contexthubHandle);
+ retVal = getBinder().getContextHubInfo(hubHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch context hub info :" + e.toString());
+ Log.e(TAG, "Could not fetch context hub info :" + e);
}
return retVal;
}
/**
- * Load a nanoapp on a specified context hub
+ * Load a nano app on a specified context hub.
*
* @param hubHandle handle of context hub to load the app on.
* @param app the nanoApp to load on the hub
@@ -149,7 +133,7 @@
try {
retVal = getBinder().loadNanoApp(hubHandle, app);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch load nanoApp :" + e.toString());
+ Log.e(TAG, "Could not fetch load nanoApp :" + e);
}
return retVal;
@@ -158,17 +142,17 @@
/**
* Unload a specified nanoApp
*
- * @param nanoAppInstanceHandle handle of the nanoApp to load
+ * @param nanoAppHandle handle of the nanoApp to load
*
- * @return int 0 on success, -1 otherewise
+ * @return int 0 on success, -1 otherwise
*/
- public int unloadNanoApp(int nanoAppInstanceHandle) {
+ public int unloadNanoApp(int nanoAppHandle) {
int retVal = -1;
try {
- retVal = getBinder().unloadNanoApp(nanoAppInstanceHandle);
+ retVal = getBinder().unloadNanoApp(nanoAppHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch unload nanoApp :" + e.toString());
+ Log.e(TAG, "Could not fetch unload nanoApp :" + e);
}
return retVal;
@@ -177,20 +161,18 @@
/**
* get information about the nano app instance
*
- * @param nanoAppInstanceHandle handle of the nanoAppInstance
- *
- * @return NanoAppInstanceInfo Inforamtion about the nano app
- * instance.
+ * @param nanoAppHandle handle of the nanoAppInstance
+ * @return NanoAppInstanceInfo Information about the nano app instance.
*
* @see NanoAppInstanceInfo
*/
- public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) {
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppHandle) {
NanoAppInstanceInfo retVal = null;
try {
- retVal = getBinder().getNanoAppInstanceInfo(nanoAppInstanceHandle);
+ retVal = getBinder().getNanoAppInstanceInfo(nanoAppHandle);
} catch (RemoteException e) {
- Log.e(TAG, "Could not fetch nanoApp info :" + e.toString());
+ Log.e(TAG, "Could not fetch nanoApp info :" + e);
}
return retVal;
@@ -204,33 +186,24 @@
*
* @see NanoAppFilter
*
- * @return Integer[] Array of handles to any found nano apps
+ * @return int[] Array of handles to any found nano apps
*/
- public Integer[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
- int[] temp;
- Integer[] retVal = null;
-
+ public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) {
+ int[] retVal = null;
try {
- temp = getBinder().findNanoAppOnHub(hubHandle, filter);
- retVal = new Integer[temp.length];
- for (int i = 0; i < temp.length; i++) {
- retVal[i] = temp[i];
- }
+ retVal = getBinder().findNanoAppOnHub(hubHandle, filter);
} catch (RemoteException e) {
- Log.e(TAG, "Could not query nanoApp instance :" + e.toString());
+ Log.e(TAG, "Could not query nanoApp instance :" + e);
}
-
return retVal;
}
/**
- * Send a message to a spcific nano app instance on a context
- * hub
- *
+ * Send a message to a specific nano app instance on a context hub.
*
* @param hubHandle handle of the hub to send the message to
* @param nanoAppHandle handle of the nano app to send to
- * @param msg Message to be sent
+ * @param message Message to be sent
*
* @see ContextHubMessage
*
@@ -251,7 +224,6 @@
/**
* Set a callback to receive messages from the context hub
*
- *
* @param callback Callback object
*
* @see ContextHubCallback
@@ -265,9 +237,8 @@
/**
* Set a callback to receive messages from the context hub
*
- *
* @param callback Callback object
- * @param hander Hander object
+ * @param handler Handler object
*
* @see ContextHubCallback
*
@@ -286,8 +257,7 @@
}
/**
- * Unregister a callback for receive messages from the context
- * hub
+ * Unregister a callback for receive messages from the context hub.
*
* @see ContextHubCallback
*
@@ -308,14 +278,10 @@
return 0;
}
- private void checkPermissions() {
- mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
- }
-
private IContextHubCallback.Stub mClientCallback = new IContextHubCallback.Stub() {
@Override
public void onMessageReceipt(final int hubId, final int nanoAppId,
- final ContextHubMessage message) throws RemoteException {
+ final ContextHubMessage message) {
if (mCallback != null) {
synchronized(this) {
final ContextHubCallback callback = mCallback;
@@ -336,8 +302,6 @@
/** @hide */
public ContextHubManager(Context context, Looper mainLooper) {
- checkPermissions();
- mContext = context;
mMainLooper = mainLooper;
IBinder b = ServiceManager.getService(ContextHubService.CONTEXTHUB_SERVICE);
@@ -347,7 +311,7 @@
try {
getBinder().registerCallback(mClientCallback);
} catch (RemoteException e) {
- Log.e(TAG, "Could not register callback:" + e.toString());
+ Log.e(TAG, "Could not register callback:" + e);
}
} else {
diff --git a/core/java/android/hardware/location/ContextHubService.java b/core/java/android/hardware/location/ContextHubService.java
index 658d90b..274babe 100644
--- a/core/java/android/hardware/location/ContextHubService.java
+++ b/core/java/android/hardware/location/ContextHubService.java
@@ -16,10 +16,8 @@
package android.hardware.location;
-import android.app.Service;
+import android.Manifest;
import android.content.Context;
-import android.content.Intent;
-import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
@@ -32,6 +30,9 @@
public class ContextHubService extends IContextHubService.Stub {
private static final String TAG = "ContextHubService";
+ private static final String HARDWARE_PERMISSION = Manifest.permission.LOCATION_HARDWARE;
+ private static final String ENFORCE_HW_PERMISSION_MESSAGE = "Permission '"
+ + HARDWARE_PERMISSION + "' not granted to access ContextHub Hardware";
public static final String CONTEXTHUB_SERVICE = "contexthub_service";
@@ -56,6 +57,7 @@
@Override
public int registerCallback(IContextHubCallback callback) throws RemoteException{
+ checkPermissions();
mCallback = callback;
return 0;
}
@@ -83,6 +85,7 @@
@Override
public int[] getContextHubHandles() throws RemoteException {
+ checkPermissions();
int [] returnArray = new int[mContextHubInfo.length];
for (int i = 0; i < returnArray.length; ++i) {
@@ -96,6 +99,7 @@
@Override
public ContextHubInfo getContextHubInfo(int contextHubHandle) throws RemoteException {
+ checkPermissions();
contextHubHandle -= 1;
if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
return null; // null means fail
@@ -106,6 +110,7 @@
@Override
public int loadNanoApp(int contextHubHandle, NanoApp app) throws RemoteException {
+ checkPermissions();
contextHubHandle -= 1;
if (!(contextHubHandle >= 0 && contextHubHandle < mContextHubInfo.length)) {
@@ -123,11 +128,12 @@
return nativeSendMessage(msgHeader, app.getAppBinary());
}
- @Override
- public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+ @Override
+ public int unloadNanoApp(int nanoAppInstanceHandle) throws RemoteException {
+ checkPermissions();
NanoAppInstanceInfo info = mNanoAppHash.get(nanoAppInstanceHandle);
if (info == null) {
- return -1; //means failed
+ return -1; //means failed
}
// Call Native interface here
@@ -137,10 +143,12 @@
msgHeader[2] = info.getHandle();
return nativeSendMessage(msgHeader, null);
- }
+ }
@Override
- public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle) throws RemoteException {
+ public NanoAppInstanceInfo getNanoAppInstanceInfo(int nanoAppInstanceHandle)
+ throws RemoteException {
+ checkPermissions();
// This assumes that all the nanoAppInfo is current. This is reasonable
// for the use cases for tightly controlled nanoApps.
if (mNanoAppHash.containsKey(nanoAppInstanceHandle)) {
@@ -152,6 +160,7 @@
@Override
public int[] findNanoAppOnHub(int hubHandle, NanoAppFilter filter) throws RemoteException {
+ checkPermissions();
ArrayList<Integer> foundInstances = new ArrayList<Integer>();
for(Integer nanoAppInstance : mNanoAppHash.keySet()) {
@@ -171,7 +180,9 @@
}
@Override
- public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg) throws RemoteException {
+ public int sendMessage(int hubHandle, int nanoAppHandle, ContextHubMessage msg)
+ throws RemoteException {
+ checkPermissions();
int[] msgHeader = new int[8];
msgHeader[0] = ContextHubManager.MSG_DATA_SEND;
msgHeader[1] = hubHandle;
@@ -181,5 +192,9 @@
return nativeSendMessage(msgHeader, msg.getData());
}
+
+ private void checkPermissions() {
+ mContext.enforceCallingPermission(HARDWARE_PERMISSION, ENFORCE_HW_PERMISSION_MESSAGE);
+ }
}
diff --git a/core/java/android/os/BadParcelableException.java b/core/java/android/os/BadParcelableException.java
index a1c5bb2..7e0b1a5 100644
--- a/core/java/android/os/BadParcelableException.java
+++ b/core/java/android/os/BadParcelableException.java
@@ -15,11 +15,15 @@
*/
package android.os;
+
import android.util.AndroidRuntimeException;
/**
- * The object you are calling has died, because its hosting process
- * no longer exists.
+ * Exception thrown when a {@link Parcelable} is malformed or otherwise invalid.
+ * <p>
+ * This is typically encountered when a custom {@link Parcelable} object is
+ * passed to another process that doesn't have the same {@link Parcelable} class
+ * in its {@link ClassLoader}.
*/
public class BadParcelableException extends AndroidRuntimeException {
public BadParcelableException(String msg) {
diff --git a/core/java/android/os/BaseBundle.java b/core/java/android/os/BaseBundle.java
index 5c71373..6e50155 100644
--- a/core/java/android/os/BaseBundle.java
+++ b/core/java/android/os/BaseBundle.java
@@ -26,7 +26,9 @@
import java.util.Set;
/**
- * A mapping from String values to various types.
+ * A mapping from String keys to values of various types. In most cases, you
+ * should work directly with either the {@link Bundle} or
+ * {@link PersistableBundle} subclass.
*/
public class BaseBundle {
private static final String TAG = "Bundle";
@@ -35,6 +37,32 @@
// Keep in sync with frameworks/native/libs/binder/PersistableBundle.cpp.
static final int BUNDLE_MAGIC = 0x4C444E42; // 'B' 'N' 'D' 'L'
+ /**
+ * Flag indicating that this Bundle is okay to "defuse." That is, it's okay
+ * for system processes to ignore any {@link BadParcelableException}
+ * encountered when unparceling it, leaving an empty bundle in its place.
+ * <p>
+ * This should <em>only</em> be set when the Bundle reaches its final
+ * destination, otherwise a system process may clobber contents that were
+ * destined for an app that could have unparceled them.
+ */
+ static final int FLAG_DEFUSABLE = 1 << 0;
+
+ private static volatile boolean sShouldDefuse = false;
+
+ /**
+ * Set global variable indicating that any Bundles parsed in this process
+ * should be "defused." That is, any {@link BadParcelableException}
+ * encountered will be suppressed and logged, leaving an empty Bundle
+ * instead of crashing.
+ *
+ * @hide
+ */
+ public static void setShouldDefuse(boolean shouldDefuse) {
+ sShouldDefuse = shouldDefuse;
+ }
+
+ /** {@hide} */
static final Parcel EMPTY_PARCEL;
static {
@@ -58,6 +86,9 @@
*/
private ClassLoader mClassLoader;
+ /** {@hide} */
+ int mFlags;
+
/**
* Constructs a new, empty Bundle that uses a specific ClassLoader for
* instantiating Parcelable and Serializable objects.
@@ -197,6 +228,11 @@
return;
}
+ if (sShouldDefuse && (mFlags & FLAG_DEFUSABLE) == 0) {
+ Log.wtf(TAG, "Attempting to unparcel a Bundle while in transit; this may "
+ + "clobber all data inside!", new Throwable());
+ }
+
if (mParcelledData == EMPTY_PARCEL) {
if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ ": empty");
@@ -221,9 +257,19 @@
mMap.erase();
mMap.ensureCapacity(N);
}
- mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
- mParcelledData.recycle();
- mParcelledData = null;
+ try {
+ mParcelledData.readArrayMapInternal(mMap, N, mClassLoader);
+ } catch (BadParcelableException e) {
+ if (sShouldDefuse) {
+ Log.w(TAG, "Failed to parse Bundle, but defusing quietly", e);
+ mMap.erase();
+ } else {
+ throw e;
+ }
+ } finally {
+ mParcelledData.recycle();
+ mParcelledData = null;
+ }
if (DEBUG) Log.d(TAG, "unparcel " + Integer.toHexString(System.identityHashCode(this))
+ " final map: " + mMap);
}
@@ -1371,9 +1417,8 @@
return;
}
- int magic = parcel.readInt();
+ final int magic = parcel.readInt();
if (magic != BUNDLE_MAGIC) {
- //noinspection ThrowableInstanceNeverThrown
throw new IllegalStateException("Bad magic number for Bundle: 0x"
+ Integer.toHexString(magic));
}
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index 74699fd..1097cad 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -27,11 +27,17 @@
import java.util.List;
/**
- * A mapping from String values to various Parcelable types.
+ * A mapping from String keys to various {@link Parcelable} values.
*
+ * @see PersistableBundle
*/
public final class Bundle extends BaseBundle implements Cloneable, Parcelable {
+ private static final int FLAG_HAS_FDS = 1 << 8;
+ private static final int FLAG_HAS_FDS_KNOWN = 1 << 9;
+ private static final int FLAG_ALLOW_FDS = 1 << 10;
+
public static final Bundle EMPTY;
+
static final Parcel EMPTY_PARCEL;
static {
@@ -40,15 +46,12 @@
EMPTY_PARCEL = BaseBundle.EMPTY_PARCEL;
}
- private boolean mHasFds = false;
- private boolean mFdsKnown = true;
- private boolean mAllowFds = true;
-
/**
* Constructs a new, empty Bundle.
*/
public Bundle() {
super();
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -59,16 +62,18 @@
*/
Bundle(Parcel parcelledData) {
super(parcelledData);
-
- mHasFds = mParcelledData.hasFileDescriptors();
- mFdsKnown = true;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+ if (mParcelledData.hasFileDescriptors()) {
+ mFlags |= FLAG_HAS_FDS;
+ }
}
/* package */ Bundle(Parcel parcelledData, int length) {
super(parcelledData, length);
-
- mHasFds = mParcelledData.hasFileDescriptors();
- mFdsKnown = true;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+ if (mParcelledData.hasFileDescriptors()) {
+ mFlags |= FLAG_HAS_FDS;
+ }
}
/**
@@ -80,6 +85,7 @@
*/
public Bundle(ClassLoader loader) {
super(loader);
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -90,6 +96,7 @@
*/
public Bundle(int capacity) {
super(capacity);
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -100,9 +107,7 @@
*/
public Bundle(Bundle b) {
super(b);
-
- mHasFds = b.mHasFds;
- mFdsKnown = b.mFdsKnown;
+ mFlags = b.mFlags;
}
/**
@@ -113,6 +118,7 @@
*/
public Bundle(PersistableBundle b) {
super(b);
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -145,14 +151,37 @@
return super.getClassLoader();
}
- /** @hide */
+ /** {@hide} */
public boolean setAllowFds(boolean allowFds) {
- boolean orig = mAllowFds;
- mAllowFds = allowFds;
+ final boolean orig = (mFlags & FLAG_ALLOW_FDS) != 0;
+ if (allowFds) {
+ mFlags |= FLAG_ALLOW_FDS;
+ } else {
+ mFlags &= ~FLAG_ALLOW_FDS;
+ }
return orig;
}
/**
+ * Mark if this Bundle is okay to "defuse." That is, it's okay for system
+ * processes to ignore any {@link BadParcelableException} encountered when
+ * unparceling it, leaving an empty bundle in its place.
+ * <p>
+ * This should <em>only</em> be set when the Bundle reaches its final
+ * destination, otherwise a system process may clobber contents that were
+ * destined for an app that could have unparceled them.
+ *
+ * @hide
+ */
+ public void setDefusable(boolean defusable) {
+ if (defusable) {
+ mFlags |= FLAG_DEFUSABLE;
+ } else {
+ mFlags &= ~FLAG_DEFUSABLE;
+ }
+ }
+
+ /**
* Clones the current Bundle. The internal map is cloned, but the keys and
* values to which it refers are copied by reference.
*/
@@ -167,9 +196,7 @@
@Override
public void clear() {
super.clear();
-
- mHasFds = false;
- mFdsKnown = true;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -182,16 +209,20 @@
bundle.unparcel();
mMap.putAll(bundle.mMap);
- // fd state is now known if and only if both bundles already knew
- mHasFds |= bundle.mHasFds;
- mFdsKnown = mFdsKnown && bundle.mFdsKnown;
+ // FD state is now known if and only if both bundles already knew
+ if ((bundle.mFlags & FLAG_HAS_FDS) != 0) {
+ mFlags |= FLAG_HAS_FDS;
+ }
+ if ((bundle.mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
+ mFlags &= ~FLAG_HAS_FDS_KNOWN;
+ }
}
/**
* Reports whether the bundle contains any parcelled file descriptors.
*/
public boolean hasFileDescriptors() {
- if (!mFdsKnown) {
+ if ((mFlags & FLAG_HAS_FDS_KNOWN) == 0) {
boolean fdFound = false; // keep going until we find one or run out of data
if (mParcelledData != null) {
@@ -247,10 +278,12 @@
}
}
- mHasFds = fdFound;
- mFdsKnown = true;
+ if (fdFound) {
+ mFlags |= FLAG_HAS_FDS;
+ }
+ mFlags |= FLAG_HAS_FDS_KNOWN;
}
- return mHasFds;
+ return (mFlags & FLAG_HAS_FDS) != 0;
}
/**
@@ -346,7 +379,7 @@
public void putParcelable(@Nullable String key, @Nullable Parcelable value) {
unparcel();
mMap.put(key, value);
- mFdsKnown = false;
+ mFlags &= ~FLAG_HAS_FDS_KNOWN;
}
/**
@@ -384,7 +417,7 @@
public void putParcelableArray(@Nullable String key, @Nullable Parcelable[] value) {
unparcel();
mMap.put(key, value);
- mFdsKnown = false;
+ mFlags &= ~FLAG_HAS_FDS_KNOWN;
}
/**
@@ -399,14 +432,14 @@
@Nullable ArrayList<? extends Parcelable> value) {
unparcel();
mMap.put(key, value);
- mFdsKnown = false;
+ mFlags &= ~FLAG_HAS_FDS_KNOWN;
}
/** {@hide} */
public void putParcelableList(String key, List<? extends Parcelable> value) {
unparcel();
mMap.put(key, value);
- mFdsKnown = false;
+ mFlags &= ~FLAG_HAS_FDS_KNOWN;
}
/**
@@ -421,7 +454,7 @@
@Nullable SparseArray<? extends Parcelable> value) {
unparcel();
mMap.put(key, value);
- mFdsKnown = false;
+ mFlags &= ~FLAG_HAS_FDS_KNOWN;
}
/**
@@ -1074,7 +1107,7 @@
*/
@Override
public void writeToParcel(Parcel parcel, int flags) {
- final boolean oldAllowFds = parcel.pushAllowFds(mAllowFds);
+ final boolean oldAllowFds = parcel.pushAllowFds((mFlags & FLAG_ALLOW_FDS) != 0);
try {
super.writeToParcelInner(parcel, flags);
} finally {
@@ -1089,8 +1122,10 @@
*/
public void readFromParcel(Parcel parcel) {
super.readFromParcelInner(parcel);
- mHasFds = mParcelledData.hasFileDescriptors();
- mFdsKnown = true;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
+ if (mParcelledData.hasFileDescriptors()) {
+ mFlags |= FLAG_HAS_FDS;
+ }
}
@Override
@@ -1105,5 +1140,4 @@
}
return "Bundle[" + mMap.toString() + "]";
}
-
}
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 1b79497..dd73e53 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -605,6 +605,30 @@
*/
public static File buildUniqueFile(File parent, String mimeType, String displayName)
throws FileNotFoundException {
+ final String[] parts = splitFileName(mimeType, displayName);
+ final String name = parts[0];
+ final String ext = parts[1];
+ File file = buildFile(parent, name, ext);
+
+ // If conflicting file, try adding counter suffix
+ int n = 0;
+ while (file.exists()) {
+ if (n++ >= 32) {
+ throw new FileNotFoundException("Failed to create unique file");
+ }
+ file = buildFile(parent, name + " (" + n + ")", ext);
+ }
+
+ return file;
+ }
+
+ /**
+ * Splits file name into base name and extension.
+ * If the display name doesn't have an extension that matches the requested MIME type, the
+ * extension is regarded as a part of filename and default extension for that MIME type is
+ * appended.
+ */
+ public static String[] splitFileName(String mimeType, String displayName) {
String name;
String ext;
@@ -642,18 +666,11 @@
}
}
- File file = buildFile(parent, name, ext);
-
- // If conflicting file, try adding counter suffix
- int n = 0;
- while (file.exists()) {
- if (n++ >= 32) {
- throw new FileNotFoundException("Failed to create unique file");
- }
- file = buildFile(parent, name + " (" + n + ")", ext);
+ if (ext == null) {
+ ext = "";
}
- return file;
+ return new String[] { name, ext };
}
private static File buildFile(File parent, String name, String ext) {
diff --git a/core/java/android/os/PersistableBundle.java b/core/java/android/os/PersistableBundle.java
index 5872f74..b947c97 100644
--- a/core/java/android/os/PersistableBundle.java
+++ b/core/java/android/os/PersistableBundle.java
@@ -18,7 +18,9 @@
import android.annotation.Nullable;
import android.util.ArrayMap;
+
import com.android.internal.util.XmlUtils;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -26,9 +28,11 @@
import java.io.IOException;
/**
- * A mapping from String values to various types that can be saved to persistent and later
- * restored.
+ * A mapping from String keys to values of various types. The set of types
+ * supported by this class is purposefully restricted to simple objects that can
+ * safely be persisted to and restored from disk.
*
+ * @see Bundle
*/
public final class PersistableBundle extends BaseBundle implements Cloneable, Parcelable,
XmlUtils.WriteMapCallback {
@@ -57,6 +61,7 @@
*/
public PersistableBundle() {
super();
+ mFlags = FLAG_DEFUSABLE;
}
/**
@@ -67,6 +72,7 @@
*/
public PersistableBundle(int capacity) {
super(capacity);
+ mFlags = FLAG_DEFUSABLE;
}
/**
@@ -77,6 +83,7 @@
*/
public PersistableBundle(PersistableBundle b) {
super(b);
+ mFlags = b.mFlags;
}
@@ -101,6 +108,7 @@
*/
private PersistableBundle(ArrayMap<String, Object> map) {
super();
+ mFlags = FLAG_DEFUSABLE;
// First stuff everything in.
putAll(map);
@@ -123,6 +131,7 @@
/* package */ PersistableBundle(Parcel parcelledData, int length) {
super(parcelledData, length);
+ mFlags = FLAG_DEFUSABLE;
}
/**
@@ -278,5 +287,4 @@
}
return "PersistableBundle[" + mMap.toString() + "]";
}
-
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 136abab..5fc2899 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2093,7 +2093,7 @@
*/
public static void clearConfiguration(Configuration inoutConfig) {
inoutConfig.fontScale = 0;
- if (!inoutConfig.userSetLocale) {
+ if (!inoutConfig.userSetLocale && !inoutConfig.getLocales().isEmpty()) {
inoutConfig.setLocales(LocaleList.getEmptyLocaleList());
}
}
@@ -2708,24 +2708,6 @@
public static final String VOLUME_MASTER = "volume_master";
/**
- * Master volume mute (int 1 = mute, 0 = not muted).
- *
- * @hide
- */
- public static final String VOLUME_MASTER_MUTE = "volume_master_mute";
-
- private static final Validator VOLUME_MASTER_MUTE_VALIDATOR = sBooleanValidator;
-
- /**
- * Microphone mute (int 1 = mute, 0 = not muted).
- *
- * @hide
- */
- public static final String MICROPHONE_MUTE = "microphone_mute";
-
- private static final Validator MICROPHONE_MUTE_VALIDATOR = sBooleanValidator;
-
- /**
* Master mono (int 1 = mono, 0 = normal).
*
* @hide
@@ -3515,8 +3497,6 @@
PRIVATE_SETTINGS.add(SCREEN_AUTO_BRIGHTNESS_ADJ);
PRIVATE_SETTINGS.add(VIBRATE_INPUT_DEVICES);
PRIVATE_SETTINGS.add(VOLUME_MASTER);
- PRIVATE_SETTINGS.add(VOLUME_MASTER_MUTE);
- PRIVATE_SETTINGS.add(MICROPHONE_MUTE);
PRIVATE_SETTINGS.add(MASTER_MONO);
PRIVATE_SETTINGS.add(NOTIFICATIONS_USE_RING_VOLUME);
PRIVATE_SETTINGS.add(VIBRATE_IN_SILENT);
@@ -3594,8 +3574,6 @@
VALIDATORS.put(ADVANCED_SETTINGS, ADVANCED_SETTINGS_VALIDATOR);
VALIDATORS.put(SCREEN_AUTO_BRIGHTNESS_ADJ, SCREEN_AUTO_BRIGHTNESS_ADJ_VALIDATOR);
VALIDATORS.put(VIBRATE_INPUT_DEVICES, VIBRATE_INPUT_DEVICES_VALIDATOR);
- VALIDATORS.put(VOLUME_MASTER_MUTE, VOLUME_MASTER_MUTE_VALIDATOR);
- VALIDATORS.put(MICROPHONE_MUTE, MICROPHONE_MUTE_VALIDATOR);
VALIDATORS.put(MASTER_MONO, MASTER_MONO_VALIDATOR);
VALIDATORS.put(NOTIFICATIONS_USE_RING_VOLUME, NOTIFICATIONS_USE_RING_VOLUME_VALIDATOR);
VALIDATORS.put(VIBRATE_IN_SILENT, VIBRATE_IN_SILENT_VALIDATOR);
diff --git a/core/java/android/speech/tts/AudioPlaybackQueueItem.java b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
index d4fea53..ed7534d 100644
--- a/core/java/android/speech/tts/AudioPlaybackQueueItem.java
+++ b/core/java/android/speech/tts/AudioPlaybackQueueItem.java
@@ -16,7 +16,7 @@
package android.speech.tts;
import android.content.Context;
-import android.media.AudioSystem;
+import android.media.AudioManager;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.ConditionVariable;
@@ -57,7 +57,7 @@
int sessionId = mAudioParams.mSessionId;
mPlayer = MediaPlayer.create(
mContext, mUri, null, mAudioParams.mAudioAttributes,
- sessionId > 0 ? sessionId : AudioSystem.AUDIO_SESSION_ALLOCATE);
+ sessionId > 0 ? sessionId : AudioManager.AUDIO_SESSION_ID_GENERATE);
if (mPlayer == null) {
dispatcher.dispatchOnError(TextToSpeech.ERROR_OUTPUT);
return;
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index fc075de..1eaa7cf 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -19,7 +19,7 @@
import android.app.Service;
import android.content.Intent;
import android.media.AudioAttributes;
-import android.media.AudioSystem;
+import android.media.AudioManager;
import android.net.Uri;
import android.os.Binder;
import android.os.Bundle;
@@ -659,7 +659,7 @@
/**
* Audio session identifier. May be used to associate audio playback with one of the
* {@link android.media.audiofx.AudioEffect} objects. If not specified by client,
- * it should be equal to {@link AudioSystem#AUDIO_SESSION_ALLOCATE}.
+ * it should be equal to {@link AudioManager#AUDIO_SESSION_ID_GENERATE}.
*/
public final int mSessionId;
@@ -684,7 +684,7 @@
/** Create AudioOutputParams with default values */
AudioOutputParams() {
- mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
+ mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
mVolume = Engine.DEFAULT_VOLUME;
mPan = Engine.DEFAULT_PAN;
mAudioAttributes = null;
@@ -722,7 +722,7 @@
return new AudioOutputParams(
paramsBundle.getInt(
Engine.KEY_PARAM_SESSION_ID,
- AudioSystem.AUDIO_SESSION_ALLOCATE),
+ AudioManager.AUDIO_SESSION_ID_GENERATE),
paramsBundle.getFloat(
Engine.KEY_PARAM_VOLUME,
Engine.DEFAULT_VOLUME),
diff --git a/core/java/android/text/BoringLayout.java b/core/java/android/text/BoringLayout.java
index bfe5c3f..a1bc2d1 100644
--- a/core/java/android/text/BoringLayout.java
+++ b/core/java/android/text/BoringLayout.java
@@ -247,23 +247,22 @@
*/
public static Metrics isBoring(CharSequence text, TextPaint paint,
TextDirectionHeuristic textDir, Metrics metrics) {
- char[] temp = TextUtils.obtain(500);
- int length = text.length();
+ final int MAX_BUF_LEN = 500;
+ final char[] buffer = TextUtils.obtain(MAX_BUF_LEN);
+ final int textLength = text.length();
boolean boring = true;
outer:
- for (int i = 0; i < length; i += 500) {
- int j = i + 500;
+ for (int start = 0; start < textLength; start += MAX_BUF_LEN) {
+ final int end = Math.min(start + MAX_BUF_LEN, textLength);
- if (j > length)
- j = length;
+ // No need to worry about getting half codepoints, since we reject surrogate code units
+ // as non-boring as soon we see one.
+ TextUtils.getChars(text, start, end, buffer, 0);
- TextUtils.getChars(text, i, j, temp, 0);
-
- int n = j - i;
-
- for (int a = 0; a < n; a++) {
- char c = temp[a];
+ final int len = end - start;
+ for (int i = 0; i < len; i++) {
+ final char c = buffer[i];
if (c == '\n' || c == '\t' ||
(c >= 0x0590 && c <= 0x08FF) || // RTL scripts
@@ -279,17 +278,19 @@
}
}
- if (textDir != null && textDir.isRtl(temp, 0, n)) {
+ // TODO: This looks a little suspicious, and in some cases can result in O(n^2)
+ // run time. Consider moving outside the loop.
+ if (textDir != null && textDir.isRtl(buffer, 0, len)) {
boring = false;
break outer;
}
}
- TextUtils.recycle(temp);
+ TextUtils.recycle(buffer);
if (boring && text instanceof Spanned) {
Spanned sp = (Spanned) text;
- Object[] styles = sp.getSpans(0, length, ParagraphStyle.class);
+ Object[] styles = sp.getSpans(0, textLength, ParagraphStyle.class);
if (styles.length > 0) {
boring = false;
}
@@ -302,7 +303,7 @@
}
TextLine line = TextLine.obtain();
- line.set(paint, text, 0, length, Layout.DIR_LEFT_TO_RIGHT,
+ line.set(paint, text, 0, textLength, Layout.DIR_LEFT_TO_RIGHT,
Layout.DIRS_ALL_LEFT_TO_RIGHT, false, null);
fm.width = (int) Math.ceil(line.metrics(fm));
TextLine.recycle(line);
diff --git a/core/java/android/text/style/TtsSpan.java b/core/java/android/text/style/TtsSpan.java
index 93a156b..e9153dd 100644
--- a/core/java/android/text/style/TtsSpan.java
+++ b/core/java/android/text/style/TtsSpan.java
@@ -1013,7 +1013,7 @@
* @return This instance.
*/
public MeasureBuilder setIntegerPart(long integerPart) {
- return setNumber(String.valueOf(integerPart));
+ return setIntegerPart(String.valueOf(integerPart));
}
/**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 55393b1..a7bf73a 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10210,44 +10210,38 @@
* ViewGroup. Intended to only be called when {@link #isAttachedToWindow()},
* {@link #getWindowVisibility()} is {@link #VISIBLE} and this view's parent {@link #isShown()}.
*
- * @param changedView the view that changed, either <code>this</code> or an ancestor
- * @param visibility aggregated visibility of this view's parent or changedView, whichever
- * is closer
- * @return the aggregated visibility for this view
+ * @param isVisible true if this view's visibility to the user is uninterrupted by its
+ * ancestors or by window visibility
+ * @return true if this view is visible to the user, not counting clipping or overlapping
*/
- int dispatchVisibilityAggregated(View changedView, @Visibility int visibility) {
- visibility = Math.max(visibility, getVisibility());
- onVisibilityAggregated(changedView, visibility);
- return visibility;
+ @Visibility boolean dispatchVisibilityAggregated(boolean isVisible) {
+ final boolean thisVisible = getVisibility() == VISIBLE;
+ if (thisVisible) {
+ onVisibilityAggregated(isVisible);
+ }
+ return thisVisible && isVisible;
}
/**
* Called when the user-visibility of this View is potentially affected by a change
* to this view itself, an ancestor view or the window this view is attached to.
*
- * <p>The visibility value reported will be one of {@link #VISIBLE}, {@link #INVISIBLE}
- * or {@link #GONE}, reflecting this view's aggregated visibility within its window.
- * The visibility parameter takes this view's own visibility into account.
- * Calls to this method may be repeated with the same visibility values; implementations
- * should ensure that work done is not duplicated unnecessarily.</p>
- *
- * @param changedView the view that changed; may be <code>this</code> or an ancestor
- * @param visibility the visibility of this view in the context of the full window
+ * @param isVisible true if this view and all of its ancestors are {@link #VISIBLE}
+ * and this view's window is also visible
*/
@CallSuper
- public void onVisibilityAggregated(View changedView, @Visibility int visibility) {
- final boolean visible = visibility == VISIBLE && getVisibility() == VISIBLE;
- if (visible && mAttachInfo != null) {
+ public void onVisibilityAggregated(boolean isVisible) {
+ if (isVisible && mAttachInfo != null) {
initialAwakenScrollBars();
}
final Drawable dr = mBackground;
- if (dr != null && visible != dr.isVisible()) {
- dr.setVisible(visible, false);
+ if (dr != null && isVisible != dr.isVisible()) {
+ dr.setVisible(isVisible, false);
}
final Drawable fg = mForegroundInfo != null ? mForegroundInfo.mDrawable : null;
- if (fg != null && visible != fg.isVisible()) {
- fg.setVisible(visible, false);
+ if (fg != null && isVisible != fg.isVisible()) {
+ fg.setVisible(isVisible, false);
}
}
@@ -11376,7 +11370,7 @@
// to change animation states.
if (mParent != null && getWindowVisibility() == VISIBLE &&
((!(mParent instanceof ViewGroup)) || ((ViewGroup) mParent).isShown())) {
- dispatchVisibilityAggregated(this, newVisibility);
+ dispatchVisibilityAggregated(newVisibility == VISIBLE);
}
notifySubtreeAccessibilityStateChangedIfNeeded();
}
@@ -15289,7 +15283,9 @@
if (vis != GONE) {
onWindowVisibilityChanged(vis);
if (isShown()) {
- onVisibilityAggregated(this, vis);
+ // Calling onVisibilityChanged directly here since the subtree will also
+ // receive dispatchAttachedToWindow and this same call
+ onVisibilityAggregated(vis == VISIBLE);
}
}
@@ -15312,7 +15308,9 @@
if (vis != GONE) {
onWindowVisibilityChanged(GONE);
if (isShown()) {
- onVisibilityAggregated(this, GONE);
+ // Invoking onVisibilityAggregated directly here since the subtree
+ // will also receive detached from window
+ onVisibilityAggregated(false);
}
}
}
@@ -18001,12 +17999,14 @@
/*
* Regardless of whether we're setting a new background or not, we want
- * to clear the previous drawable.
+ * to clear the previous drawable. setVisible first while we still have the callback set.
*/
if (mBackground != null) {
+ if (isAttachedToWindow()) {
+ mBackground.setVisible(false, false);
+ }
mBackground.setCallback(null);
unscheduleDrawable(mBackground);
- mBackground.setVisible(false, false);
}
if (background != null) {
@@ -18043,12 +18043,19 @@
requestLayout = true;
}
+ // Set mBackground before we set this as the callback and start making other
+ // background drawable state change calls. In particular, the setVisible call below
+ // can result in drawables attempting to start animations or otherwise invalidate,
+ // which requires the view set as the callback (us) to recognize the drawable as
+ // belonging to it as per verifyDrawable.
+ mBackground = background;
background.setCallback(this);
if (background.isStateful()) {
background.setState(getDrawableState());
}
- background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
- mBackground = background;
+ if (isAttachedToWindow()) {
+ background.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
+ }
applyBackgroundTint();
@@ -18227,9 +18234,11 @@
}
if (mForegroundInfo.mDrawable != null) {
+ if (isAttachedToWindow()) {
+ mForegroundInfo.mDrawable.setVisible(false, false);
+ }
mForegroundInfo.mDrawable.setCallback(null);
unscheduleDrawable(mForegroundInfo.mDrawable);
- mForegroundInfo.mDrawable.setVisible(false, false);
}
mForegroundInfo.mDrawable = foreground;
@@ -18244,7 +18253,9 @@
foreground.setState(getDrawableState());
}
applyForegroundTint();
- foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
+ if (isAttachedToWindow()) {
+ foreground.setVisible(getWindowVisibility() == VISIBLE && isShown(), false);
+ }
} else if ((mViewFlags & WILL_NOT_DRAW) != 0 && mBackground == null) {
mPrivateFlags |= PFLAG_SKIP_DRAW;
}
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 36a5db1..aa11e3f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1291,20 +1291,19 @@
}
@Override
- int dispatchVisibilityAggregated(View changedView, @Visibility int visibility) {
- visibility = super.dispatchVisibilityAggregated(changedView, visibility);
+ boolean dispatchVisibilityAggregated(boolean isVisible) {
+ isVisible = super.dispatchVisibilityAggregated(isVisible);
final int count = mChildrenCount;
final View[] children = mChildren;
for (int i = 0; i < count; i++) {
- // Only dispatch to children with at least the same level of visibility
- // that we're reporting, otherwise it won't affect that child/subtree at all
- // so it's not worth telling them about it. Note that we use <= here
- // because VISIBLE < INVISIBLE < GONE as constant values.
- if (children[i].getVisibility() <= visibility) {
- children[i].dispatchVisibilityAggregated(changedView, visibility);
+ // Only dispatch to visible children. Not visible children and their subtrees already
+ // know that they aren't visible and that's not going to change as a result of
+ // whatever triggered this dispatch.
+ if (children[i].getVisibility() == VISIBLE) {
+ children[i].dispatchVisibilityAggregated(isVisible);
}
}
- return visibility;
+ return isVisible;
}
@Override
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fecf892..a2295ce 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1472,7 +1472,7 @@
if (viewVisibilityChanged) {
mAttachInfo.mWindowVisibility = viewVisibility;
host.dispatchWindowVisibilityChanged(viewVisibility);
- host.dispatchVisibilityAggregated(host, viewVisibility);
+ host.dispatchVisibilityAggregated(viewVisibility == View.VISIBLE);
if (viewVisibility != View.VISIBLE || mNewSurfaceNeeded) {
endDragResizing();
destroyHardwareResources();
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 9f05990..63f3744 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -566,8 +566,8 @@
* @param data The data list to populate with shortcuts.
* @param menu The current menu, which may be null.
*/
- public void onProvideKeyboardShortcuts(
- List<KeyboardShortcutGroup> data, @Nullable Menu menu);
+ default public void onProvideKeyboardShortcuts(
+ List<KeyboardShortcutGroup> data, @Nullable Menu menu) { };
}
/** @hide */
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index a1cbc1d..887cc3a 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -170,7 +170,7 @@
sWindowManagerService = getWindowManagerService();
ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
} catch (RemoteException e) {
- Log.e(TAG, "Failed to get WindowManagerService, cannot set animator scale", e);
+ throw e.rethrowFromSystemServer();
}
}
return sWindowManagerService;
@@ -192,7 +192,7 @@
},
imm.getClient(), imm.getInputContext());
} catch (RemoteException e) {
- Log.e(TAG, "Failed to open window session", e);
+ throw e.rethrowFromSystemServer();
}
}
return sWindowSession;
diff --git a/core/java/android/view/textservice/SpellCheckerSubtype.java b/core/java/android/view/textservice/SpellCheckerSubtype.java
index df33698..35d3bf9 100644
--- a/core/java/android/view/textservice/SpellCheckerSubtype.java
+++ b/core/java/android/view/textservice/SpellCheckerSubtype.java
@@ -50,7 +50,10 @@
private static final String TAG = SpellCheckerSubtype.class.getSimpleName();
private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
private static final String EXTRA_VALUE_KEY_VALUE_SEPARATOR = "=";
- private static final int SUBTYPE_ID_NONE = 0;
+ /**
+ * @hide
+ */
+ public static final int SUBTYPE_ID_NONE = 0;
private static final String SUBTYPE_LANGUAGE_TAG_NONE = "";
private final int mSubtypeId;
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 3d72260..0751ab0 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -106,6 +106,9 @@
public static final int LIBLOAD_WEBVIEW_BEING_REPLACED = 8;
public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 9;
+ // error for namespace lookup
+ public static final int LIBLOAD_FAILED_TO_FIND_NAMESPACE = 10;
+
private static String getWebViewPreparationErrorReason(int error) {
switch (error) {
case LIBLOAD_FAILED_WAITING_FOR_RELRO:
@@ -239,7 +242,8 @@
* Load the native library for the given package name iff that package
* name is the same as the one providing the webview.
*/
- public static int loadWebViewNativeLibraryFromPackage(String packageName) {
+ public static int loadWebViewNativeLibraryFromPackage(String packageName,
+ ClassLoader clazzLoader) {
int ret = waitForProviderAndSetPackageInfo();
if (ret != LIBLOAD_SUCCESS) {
return ret;
@@ -247,7 +251,7 @@
if (!sPackageInfo.packageName.equals(packageName))
return LIBLOAD_WRONG_PACKAGE_NAME;
- return loadNativeLibrary();
+ return loadNativeLibrary(clazzLoader);
}
static WebViewFactoryProvider getProvider() {
@@ -333,15 +337,16 @@
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
}
- Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
- loadNativeLibrary();
- Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
-
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
try {
initialApplication.getAssets().addAssetPathAsSharedLibrary(
webViewContext.getApplicationInfo().sourceDir);
ClassLoader clazzLoader = webViewContext.getClassLoader();
+
+ Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
+ loadNativeLibrary(clazzLoader);
+ Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
try {
return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
@@ -633,7 +638,7 @@
}
// Assumes that we have waited for relro creation and set sPackageInfo
- private static int loadNativeLibrary() {
+ private static int loadNativeLibrary(ClassLoader clazzLoader) {
if (!sAddressSpaceReserved) {
Log.e(LOGTAG, "can't load with relro file; address space not reserved");
return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
@@ -641,9 +646,10 @@
String[] args = getWebViewNativeLibraryPaths(sPackageInfo);
int result = nativeLoadWithRelroFile(args[0] /* path32 */,
- args[1] /* path64 */,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+ args[1] /* path64 */,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_64,
+ clazzLoader);
if (result != LIBLOAD_SUCCESS) {
Log.w(LOGTAG, "failed to load with relro file, proceeding without");
} else if (DEBUG) {
@@ -672,5 +678,6 @@
private static native boolean nativeCreateRelroFile(String lib32, String lib64,
String relro32, String relro64);
private static native int nativeLoadWithRelroFile(String lib32, String lib64,
- String relro32, String relro64);
+ String relro32, String relro64,
+ ClassLoader clazzLoader);
}
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index 1321221..6d7313d 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -1644,7 +1644,7 @@
boolean handled = false;
int action = event.getAction();
if (KeyEvent.isConfirmKey(keyCode)
- && event.hasNoModifiers() && action == KeyEvent.ACTION_UP) {
+ && event.hasNoModifiers() && action != KeyEvent.ACTION_UP) {
handled = resurrectSelectionIfNeeded();
if (!handled && event.getRepeatCount() == 0 && getChildCount() > 0) {
keyPressed();
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index 71b5ce9..04d344f 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -1501,10 +1501,10 @@
}
@Override
- public void onVisibilityAggregated(View changedView, @Visibility int visibility) {
- super.onVisibilityAggregated(changedView, visibility);
+ public void onVisibilityAggregated(boolean isVisible) {
+ super.onVisibilityAggregated(isVisible);
if (mDrawable != null) {
- mDrawable.setVisible(visibility == VISIBLE, false);
+ mDrawable.setVisible(isVisible, false);
}
}
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index dd0f91e..e9fa26c 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -617,6 +617,7 @@
private void swapCurrentDrawable(Drawable newDrawable) {
final Drawable oldDrawable = mCurrentDrawable;
mCurrentDrawable = newDrawable;
+
if (oldDrawable != mCurrentDrawable) {
if (oldDrawable != null) {
oldDrawable.setVisible(false, false);
@@ -1645,10 +1646,9 @@
}
@Override
- public void onVisibilityAggregated(View changedView, @Visibility int visibility) {
- super.onVisibilityAggregated(changedView, visibility);
+ public void onVisibilityAggregated(boolean isVisible) {
+ super.onVisibilityAggregated(isVisible);
- final boolean isVisible = visibility == VISIBLE;
if (isVisible != mAggregatedIsVisible) {
mAggregatedIsVisible = isVisible;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index fbedbda..8a1a8c5 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6552,7 +6552,7 @@
if (TextUtils.equals(content.subSequence(start, end), text.text)) {
if (text.text instanceof Spanned) {
// OK to copy spans only.
- TextUtils.copySpansFrom((Spanned) text.text, start, end,
+ TextUtils.copySpansFrom((Spanned) text.text, 0, end - start,
Object.class, content, start);
}
} else {
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 90ee05e..9461ce6 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -854,7 +854,8 @@
private final HashMap<String, String> mCopyOnWriteDataStore = new HashMap<>();
private boolean mCopyOnWrite = false;
- private String mEnabledInputMethodsStrCache;
+ @NonNull
+ private String mEnabledInputMethodsStrCache = "";
@UserIdInt
private int mCurrentUserId;
private int[] mCurrentProfileIds = new int[0];
@@ -949,7 +950,7 @@
// TODO: mCurrentProfileIds should be updated here.
}
- private void putString(final String key, final String str) {
+ private void putString(@NonNull final String key, @Nullable final String str) {
if (mCopyOnWrite) {
mCopyOnWriteDataStore.put(key, str);
} else {
@@ -957,12 +958,15 @@
}
}
- private String getString(final String key) {
+ @Nullable
+ private String getString(@NonNull final String key, @Nullable final String defaultValue) {
+ final String result;
if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
- final String result = mCopyOnWriteDataStore.get(key);
- return result != null ? result : "";
+ result = mCopyOnWriteDataStore.get(key);
+ } else {
+ result = Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
}
- return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
+ return result != null ? result : defaultValue;
}
private void putInt(final String key, final int value) {
@@ -1124,16 +1128,24 @@
return res;
}
- private void putEnabledInputMethodsStr(String str) {
+ private void putEnabledInputMethodsStr(@Nullable String str) {
if (DEBUG) {
Slog.d(TAG, "putEnabledInputMethodStr: " + str);
}
- putString(Settings.Secure.ENABLED_INPUT_METHODS, str);
- mEnabledInputMethodsStrCache = str;
+ if (TextUtils.isEmpty(str)) {
+ // OK to coalesce to null, since getEnabledInputMethodsStr() can take care of the
+ // empty data scenario.
+ putString(Settings.Secure.ENABLED_INPUT_METHODS, null);
+ } else {
+ putString(Settings.Secure.ENABLED_INPUT_METHODS, str);
+ }
+ // TODO: Update callers of putEnabledInputMethodsStr to make str @NonNull.
+ mEnabledInputMethodsStrCache = (str != null ? str : "");
}
+ @NonNull
public String getEnabledInputMethodsStr() {
- mEnabledInputMethodsStrCache = getString(Settings.Secure.ENABLED_INPUT_METHODS);
+ mEnabledInputMethodsStrCache = getString(Settings.Secure.ENABLED_INPUT_METHODS, "");
if (DEBUG) {
Slog.d(TAG, "getEnabledInputMethodsStr: " + mEnabledInputMethodsStrCache
+ ", " + mCurrentUserId);
@@ -1187,11 +1199,17 @@
saveSubtypeHistory(subtypeHistory, imeId, subtypeId);
}
- private void putSubtypeHistoryStr(String str) {
+ private void putSubtypeHistoryStr(@NonNull String str) {
if (DEBUG) {
Slog.d(TAG, "putSubtypeHistoryStr: " + str);
}
- putString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str);
+ if (TextUtils.isEmpty(str)) {
+ // OK to coalesce to null, since getSubtypeHistoryStr() can take care of the empty
+ // data scenario.
+ putString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, null);
+ } else {
+ putString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, str);
+ }
}
public Pair<String, String> getLastInputMethodAndSubtypeLocked() {
@@ -1308,8 +1326,9 @@
return imsList;
}
+ @NonNull
private String getSubtypeHistoryStr() {
- final String history = getString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY);
+ final String history = getString(Settings.Secure.INPUT_METHODS_SUBTYPE_HISTORY, "");
if (DEBUG) {
Slog.d(TAG, "getSubtypeHistoryStr: " + history);
}
@@ -1332,8 +1351,9 @@
putInt(Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE, subtypeId);
}
+ @Nullable
public String getSelectedInputMethod() {
- final String imi = getString(Settings.Secure.DEFAULT_INPUT_METHOD);
+ final String imi = getString(Settings.Secure.DEFAULT_INPUT_METHOD, null);
if (DEBUG) {
Slog.d(TAG, "getSelectedInputMethodStr: " + imi);
}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index df48d6d..fbd8fb5 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -2073,11 +2073,7 @@
public void requestKeyboardShortcuts(List<KeyboardShortcutGroup> list) {
final PanelFeatureState st = mWindow.getPanelState(FEATURE_OPTIONS_PANEL, false);
if (!mWindow.isDestroyed() && st != null && mWindow.getCallback() != null) {
- try {
- mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu);
- } catch (AbstractMethodError e) {
- // We run into this if the app is using supportlib.
- }
+ mWindow.getCallback().onProvideKeyboardShortcuts(list, st.menu);
}
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 8ef1a22..c6db0ed 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -36,7 +36,7 @@
android_app_Activity.cpp \
android_app_ApplicationLoaders.cpp \
android_app_NativeActivity.cpp \
- android_auditing_SecurityLog.cpp \
+ android_app_admin_SecurityLog.cpp \
android_opengl_EGL14.cpp \
android_opengl_EGLExt.cpp \
android_opengl_GLES10.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 95323f7..7ff38fd5 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -109,7 +109,7 @@
* JNI-based registration functions. Note these are properly contained in
* namespace android.
*/
-extern int register_android_auditing_SecurityLog(JNIEnv* env);
+extern int register_android_app_admin_SecurityLog(JNIEnv* env);
extern int register_android_content_AssetManager(JNIEnv* env);
extern int register_android_util_EventLog(JNIEnv* env);
extern int register_android_util_Log(JNIEnv* env);
@@ -1253,7 +1253,7 @@
REG_JNI(register_android_util_EventLog),
REG_JNI(register_android_util_Log),
REG_JNI(register_android_util_PathParser),
- REG_JNI(register_android_auditing_SecurityLog),
+ REG_JNI(register_android_app_admin_SecurityLog),
REG_JNI(register_android_content_AssetManager),
REG_JNI(register_android_content_StringBlock),
REG_JNI(register_android_content_XmlBlock),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index fb9b1e5..4001283 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -73,6 +73,9 @@
case SkEncodedFormat::kWBMP_SkEncodedFormat:
mimeType = "image/vnd.wap.wbmp";
break;
+ case SkEncodedFormat::kRAW_SkEncodedFormat:
+ mimeType = "image/x-adobe-dng";
+ break;
default:
mimeType = nullptr;
break;
diff --git a/core/jni/android_app_admin_SecurityLog.cpp b/core/jni/android_app_admin_SecurityLog.cpp
new file mode 100644
index 0000000..da47c4c
--- /dev/null
+++ b/core/jni/android_app_admin_SecurityLog.cpp
@@ -0,0 +1,312 @@
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#include <fcntl.h>
+
+#include "JNIHelp.h"
+#include "core_jni_helpers.h"
+#include "jni.h"
+#include "log/logger.h"
+
+// The size of the tag number comes out of the payload size.
+#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
+
+namespace android {
+
+static jclass gCollectionClass;
+static jmethodID gCollectionAddID;
+
+static jclass gEventClass;
+static jmethodID gEventInitID;
+
+static jclass gIntegerClass;
+static jfieldID gIntegerValueID;
+
+static jclass gLongClass;
+static jfieldID gLongValueID;
+
+static jclass gFloatClass;
+static jfieldID gFloatValueID;
+
+static jclass gStringClass;
+
+
+static jboolean android_app_admin_SecurityLog_isLoggingEnabled(JNIEnv* env,
+ jobject /* clazz */) {
+ return (bool)__android_log_security();
+}
+
+static jint android_app_admin_SecurityLog_writeEvent_String(JNIEnv* env,
+ jobject /* clazz */,
+ jint tag, jstring value) {
+ uint8_t buf[MAX_EVENT_PAYLOAD];
+
+ // Don't throw NPE -- I feel like it's sort of mean for a logging function
+ // to be all crashy if you pass in NULL -- but make the NULL value explicit.
+ const char *str = value != NULL ? env->GetStringUTFChars(value, NULL) : "NULL";
+ uint32_t len = strlen(str);
+ size_t max = sizeof(buf) - sizeof(len) - 2; // Type byte, final newline
+ if (len > max) len = max;
+
+ buf[0] = EVENT_TYPE_STRING;
+ memcpy(&buf[1], &len, sizeof(len));
+ memcpy(&buf[1 + sizeof(len)], str, len);
+ buf[1 + sizeof(len) + len] = '\n';
+
+ if (value != NULL) env->ReleaseStringUTFChars(value, str);
+ return __android_log_security_bwrite(tag, buf, 2 + sizeof(len) + len);
+}
+
+static jint android_app_admin_SecurityLog_writeEvent_Array(JNIEnv* env, jobject clazz,
+ jint tag, jobjectArray value) {
+ if (value == NULL) {
+ return android_app_admin_SecurityLog_writeEvent_String(env, clazz, tag, NULL);
+ }
+
+ uint8_t buf[MAX_EVENT_PAYLOAD];
+ const size_t max = sizeof(buf) - 1; // leave room for final newline
+ size_t pos = 2; // Save room for type tag & array count
+
+ jsize copied = 0, num = env->GetArrayLength(value);
+ for (; copied < num && copied < 255; ++copied) {
+ jobject item = env->GetObjectArrayElement(value, copied);
+ if (item == NULL || env->IsInstanceOf(item, gStringClass)) {
+ if (pos + 1 + sizeof(jint) > max) break;
+ const char *str = item != NULL ? env->GetStringUTFChars((jstring) item, NULL) : "NULL";
+ jint len = strlen(str);
+ if (pos + 1 + sizeof(len) + len > max) len = max - pos - 1 - sizeof(len);
+ buf[pos++] = EVENT_TYPE_STRING;
+ memcpy(&buf[pos], &len, sizeof(len));
+ memcpy(&buf[pos + sizeof(len)], str, len);
+ pos += sizeof(len) + len;
+ if (item != NULL) env->ReleaseStringUTFChars((jstring) item, str);
+ } else if (env->IsInstanceOf(item, gIntegerClass)) {
+ jint intVal = env->GetIntField(item, gIntegerValueID);
+ if (pos + 1 + sizeof(intVal) > max) break;
+ buf[pos++] = EVENT_TYPE_INT;
+ memcpy(&buf[pos], &intVal, sizeof(intVal));
+ pos += sizeof(intVal);
+ } else if (env->IsInstanceOf(item, gLongClass)) {
+ jlong longVal = env->GetLongField(item, gLongValueID);
+ if (pos + 1 + sizeof(longVal) > max) break;
+ buf[pos++] = EVENT_TYPE_LONG;
+ memcpy(&buf[pos], &longVal, sizeof(longVal));
+ pos += sizeof(longVal);
+ } else if (env->IsInstanceOf(item, gFloatClass)) {
+ jfloat floatVal = env->GetFloatField(item, gFloatValueID);
+ if (pos + 1 + sizeof(floatVal) > max) break;
+ buf[pos++] = EVENT_TYPE_FLOAT;
+ memcpy(&buf[pos], &floatVal, sizeof(floatVal));
+ pos += sizeof(floatVal);
+ } else {
+ jniThrowException(env,
+ "java/lang/IllegalArgumentException",
+ "Invalid payload item type");
+ return -1;
+ }
+ env->DeleteLocalRef(item);
+ }
+
+ buf[0] = EVENT_TYPE_LIST;
+ buf[1] = copied;
+ buf[pos++] = '\n';
+ return __android_log_security_bwrite(tag, buf, pos);
+}
+
+static void readEvents(JNIEnv* env, int loggerMode, jlong startTime, jobject out) {
+ struct logger_list *logger_list;
+ if (startTime) {
+ logger_list = android_logger_list_alloc_time(loggerMode,
+ log_time(startTime / NS_PER_SEC, startTime % NS_PER_SEC), 0);
+ } else {
+ logger_list = android_logger_list_alloc(loggerMode, 0, 0);
+ }
+ if (!logger_list) {
+ jniThrowIOException(env, errno);
+ return;
+ }
+
+ if (!android_logger_open(logger_list, LOG_ID_SECURITY)) {
+ jniThrowIOException(env, errno);
+ android_logger_list_free(logger_list);
+ return;
+ }
+
+ while (1) {
+ log_msg log_msg;
+ int ret = android_logger_list_read(logger_list, &log_msg);
+
+ if (ret == 0) {
+ break;
+ }
+ if (ret < 0) {
+ if (ret == -EINTR) {
+ continue;
+ }
+ if (ret == -EINVAL) {
+ jniThrowException(env, "java/io/IOException", "Event too short");
+ } else if (ret != -EAGAIN) {
+ jniThrowIOException(env, -ret); // Will throw on return
+ }
+ break;
+ }
+
+ if (log_msg.id() != LOG_ID_SECURITY) {
+ continue;
+ }
+
+ jsize len = ret;
+ jbyteArray array = env->NewByteArray(len);
+ if (array == NULL) {
+ break;
+ }
+
+ jbyte *bytes = env->GetByteArrayElements(array, NULL);
+ memcpy(bytes, log_msg.buf, len);
+ env->ReleaseByteArrayElements(array, bytes, 0);
+
+ jobject event = env->NewObject(gEventClass, gEventInitID, array);
+ if (event == NULL) {
+ break;
+ }
+
+ env->CallBooleanMethod(out, gCollectionAddID, event);
+ env->DeleteLocalRef(event);
+ env->DeleteLocalRef(array);
+ }
+
+ android_logger_list_close(logger_list);
+}
+
+static void android_app_admin_SecurityLog_readEvents(JNIEnv* env, jobject /* clazz */,
+ jobject out) {
+
+ if (out == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return;
+ }
+ readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, out);
+}
+
+static void android_app_admin_SecurityLog_readEventsSince(JNIEnv* env, jobject /* clazz */,
+ jlong timestamp,
+ jobject out) {
+
+ if (out == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return;
+ }
+ readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, timestamp, out);
+}
+
+static void android_app_admin_SecurityLog_readPreviousEvents(JNIEnv* env, jobject /* clazz */,
+ jobject out) {
+
+ if (out == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return;
+ }
+ readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_PSTORE, 0, out);
+}
+
+static void android_app_admin_SecurityLog_readEventsOnWrapping(JNIEnv* env, jobject /* clazz */,
+ jlong timestamp,
+ jobject out) {
+ if (out == NULL) {
+ jniThrowNullPointerException(env, NULL);
+ return;
+ }
+ readEvents(env, ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK | ANDROID_LOG_WRAP, timestamp, out);
+}
+
+/*
+ * JNI registration.
+ */
+static const JNINativeMethod gRegisterMethods[] = {
+ /* name, signature, funcPtr */
+ { "isLoggingEnabled",
+ "()Z",
+ (void*) android_app_admin_SecurityLog_isLoggingEnabled
+ },
+ { "writeEvent",
+ "(ILjava/lang/String;)I",
+ (void*) android_app_admin_SecurityLog_writeEvent_String
+ },
+ { "writeEvent",
+ "(I[Ljava/lang/Object;)I",
+ (void*) android_app_admin_SecurityLog_writeEvent_Array
+ },
+ { "readEvents",
+ "(Ljava/util/Collection;)V",
+ (void*) android_app_admin_SecurityLog_readEvents
+ },
+ { "readEventsSince",
+ "(JLjava/util/Collection;)V",
+ (void*) android_app_admin_SecurityLog_readEventsSince
+ },
+ { "readPreviousEvents",
+ "(Ljava/util/Collection;)V",
+ (void*) android_app_admin_SecurityLog_readPreviousEvents
+ },
+ { "readEventsOnWrapping",
+ "(JLjava/util/Collection;)V",
+ (void*) android_app_admin_SecurityLog_readEventsOnWrapping
+ },
+};
+
+static struct { const char *name; jclass *clazz; } gClasses[] = {
+ { "android/app/admin/SecurityLog$SecurityEvent", &gEventClass },
+ { "java/lang/Integer", &gIntegerClass },
+ { "java/lang/Long", &gLongClass },
+ { "java/lang/Float", &gFloatClass },
+ { "java/lang/String", &gStringClass },
+ { "java/util/Collection", &gCollectionClass },
+};
+
+static struct { jclass *c; const char *name, *ft; jfieldID *id; } gFields[] = {
+ { &gIntegerClass, "value", "I", &gIntegerValueID },
+ { &gLongClass, "value", "J", &gLongValueID },
+ { &gFloatClass, "value", "F", &gFloatValueID },
+};
+
+static struct { jclass *c; const char *name, *mt; jmethodID *id; } gMethods[] = {
+ { &gEventClass, "<init>", "([B)V", &gEventInitID },
+ { &gCollectionClass, "add", "(Ljava/lang/Object;)Z", &gCollectionAddID },
+};
+
+int register_android_app_admin_SecurityLog(JNIEnv* env) {
+ for (int i = 0; i < NELEM(gClasses); ++i) {
+ jclass clazz = FindClassOrDie(env, gClasses[i].name);
+ *gClasses[i].clazz = MakeGlobalRefOrDie(env, clazz);
+ }
+
+ for (int i = 0; i < NELEM(gFields); ++i) {
+ *gFields[i].id = GetFieldIDOrDie(env,
+ *gFields[i].c, gFields[i].name, gFields[i].ft);
+ }
+
+ for (int i = 0; i < NELEM(gMethods); ++i) {
+ *gMethods[i].id = GetMethodIDOrDie(env,
+ *gMethods[i].c, gMethods[i].name, gMethods[i].mt);
+ }
+
+ return RegisterMethodsOrDie(
+ env,
+ "android/app/admin/SecurityLog",
+ gRegisterMethods, NELEM(gRegisterMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 7314fbc..e17de17 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -78,11 +78,11 @@
static void updateFullPathPropertiesAndStrokeStyles(JNIEnv*, jobject, jlong fullPathPtr,
jfloat strokeWidth, jint strokeColor, jfloat strokeAlpha, jint fillColor, jfloat fillAlpha,
jfloat trimPathStart, jfloat trimPathEnd, jfloat trimPathOffset, jfloat strokeMiterLimit,
- jint strokeLineCap, jint strokeLineJoin) {
+ jint strokeLineCap, jint strokeLineJoin, jint fillType) {
VectorDrawable::FullPath* fullPath = reinterpret_cast<VectorDrawable::FullPath*>(fullPathPtr);
fullPath->updateProperties(strokeWidth, strokeColor, strokeAlpha, fillColor, fillAlpha,
trimPathStart, trimPathEnd, trimPathOffset, strokeMiterLimit, strokeLineCap,
- strokeLineJoin);
+ strokeLineJoin, fillType);
}
static void updateFullPathFillGradient(JNIEnv*, jobject, jlong pathPtr, jlong fillGradientPtr) {
@@ -331,7 +331,7 @@
{"nDraw", "(JJJLandroid/graphics/Rect;ZZ)V", (void*)draw},
{"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
{"nCreateFullPath", "!(J)J", (void*)createFullPath},
- {"nUpdateFullPathProperties", "!(JFIFIFFFFFII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+ {"nUpdateFullPathProperties", "!(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
{"nUpdateFullPathFillGradient", "!(JJ)V", (void*)updateFullPathFillGradient},
{"nUpdateFullPathStrokeGradient", "!(JJ)V", (void*)updateFullPathStrokeGradient},
{"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 3e4e352..1bc4285 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -200,7 +200,7 @@
ALOGE("Error creating AudioRecord: Error retrieving session id pointer");
return (jint) AUDIO_JAVA_ERROR;
}
- int sessionId = nSession[0];
+ audio_session_t sessionId = (audio_session_t) nSession[0];
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
@@ -385,7 +385,7 @@
}
return nativeToJavaStatus(
- lpRecorder->start((AudioSystem::sync_event_t)event, triggerSession));
+ lpRecorder->start((AudioSystem::sync_event_t)event, (audio_session_t) triggerSession));
}
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 1eb0111..7496124 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -109,7 +109,8 @@
jfieldID mRule;
jfieldID mFormat;
jfieldID mRouteFlags;
- jfieldID mRegistrationId;
+ jfieldID mDeviceType;
+ jfieldID mDeviceAddress;
jfieldID mMixType;
jfieldID mCallbackFlags;
} gAudioMixFields;
@@ -388,7 +389,7 @@
}
static void
-android_media_AudioSystem_recording_callback(int event, int session, int source,
+android_media_AudioSystem_recording_callback(int event, audio_session_t session, int source,
const audio_config_base_t *clientConfig, const audio_config_base_t *deviceConfig,
audio_patch_handle_t patchHandle)
{
@@ -1539,7 +1540,7 @@
static jint
android_media_AudioSystem_getAudioHwSyncForSession(JNIEnv *env, jobject thiz, jint sessionId)
{
- return (jint)AudioSystem::getAudioHwSyncForSession((audio_session_t)sessionId);
+ return (jint) AudioSystem::getAudioHwSyncForSession((audio_session_t) sessionId);
}
static void
@@ -1561,13 +1562,15 @@
{
nAudioMix->mMixType = env->GetIntField(jAudioMix, gAudioMixFields.mMixType);
nAudioMix->mRouteFlags = env->GetIntField(jAudioMix, gAudioMixFields.mRouteFlags);
+ nAudioMix->mDeviceType = (audio_devices_t)
+ env->GetIntField(jAudioMix, gAudioMixFields.mDeviceType);
- jstring jRegistrationId = (jstring)env->GetObjectField(jAudioMix,
- gAudioMixFields.mRegistrationId);
- const char *nRegistrationId = env->GetStringUTFChars(jRegistrationId, NULL);
- nAudioMix->mRegistrationId = String8(nRegistrationId);
- env->ReleaseStringUTFChars(jRegistrationId, nRegistrationId);
- env->DeleteLocalRef(jRegistrationId);
+ jstring jDeviceAddress = (jstring)env->GetObjectField(jAudioMix,
+ gAudioMixFields.mDeviceAddress);
+ const char *nDeviceAddress = env->GetStringUTFChars(jDeviceAddress, NULL);
+ nAudioMix->mDeviceAddress = String8(nDeviceAddress);
+ env->ReleaseStringUTFChars(jDeviceAddress, nDeviceAddress);
+ env->DeleteLocalRef(jDeviceAddress);
nAudioMix->mCbFlags = env->GetIntField(jAudioMix, gAudioMixFields.mCallbackFlags);
@@ -1857,7 +1860,8 @@
gAudioMixFields.mFormat = GetFieldIDOrDie(env, audioMixClass, "mFormat",
"Landroid/media/AudioFormat;");
gAudioMixFields.mRouteFlags = GetFieldIDOrDie(env, audioMixClass, "mRouteFlags", "I");
- gAudioMixFields.mRegistrationId = GetFieldIDOrDie(env, audioMixClass, "mRegistrationId",
+ gAudioMixFields.mDeviceType = GetFieldIDOrDie(env, audioMixClass, "mDeviceSystemType", "I");
+ gAudioMixFields.mDeviceAddress = GetFieldIDOrDie(env, audioMixClass, "mDeviceAddress",
"Ljava/lang/String;");
gAudioMixFields.mMixType = GetFieldIDOrDie(env, audioMixClass, "mMixType", "I");
gAudioMixFields.mCallbackFlags = GetFieldIDOrDie(env, audioMixClass, "mCallbackFlags", "I");
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 302cf63..024c21d 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -235,7 +235,7 @@
ALOGE("Error creating AudioTrack: Error retrieving session id pointer");
return (jint) AUDIO_JAVA_ERROR;
}
- int sessionId = nSession[0];
+ audio_session_t sessionId = (audio_session_t) nSession[0];
env->ReleasePrimitiveArrayCritical(jSession, nSession, 0);
nSession = NULL;
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index b7701d6..14252dc 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -144,7 +144,7 @@
PublicFormat f) {
switch(f) {
case PublicFormat::JPEG:
- return HAL_DATASPACE_JFIF;
+ return HAL_DATASPACE_V0_JFIF;
case PublicFormat::DEPTH_POINT_CLOUD:
case PublicFormat::DEPTH16:
return HAL_DATASPACE_DEPTH;
@@ -156,7 +156,7 @@
case PublicFormat::YUV_420_888:
case PublicFormat::NV21:
case PublicFormat::YV12:
- return HAL_DATASPACE_JFIF;
+ return HAL_DATASPACE_V0_JFIF;
default:
// Most formats map to UNKNOWN
return HAL_DATASPACE_UNKNOWN;
@@ -210,7 +210,7 @@
switch (dataSpace) {
case HAL_DATASPACE_DEPTH:
return PublicFormat::DEPTH_POINT_CLOUD;
- case HAL_DATASPACE_JFIF:
+ case HAL_DATASPACE_V0_JFIF:
return PublicFormat::JPEG;
default:
// Assume otherwise-marked blobs are also JPEG
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 50c7bfb..a52c4e5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -5876,6 +5876,12 @@
</attr>
<!-- sets the Miter limit for a stroked path -->
<attr name="strokeMiterLimit" format="float"/>
+ <!-- sets the fillType for a path. It is the same as SVG's "fill-rule" properties.
+ For more details, see https://www.w3.org/TR/SVG/painting.html#FillRuleProperty -->
+ <attr name="fillType" format="enum">
+ <enum name="nonZero" value="0"/>
+ <enum name="evenOdd" value="1"/>
+ </attr>
</declare-styleable>
<!-- Defines the clip path used in VectorDrawables. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 2b0ef42..4e8740a 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2706,6 +2706,7 @@
<public type="attr" name="canRecord" />
<public type="attr" name="tunerCount" />
<public type="attr" name="nfcAntennaPositionDrawable" />
+ <public type="attr" name="fillType" />
<public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
<public type="style" name="Widget.Material.SeekBar.Discrete" />
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index a65a813..e636bc0 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -993,7 +993,7 @@
</style>
<style name="Widget.Material.SuggestionItem" parent="@android:style/TextAppearance.Material.Body1">
- <item name="textColor">#8a000000</item> <!-- alpha=.54, textColor=@color/black -->
+ <item name="textColor">?attr/textColorSecondary</item>
<item name="drawablePadding">8dip</item>
<item name="gravity">start|center_vertical</item>
<item name="layout_gravity">start|center_vertical</item>
@@ -1008,11 +1008,11 @@
</style>
<style name="TextAppearance.Material.TextSuggestionHighlight" parent="Widget.Material.SuggestionItem">
- <item name="textColor">#de000000</item> <!-- alpha=.87, textColor=@color/black -->
+ <item name="textColor">?attr/textColorPrimary</item>
</style>
<style name="Widget.Material.SuggestionButton" parent="@android:style/TextAppearance.Material.Button">
- <item name="textColor">#de009688</item> <!-- alpha=.87, textColor=#009688 -->
+ <item name="textColor">?attr/colorAccent</item>
<item name="drawablePadding">8dip</item>
<item name="gravity">start|center_vertical</item>
<item name="layout_gravity">start|center_vertical</item>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 5970a22..a361eda 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -223,6 +223,7 @@
<item name="textSelectHandleWindowStyle">@style/Widget.Material.TextSelectHandle</item>
<item name="textEditSuggestionItemLayout">@layout/text_edit_suggestion_item_material</item>
<item name="textEditSuggestionContainerLayout">@layout/text_edit_suggestion_container_material</item>
+ <item name="textEditSuggestionHighlightStyle">@style/TextAppearance.Material.TextSuggestionHighlight</item>
<item name="textCursorDrawable">@drawable/text_cursor_material</item>
<!-- Widget styles -->
diff --git a/data/fonts/Android.mk b/data/fonts/Android.mk
index dc85046..fd28f64 100644
--- a/data/fonts/Android.mk
+++ b/data/fonts/Android.mk
@@ -105,4 +105,4 @@
.PHONY: fontchain_lint
fontchain_lint: $(FONTCHAIN_LINTER) $(TARGET_OUT)/etc/fonts.xml
PYTHONPATH=$$PYTHONPATH:external/fonttools/Lib \
- python $(FONTCHAIN_LINTER) $(TARGET_OUT)
\ No newline at end of file
+ python $(FONTCHAIN_LINTER) $(TARGET_OUT) external/unicode
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index ae98c22..bd069ff 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -1281,8 +1281,10 @@
private static final int STROKE_LINE_CAP_INDEX = 8;
private static final int STROKE_LINE_JOIN_INDEX = 9;
private static final int STROKE_MITER_LIMIT_INDEX = 10;
- private static final int TOTAL_PROPERTY_COUNT = 11;
+ private static final int FILL_TYPE_INDEX = 11;
+ private static final int TOTAL_PROPERTY_COUNT = 12;
+ // Property map for animatable attributes.
private final static HashMap<String, Integer> sPropertyMap
= new HashMap<String, Integer> () {
{
@@ -1399,6 +1401,7 @@
int strokeLineCap = properties.getInt(STROKE_LINE_CAP_INDEX * 4);
int strokeLineJoin = properties.getInt(STROKE_LINE_JOIN_INDEX * 4);
float strokeMiterLimit = properties.getFloat(STROKE_MITER_LIMIT_INDEX * 4);
+ int fillType = properties.getInt(FILL_TYPE_INDEX * 4);
Shader fillGradient = null;
Shader strokeGradient = null;
// Account for any configuration changes.
@@ -1474,10 +1477,11 @@
R.styleable.VectorDrawablePath_trimPathOffset, trimPathOffset);
trimPathStart = a.getFloat(
R.styleable.VectorDrawablePath_trimPathStart, trimPathStart);
+ fillType = a.getInt(R.styleable.VectorDrawablePath_fillType, fillType);
nUpdateFullPathProperties(mNativePtr, strokeWidth, strokeColor, strokeAlpha,
fillColor, fillAlpha, trimPathStart, trimPathEnd, trimPathOffset,
- strokeMiterLimit, strokeLineCap, strokeLineJoin);
+ strokeMiterLimit, strokeLineCap, strokeLineJoin, fillType);
}
@Override
@@ -1645,7 +1649,7 @@
private static native void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
- int strokeLineJoin);
+ int strokeLineJoin, int fillType);
private static native void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr);
private static native void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr);
diff --git a/libs/hwui/FrameBuilder.cpp b/libs/hwui/FrameBuilder.cpp
index fd5856a..50b21a4 100644
--- a/libs/hwui/FrameBuilder.cpp
+++ b/libs/hwui/FrameBuilder.cpp
@@ -646,7 +646,9 @@
}
void FrameBuilder::deferTextOp(const TextOp& op) {
- BakedOpState* bakedState = tryBakeOpState(op);
+ BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
+ mAllocator, *mCanvasState.writableSnapshot(), op,
+ BakedOpState::StrokeBehavior::StyleDefined);
if (!bakedState) return; // quick rejected
batchid_t batchId = textBatchId(*(op.paint));
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index f7b38e3..d35f764 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -158,7 +158,8 @@
void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
- float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin) {
+ float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
+ int fillType) {
mProperties.strokeWidth = strokeWidth;
mProperties.strokeColor = strokeColor;
mProperties.strokeAlpha = strokeAlpha;
@@ -167,6 +168,7 @@
mProperties.strokeMiterLimit = strokeMiterLimit;
mProperties.strokeLineCap = strokeLineCap;
mProperties.strokeLineJoin = strokeLineJoin;
+ mProperties.fillType = fillType;
// If any trim property changes, mark trim dirty and update the trim path
setTrimPathStart(trimPathStart);
@@ -179,7 +181,7 @@
return SkColorSetA(color, alphaBytes * alpha);
}
-void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale,
+void FullPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath, float strokeScale,
const SkMatrix& matrix){
// Draw path's fill, if fill color or gradient is valid
bool needsFill = false;
@@ -196,6 +198,8 @@
if (needsFill) {
mPaint.setStyle(SkPaint::Style::kFill_Style);
mPaint.setAntiAlias(true);
+ SkPath::FillType ft = static_cast<SkPath::FillType>(mProperties.fillType);
+ renderPath.setFillType(ft);
outCanvas->drawPath(renderPath, mPaint);
}
@@ -306,7 +310,7 @@
}
}
-void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
+void ClipPath::drawPath(SkCanvas* outCanvas, SkPath& renderPath,
float strokeScale, const SkMatrix& matrix){
outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
}
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index 36a8aeb..4d2fed0 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -96,7 +96,7 @@
protected:
virtual const SkPath& getUpdatedPath();
- virtual void drawPath(SkCanvas *outCanvas, const SkPath& renderPath,
+ virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
float strokeScale, const SkMatrix& matrix) = 0;
Data mData;
SkPath mSkPath;
@@ -118,6 +118,7 @@
int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
float strokeMiterLimit = 4;
+ int fillType = 0; /* non-zero or kWinding_FillType in Skia */
};
FullPath(const FullPath& path); // for cloning
@@ -133,7 +134,7 @@
void updateProperties(float strokeWidth, SkColor strokeColor,
float strokeAlpha, SkColor fillColor, float fillAlpha,
float trimPathStart, float trimPathEnd, float trimPathOffset,
- float strokeMiterLimit, int strokeLineCap, int strokeLineJoin);
+ float strokeMiterLimit, int strokeLineCap, int strokeLineJoin, int fillType);
// TODO: Cleanup: Remove the setter and getters below, and their counterparts in java and JNI
float getStrokeWidth() {
return mProperties.strokeWidth;
@@ -197,7 +198,7 @@
protected:
const SkPath& getUpdatedPath() override;
- void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
+ void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
float strokeScale, const SkMatrix& matrix) override;
private:
@@ -213,6 +214,7 @@
StrokeLineCap,
StrokeLineJoin,
StrokeMiterLimit,
+ FillType,
Count,
};
// Applies trimming to the specified path.
@@ -233,7 +235,7 @@
ClipPath(const Data& nodes) : Path(nodes) {}
protected:
- void drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
+ void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
float strokeScale, const SkMatrix& matrix) override;
};
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index f147fd4..31555f2 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -316,6 +316,61 @@
<< "Expect number of ops = 2 * loop count";
}
+static auto styles = {
+ SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
+
+TEST(FrameBuilder, textStyle) {
+ class TextStyleTestRenderer : public TestRendererBase {
+ public:
+ void onMergedTextOps(const MergedBakedOpList& opList) override {
+ ASSERT_EQ(0, mIndex);
+ ASSERT_EQ(3u, opList.count);
+ mIndex += opList.count;
+
+ int index = 0;
+ for (auto style : styles) {
+ auto state = opList.states[index++];
+ ASSERT_EQ(style, state->op->paint->getStyle())
+ << "Remainder of validation relies upon stable merged order";
+ ASSERT_EQ(0, state->computedState.clipSideFlags)
+ << "Clipped bounds validation requires unclipped ops";
+ }
+
+ Rect fill = opList.states[0]->computedState.clippedBounds;
+ Rect stroke = opList.states[1]->computedState.clippedBounds;
+ EXPECT_EQ(stroke, opList.states[2]->computedState.clippedBounds)
+ << "Stroke+Fill should be same as stroke";
+
+ EXPECT_TRUE(stroke.contains(fill));
+ EXPECT_FALSE(fill.contains(stroke));
+
+ Rect outsetFill(fill);
+ outsetFill.outset(10);
+ EXPECT_EQ(stroke, outsetFill);
+ }
+ };
+ auto node = TestUtils::createNode(0, 0, 400, 400,
+ [](RenderProperties& props, TestCanvas& canvas) {
+ SkPaint paint;
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ paint.setAntiAlias(true);
+ paint.setTextSize(50);
+ paint.setStrokeWidth(10);
+
+ // draw 3 copies of the same text overlapping, each with a different style.
+ // They'll get merged, but with
+ for (auto style : styles) {
+ paint.setStyle(style);
+ TestUtils::drawTextToCanvas(&canvas, "Test string1", paint, 100, 100);
+ }
+ });
+ FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+ TestUtils::createSyncedNodeList(node), sLightGeometry, nullptr);
+ TextStyleTestRenderer renderer;
+ frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+ EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
+}
+
RENDERTHREAD_TEST(FrameBuilder, textureLayer) {
class TextureLayerTestRenderer : public TestRendererBase {
public:
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index 949c541..454011f 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -16,7 +16,6 @@
#include <gtest/gtest.h>
-#include "BakedOpRenderer.h"
#include "Glop.h"
#include "GlopBuilder.h"
#include "Rect.h"
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 0f82cfc..ca306cc 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -228,7 +228,7 @@
/**
* Audio session ID
*/
- private int mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
+ private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
/**
* AudioAttributes
*/
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index c5d1120..e1dab09 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -295,7 +295,7 @@
/**
* Audio session ID
*/
- private int mSessionId = AudioSystem.AUDIO_SESSION_ALLOCATE;
+ private int mSessionId = AudioManager.AUDIO_SESSION_ID_GENERATE;
/**
* Reference to the app-ops service.
*/
@@ -368,7 +368,7 @@
int bufferSizeInBytes, int mode)
throws IllegalArgumentException {
this(streamType, sampleRateInHz, channelConfig, audioFormat,
- bufferSizeInBytes, mode, AudioSystem.AUDIO_SESSION_ALLOCATE);
+ bufferSizeInBytes, mode, AudioManager.AUDIO_SESSION_ID_GENERATE);
}
/**
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 56d3c99..adeb834 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -36,30 +36,28 @@
private AudioMixingRule mRule;
private AudioFormat mFormat;
private int mRouteFlags;
- private String mRegistrationId;
private int mMixType = MIX_TYPE_INVALID;
// written by AudioPolicy
int mMixState = MIX_STATE_DISABLED;
int mCallbackFlags;
+ String mDeviceAddress;
// initialized in constructor, read by AudioPolicyConfig
- final int mDeviceId;
- final String mDeviceAddress;
+ final int mDeviceSystemType; // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
/**
* All parameters are guaranteed valid through the Builder.
*/
private AudioMix(AudioMixingRule rule, AudioFormat format, int routeFlags, int callbackFlags,
- int deviceId, String deviceAddress) {
+ int deviceType, String deviceAddress) {
mRule = rule;
mFormat = format;
mRouteFlags = routeFlags;
- mRegistrationId = null;
mMixType = rule.getTargetMixType();
mCallbackFlags = callbackFlags;
- mDeviceId = deviceId;
- mDeviceAddress = deviceAddress;
+ mDeviceSystemType = deviceType;
+ mDeviceAddress = (deviceAddress == null) ? new String("") : deviceAddress;
}
// CALLBACK_FLAG_* values: keep in sync with AudioMix::kCbFlag* values defined
@@ -155,12 +153,12 @@
}
void setRegistration(String regId) {
- mRegistrationId = regId;
+ mDeviceAddress = regId;
}
/** @hide */
public String getRegistration() {
- return mRegistrationId;
+ return mDeviceAddress;
}
/** @hide */
@@ -185,7 +183,8 @@
private AudioFormat mFormat = null;
private int mRouteFlags = 0;
private int mCallbackFlags = 0;
- private int mDeviceId = -1;
+ // an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
+ private int mDeviceSystemType = AudioSystem.DEVICE_NONE;
private String mDeviceAddress = null;
/**
@@ -243,12 +242,12 @@
/**
* @hide
* Only used by AudioPolicyConfig, not a public API.
- * @param deviceId
+ * @param deviceType an AudioSystem.DEVICE_* value, not AudioDeviceInfo.TYPE_*
* @param address
* @return the same Builder instance.
*/
- Builder setDevice(int deviceId, String address) {
- mDeviceId = deviceId;
+ Builder setDevice(int deviceType, String address) {
+ mDeviceSystemType = deviceType;
mDeviceAddress = address;
return this;
}
@@ -312,7 +311,7 @@
if (!device.isSink()) {
throw new IllegalArgumentException("Unsupported device type on mix, not a sink");
}
- mDeviceId = device.getId();
+ mDeviceSystemType = AudioDeviceInfo.convertDeviceTypeToInternalDevice(device.getType());
mDeviceAddress = device.getAddress();
return this;
}
@@ -344,7 +343,9 @@
}
mFormat = new AudioFormat.Builder().setSampleRate(rate).build();
}
- if (mDeviceId != -1) {
+ if ((mDeviceSystemType != AudioSystem.DEVICE_NONE)
+ && (mDeviceSystemType != AudioSystem.DEVICE_OUT_REMOTE_SUBMIX)
+ && (mDeviceSystemType != AudioSystem.DEVICE_IN_REMOTE_SUBMIX)) {
if ((mRouteFlags & ROUTE_FLAG_RENDER) == 0) {
throw new IllegalArgumentException(
"Can't have audio device without flag ROUTE_FLAG_RENDER");
@@ -357,8 +358,17 @@
throw new IllegalArgumentException(
"Can't have flag ROUTE_FLAG_RENDER without an audio device");
}
+ if ((mRouteFlags & ROUTE_FLAG_SUPPORTED) == ROUTE_FLAG_LOOP_BACK) {
+ if (mRule.getTargetMixType() == MIX_TYPE_PLAYERS) {
+ mDeviceSystemType = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
+ } else if (mRule.getTargetMixType() == MIX_TYPE_RECORDERS) {
+ mDeviceSystemType = AudioSystem.DEVICE_IN_REMOTE_SUBMIX;
+ } else {
+ throw new IllegalArgumentException("Unknown mixing rule type");
+ }
+ }
}
- return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceId,
+ return new AudioMix(mRule, mFormat, mRouteFlags, mCallbackFlags, mDeviceSystemType,
mDeviceAddress);
}
}
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index 3af3ae7..cafa5a8 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -84,7 +84,7 @@
// write callback flags
dest.writeInt(mix.mCallbackFlags);
// write device information
- dest.writeInt(mix.mDeviceId);
+ dest.writeInt(mix.mDeviceSystemType);
dest.writeString(mix.mDeviceAddress);
// write mix format
dest.writeInt(mix.getFormat().getSampleRate());
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index e9d62de..2fb1a3b 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -906,14 +906,16 @@
android_media_MediaPlayer_release(env, thiz);
}
-static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz, jint sessionId) {
+static void android_media_MediaPlayer_set_audio_session_id(JNIEnv *env, jobject thiz,
+ jint sessionId) {
ALOGV("set_session_id(): %d", sessionId);
sp<MediaPlayer> mp = getMediaPlayer(env, thiz);
if (mp == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
}
- process_media_player_call( env, thiz, mp->setAudioSessionId(sessionId), NULL, NULL );
+ process_media_player_call( env, thiz, mp->setAudioSessionId((audio_session_t) sessionId), NULL,
+ NULL);
}
static jint android_media_MediaPlayer_get_audio_session_id(JNIEnv *env, jobject thiz) {
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index fa69135..10efe18 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -351,7 +351,7 @@
priority,
effectCallback,
&lpJniStorage->mCallbackData,
- sessionId,
+ (audio_session_t) sessionId,
0);
if (lpAudioEffect == 0) {
ALOGE("Error creating AudioEffect");
@@ -819,7 +819,7 @@
effect_descriptor_t *descriptors = new effect_descriptor_t[AudioEffect::kMaxPreProcessing];
uint32_t numEffects = AudioEffect::kMaxPreProcessing;
- status_t status = AudioEffect::queryDefaultPreProcessing(audioSession,
+ status_t status = AudioEffect::queryDefaultPreProcessing((audio_session_t) audioSession,
descriptors,
&numEffects);
if (status != NO_ERROR || numEffects == 0) {
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 3d3adba..f1a8c6f 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -388,7 +388,7 @@
0,
android_media_visualizer_effect_callback,
lpJniStorage,
- sessionId);
+ (audio_session_t) sessionId);
if (lpVisualizer == 0) {
ALOGE("Error creating Visualizer");
goto setup_failure;
diff --git a/packages/DocumentsUI/app-perf-tests/Android.mk b/packages/DocumentsUI/app-perf-tests/Android.mk
new file mode 100644
index 0000000..3f12906
--- /dev/null
+++ b/packages/DocumentsUI/app-perf-tests/Android.mk
@@ -0,0 +1,18 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+#LOCAL_SDK_VERSION := current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+
+LOCAL_JAVA_LIBRARIES := android-support-v4 android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ub-uiautomator
+
+LOCAL_PACKAGE_NAME := DocumentsUIAppPerfTests
+LOCAL_INSTRUMENTATION_FOR := DocumentsUI
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml b/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
new file mode 100644
index 0000000..1c3ed80
--- /dev/null
+++ b/packages/DocumentsUI/app-perf-tests/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.documentsui.appperftests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <activity
+ android:name="com.android.documentsui.LauncherActivity" />
+ </application>
+
+ <!-- This package instrumentates itself, so the DocumentsUI process can be killed without
+ killing the testing package. -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.documentsui.appperftests"
+ android:label="App performance tests for DocumentsUI" />
+
+</manifest>
diff --git a/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
new file mode 100644
index 0000000..d6e8a96
--- /dev/null
+++ b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/FilesAppPerfTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.support.test.uiautomator.UiDevice;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+@LargeTest
+public class FilesAppPerfTest extends InstrumentationTestCase {
+
+ // Keys used to report metrics to APCT.
+ private static final String KEY_FILES_COLD_START_PERFORMANCE_MEDIAN =
+ "files-cold-start-performance-median";
+ private static final String KEY_FILES_WARM_START_PERFORMANCE_MEDIAN =
+ "files-warm-start-performance-median";
+
+ private static final String TARGET_PACKAGE = "com.android.documentsui";
+
+ private static final int NUM_MEASUREMENTS = 10;
+
+ private LauncherActivity mActivity;
+ private UiDevice mDevice;
+
+ @Override
+ public void setUp() {
+ mDevice = UiDevice.getInstance(getInstrumentation());
+ }
+
+ public void testFilesColdStartPerformance() throws Exception {
+ runFilesStartPerformanceTest(true);
+ }
+
+ public void testFilesWarmStartPerformance() throws Exception {
+ runFilesStartPerformanceTest(false);
+ }
+
+ public void runFilesStartPerformanceTest(boolean cold) throws Exception {
+ long[] measurements = new long[NUM_MEASUREMENTS];
+ for (int i = 0; i < NUM_MEASUREMENTS; i++) {
+ if (cold) {
+ // Kill all providers, as well as DocumentsUI to measure a cold start.
+ killProviders();
+ mDevice.executeShellCommand("am force-stop " + TARGET_PACKAGE);
+ }
+ mDevice.waitForIdle();
+
+ LauncherActivity.testCaseLatch = new CountDownLatch(1);
+ mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
+ LauncherActivity.class, null);
+ LauncherActivity.testCaseLatch.await();
+ measurements[i] = LauncherActivity.measurement;
+ }
+
+ reportMetrics(cold ? KEY_FILES_COLD_START_PERFORMANCE_MEDIAN
+ : KEY_FILES_WARM_START_PERFORMANCE_MEDIAN, measurements);
+ }
+
+ private void reportMetrics(String key, long[] measurements) {
+ final Bundle status = new Bundle();
+ Arrays.sort(measurements);
+ final long median = measurements[NUM_MEASUREMENTS / 2 - 1];
+ status.putDouble(key, median);
+
+ getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+ }
+
+ private void killProviders() throws Exception {
+ final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);
+ final List<ResolveInfo> providers = pm.queryIntentContentProviders(intent, 0);
+ for (ResolveInfo info : providers) {
+ final String packageName = info.providerInfo.packageName;
+ mDevice.executeShellCommand("am force-stop " + packageName);
+ }
+ }
+}
diff --git a/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/LauncherActivity.java
new file mode 100644
index 0000000..21fc52e
--- /dev/null
+++ b/packages/DocumentsUI/app-perf-tests/src/com/android/documentsui/LauncherActivity.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.Shared.EXTRA_BENCHMARK;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+
+import java.util.concurrent.CountDownLatch;
+
+public class LauncherActivity extends Activity {
+ private static final String TARGET_PACKAGE = "com.android.documentsui";
+ private static final int BENCHMARK_REQUEST_CODE = 1986;
+
+ public static CountDownLatch testCaseLatch = null;
+ public static long measurement = -1;
+
+ private long mStartTime = -1;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ new Handler().post(new Runnable() {
+ @Override public void run() {
+ final Intent intent = new Intent("android.intent.action.OPEN_DOCUMENT");
+ intent.addCategory(Intent.CATEGORY_OPENABLE);
+ intent.putExtra(EXTRA_BENCHMARK, true);
+ intent.setType("*/*");
+
+ mStartTime = System.currentTimeMillis();
+ startActivityForResult(intent, BENCHMARK_REQUEST_CODE);
+ }
+ });
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ if (requestCode == BENCHMARK_REQUEST_CODE) {
+ measurement = System.currentTimeMillis() - mStartTime;
+ testCaseLatch.countDown();
+ finish();
+ }
+ }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index c51cbb3..fe61094 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -17,6 +17,7 @@
package com.android.documentsui;
import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.EXTRA_BENCHMARK;
import static com.android.documentsui.State.MODE_GRID;
import android.app.Activity;
@@ -30,6 +31,9 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.MessageQueue;
+import android.os.MessageQueue.IdleHandler;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Root;
import android.support.annotation.CallSuper;
@@ -60,6 +64,8 @@
public abstract class BaseActivity extends Activity
implements SearchManagerListener, NavigationView.Environment {
+ private static final String BENCHMARK_TESTING_PACKAGE = "com.android.documentsui.appperftests";
+
State mState;
RootsCache mRoots;
SearchViewManager mSearchManager;
@@ -92,11 +98,20 @@
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
+ final Intent intent = getIntent();
+
+ // If startup benchmark is requested by a whitelisted testing package, then close the
+ // activity once idle, and notify the testing activity.
+ if (intent.getBooleanExtra(EXTRA_BENCHMARK, false) &&
+ BENCHMARK_TESTING_PACKAGE.equals(getCallingPackage())) {
+ closeOnIdleForTesting();
+ }
+
setContentView(mLayoutId);
mDrawer = DrawerController.create(this);
mState = getState(icicle);
- Metrics.logActivityLaunch(this, mState, getIntent());
+ Metrics.logActivityLaunch(this, mState, intent);
mRoots = DocumentsApplication.getRootsCache(this);
@@ -668,6 +683,33 @@
}
}
+ /**
+ * Closes the activity when it's idle. Used only for tests.
+ */
+ private void closeOnIdleForTesting() {
+ addEventListener(new EventListener() {
+ @Override
+ public void onDirectoryNavigated(Uri uri) {
+ }
+
+ @Override
+ public void onDirectoryLoaded(Uri uri) {
+ getMainLooper().getQueue().addIdleHandler(new IdleHandler() {
+ @Override
+ public boolean queueIdle() {
+ setResult(RESULT_OK);
+ finish();
+ return false;
+ }
+ });
+ new Handler().post(new Runnable() {
+ @Override public void run() {
+ }
+ });
+ }
+ });
+ }
+
private static final class HandleRootsChangedTask
extends PairedTask<BaseActivity, RootInfo, RootInfo> {
DocumentInfo mDownloadsDocument;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index b539421..c32bbff 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -86,6 +86,11 @@
*/
public static final String EXTRA_IGNORE_STATE = "ignoreState";
+ /**
+ * Extra for an Intent for enabling performance benchmark. Used only by tests.
+ */
+ public static final String EXTRA_BENCHMARK = "com.android.documentsui.benchmark";
+
private static final Collator sCollator;
static {
@@ -133,8 +138,7 @@
/**
* Compare two strings against each other using system default collator in a
- * case-insensitive mode. Clusters strings prefixed with {@link DIR_PREFIX}
- * before other items.
+ * case-insensitive mode.
*/
public static int compareToIgnoreCaseNullable(String lhs, String rhs) {
final boolean leftEmpty = TextUtils.isEmpty(lhs);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index be70417..63a834f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -98,7 +98,6 @@
import com.android.documentsui.services.FileOperationService;
import com.android.documentsui.services.FileOperationService.OpType;
import com.android.documentsui.services.FileOperations;
-
import com.google.common.collect.Lists;
import java.lang.annotation.Retention;
@@ -165,6 +164,7 @@
private String mQuery = null;
private Selection mSelection = null;
private boolean mSearchMode = false;
+ private @Nullable ActionMode mActionMode;
@Override
public View onCreateView(
@@ -406,9 +406,9 @@
int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight();
- assert(mRecView.getWidth() > 0);
-
- int columnCount = Math.max(1,
+ // RecyclerView sometimes gets a width of 0 (see b/27150284). Clamp so that we always lay
+ // out the grid with at least 2 columns.
+ int columnCount = Math.max(2,
(mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin));
return columnCount;
@@ -439,7 +439,6 @@
implements MultiSelectManager.Callback, ActionMode.Callback {
private Selection mSelected = new Selection();
- private ActionMode mActionMode;
private int mNoCopyCount = 0;
private int mNoDeleteCount = 0;
private int mNoRenameCount = -1;
@@ -578,10 +577,9 @@
return true;
case R.id.menu_delete:
- // Pass mode along to the delete function so it can
- // end action mode when documents are deleted.
+ // deleteDocuments will end action mode if the documents are deleted.
// It won't end action mode if user cancels the delete.
- deleteDocuments(selection, mode);
+ deleteDocuments(selection);
return true;
case R.id.menu_copy_to:
@@ -690,7 +688,7 @@
}.execute(selected);
}
- private void deleteDocuments(final Selection selected, final ActionMode mode) {
+ private void deleteDocuments(final Selection selected) {
assert(!selected.isEmpty());
final DocumentInfo srcParent = getDisplayState().stack.peek();
@@ -727,7 +725,9 @@
// This is done here, rather in the onActionItemClicked
// so we can avoid de-selecting items in the case where
// the user cancels the delete.
- mode.finish();
+ if (mActionMode != null) {
+ mActionMode.finish();
+ }
// Hide the files in the UI...since the operation
// might be queued up on FileOperationService.
// We're walking a line here.
@@ -1263,12 +1263,25 @@
}
// Handle enter key events
- if (keyCode == KeyEvent.KEYCODE_ENTER) {
- if (event.isShiftPressed()) {
- return onSelect(doc);
- } else {
+ switch (keyCode) {
+ case KeyEvent.KEYCODE_ENTER:
+ if (event.isShiftPressed()) {
+ return onSelect(doc);
+ }
+ // For non-shifted enter keypresses, fall through.
+ case KeyEvent.KEYCODE_DPAD_CENTER:
+ case KeyEvent.KEYCODE_BUTTON_A:
return onActivate(doc);
- }
+ case KeyEvent.KEYCODE_FORWARD_DEL:
+ // This has to be handled here instead of in a keyboard shortcut, because
+ // keyboard shortcuts all have to be modified with the 'Ctrl' key.
+ if (mSelectionManager.hasSelection()) {
+ deleteDocuments(mSelectionManager.getSelection());
+ }
+ // Always handle the key, even if there was nothing to delete. This is a
+ // precaution to prevent other handlers from potentially picking up the event
+ // and triggering extra behaviours.
+ return true;
}
return false;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
index 5edda38..450341f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
@@ -77,10 +77,18 @@
/**
* Makes the associated item view appear selected. Note that this merely affects the appearance
* of the view, it doesn't actually select the item.
+ * TODO: Use the DirectoryItemAnimator instead of manually controlling animation using a boolean
+ * flag.
*
* @param selected
+ * @param animate Whether or not to animate the change. Only selection changes initiated by the
+ * selection manager should be animated. See
+ * {@link ModelBackedDocumentsAdapter#onBindViewHolder(DocumentHolder, int, java.util.List)}
*/
- public void setSelected(boolean selected) {
+ public void setSelected(boolean selected, boolean animate) {
+ // Note: the animate param doesn't apply for this base implementation, because the
+ // DirectoryItemAnimator takes care of it. It's required by subclasses, which perform their
+ // own animation.
itemView.setActivated(selected);
itemView.setBackgroundColor(selected ? mSelectedBgColor : mDefaultBgColor);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index 39fdf8e..ea1deb4 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -104,7 +104,8 @@
return false;
}
- if (mState.action == ACTION_OPEN_TREE) {
+ if (mState.action == ACTION_OPEN_TREE
+ || mState.action == ACTION_PICK_COPY_DESTINATION) {
// In this case nothing *ever* is selectable...the expected user behavior is
// they navigate *into* a folder, then click a confirmation button indicating
// that the current directory is the directory they are picking.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
index 90b2341..ce5bcb1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
@@ -42,12 +42,17 @@
}
@Override
- public void setSelected(boolean selected) {
- super.setSelected(selected);
+ public void setSelected(boolean selected, boolean animate) {
+ super.setSelected(selected, animate);
float checkAlpha = selected ? 1f : 0f;
- mIconCheck.animate().alpha(checkAlpha).start();
- mIconMime.animate().alpha(1f - checkAlpha).start();
+ if (animate) {
+ mIconCheck.animate().alpha(checkAlpha).start();
+ mIconMime.animate().alpha(1f - checkAlpha).start();
+ } else {
+ mIconCheck.setAlpha(checkAlpha);
+ mIconMime.setAlpha(1f - checkAlpha);
+ }
}
/**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
index c8641a8..c4f6f11 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
@@ -69,12 +69,16 @@
}
@Override
- public void setSelected(boolean selected) {
+ public void setSelected(boolean selected, boolean animate) {
// We always want to make sure our check box disappears if we're not selected,
// even if the item is disabled. This is because this object can be reused
// and this method will be called to setup initial state.
float checkAlpha = selected ? 1f : 0f;
- mIconCheck.animate().alpha(checkAlpha).start();
+ if (animate) {
+ mIconCheck.animate().alpha(checkAlpha).start();
+ } else {
+ mIconCheck.setAlpha(checkAlpha);
+ }
// But it should be an error to be set to selected && be disabled.
if (!itemView.isEnabled()) {
@@ -82,9 +86,13 @@
return;
}
- super.setSelected(selected);
+ super.setSelected(selected, animate);
- mIconMimeSm.animate().alpha(1f - checkAlpha).start();
+ if (animate) {
+ mIconMimeSm.animate().alpha(1f - checkAlpha).start();
+ } else {
+ mIconMimeSm.setAlpha(1f - checkAlpha);
+ }
}
public void setEnabled(boolean enabled) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
index 3a1be11..ace53e0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
@@ -65,22 +65,31 @@
}
@Override
- public void setSelected(boolean selected) {
+ public void setSelected(boolean selected, boolean animate) {
// We always want to make sure our check box disappears if we're not selected,
// even if the item is disabled. But it should be an error (see assert below)
// to be set to selected && be disabled.
float checkAlpha = selected ? 1f : 0f;
- mIconCheck.animate().alpha(checkAlpha).start();
+ if (animate) {
+ mIconCheck.animate().alpha(checkAlpha).start();
+ } else {
+ mIconCheck.setAlpha(checkAlpha);
+ }
if (!itemView.isEnabled()) {
assert(!selected);
return;
}
- super.setSelected(selected);
+ super.setSelected(selected, animate);
- mIconMime.animate().alpha(1f - checkAlpha).start();
- mIconThumb.animate().alpha(1f - checkAlpha).start();
+ if (animate) {
+ mIconMime.animate().alpha(1f - checkAlpha).start();
+ mIconThumb.animate().alpha(1f - checkAlpha).start();
+ } else {
+ mIconMime.setAlpha(1f - checkAlpha);
+ mIconThumb.setAlpha(1f - checkAlpha);
+ }
}
@Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index 68b1bcc..c5ee592 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -20,9 +20,10 @@
import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
import static com.android.documentsui.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.model.DocumentInfo.getCursorLong;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
import android.database.Cursor;
-import android.database.MergeCursor;
import android.os.Bundle;
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
@@ -61,17 +62,34 @@
private String mIds[] = new String[0];
private int mSortOrder = SORT_ORDER_DISPLAY_NAME;
- private int mAuthorityIndex = -1;
- private int mDocIdIndex = -1;
- private int mMimeTypeIndex = -1;
- private int mDisplayNameIndex = -1;
- private int mColumnSizeIndex = -1;
- private int mLastModifiedIndex = -1;
-
@Nullable String info;
@Nullable String error;
@Nullable DocumentInfo doc;
+ /**
+ * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
+ * string that can be used to identify the document referred to by the cursor.
+ *
+ * @param c A cursor that refers to a document.
+ */
+ private static String createModelId(Cursor c) {
+ // TODO: Maybe more efficient to use just the document ID, in cases where there is only one
+ // authority (which should be the majority of cases).
+ return createModelId(
+ getCursorString(c, RootCursorWrapper.COLUMN_AUTHORITY),
+ getCursorString(c, Document.COLUMN_DOCUMENT_ID));
+ }
+
+ /**
+ * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
+ * string that can be used to identify the document referred to by the cursor.
+ *
+ * @param c A cursor that refers to a document.
+ */
+ static String createModelId(String authority, String docId) {
+ return authority + "|" + docId;
+ }
+
private void notifyUpdateListeners() {
for (UpdateListener listener: mUpdateListeners) {
listener.onModelUpdate(this);
@@ -109,13 +127,6 @@
mCursor = result.cursor;
mCursorCount = mCursor.getCount();
mSortOrder = result.sortOrder;
- mAuthorityIndex = mCursor.getColumnIndex(RootCursorWrapper.COLUMN_AUTHORITY);
- assert(mAuthorityIndex != -1);
- mDocIdIndex = mCursor.getColumnIndex(Document.COLUMN_DOCUMENT_ID);
- mMimeTypeIndex = mCursor.getColumnIndex(Document.COLUMN_MIME_TYPE);
- mDisplayNameIndex = mCursor.getColumnIndex(Document.COLUMN_DISPLAY_NAME);
- mColumnSizeIndex = mCursor.getColumnIndex(Document.COLUMN_SIZE);
-
doc = result.doc;
updateModelData();
@@ -162,30 +173,22 @@
for (int pos = 0; pos < mCursorCount; ++pos) {
mCursor.moveToNext();
positions[pos] = pos;
+ mIds[pos] = createModelId(mCursor);
- // Generates a Model ID for a cursor entry that refers to a document. The Model ID is a
- // unique string that can be used to identify the document referred to by the cursor.
- // If the cursor is a merged cursor over multiple authorities, then prefix the ids
- // with the authority to avoid collisions.
- if (mCursor instanceof MergeCursor) {
- mIds[pos] = getString(mAuthorityIndex) + "|" + mCursor.getString(mDocIdIndex);
- } else {
- mIds[pos] = mCursor.getString(mDocIdIndex);
- }
-
- mimeType = getString(mMimeTypeIndex);
+ mimeType = getCursorString(mCursor, Document.COLUMN_MIME_TYPE);
isDirs[pos] = Document.MIME_TYPE_DIR.equals(mimeType);
- switch (mSortOrder) {
+ switch(mSortOrder) {
case SORT_ORDER_DISPLAY_NAME:
- displayNames[pos] = getString(mDisplayNameIndex);
+ final String displayName = getCursorString(
+ mCursor, Document.COLUMN_DISPLAY_NAME);
+ displayNames[pos] = displayName;
break;
case SORT_ORDER_LAST_MODIFIED:
- longValues[pos] = getLastModified();
+ longValues[pos] = getLastModified(mCursor);
break;
case SORT_ORDER_SIZE:
- longValues[pos] = mColumnSizeIndex != -1
- ? mCursor.getLong(mColumnSizeIndex) : 0;
+ longValues[pos] = getCursorLong(mCursor, Document.COLUMN_SIZE);
break;
}
}
@@ -361,17 +364,13 @@
}
}
- private String getString(int columnIndex) {
- return columnIndex != -1 ? mCursor.getString(columnIndex) : null;
- }
-
/**
* @return Timestamp for the given document. Some docs (e.g. active downloads) have a null
* timestamp - these will be replaced with MAX_LONG so that such files get sorted to the top
* when sorting by date.
*/
- private long getLastModified() {
- long l = mCursor.getLong(mLastModifiedIndex);
+ long getLastModified(Cursor cursor) {
+ long l = getCursorLong(mCursor, Document.COLUMN_LAST_MODIFIED);
return (l == -1) ? Long.MAX_VALUE : l;
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
index 149ecdd..ca3b2e2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -29,7 +29,6 @@
import android.view.ViewGroup;
import com.android.documentsui.State;
-
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -103,7 +102,7 @@
public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
if (payload.contains(SELECTION_CHANGED_MARKER)) {
final boolean selected = mEnv.isSelected(mModelIds.get(position));
- holder.setSelected(selected);
+ holder.setSelected(selected, true);
} else {
onBindViewHolder(holder, position);
}
@@ -124,7 +123,7 @@
assert(!selected);
}
holder.setEnabled(enabled);
- holder.setSelected(mEnv.isSelected(modelId));
+ holder.setSelected(mEnv.isSelected(modelId), false);
mEnv.onBindDocumentHolder(holder, cursor);
}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index b0cc09a..b80486d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -903,7 +903,7 @@
public Selection createFromParcel(Parcel in, ClassLoader loader) {
return new Selection(
in.readString(),
- (ArrayList<String>) in.readArrayList(loader));
+ in.readArrayList(loader));
}
@Override
@@ -931,7 +931,6 @@
Rect getAbsoluteRectForChildViewAt(int index);
int getAdapterPositionAt(int index);
int getColumnCount();
- int getRowCount();
int getChildCount();
int getVisibleChildCount();
/**
@@ -1008,13 +1007,6 @@
}
@Override
- public int getRowCount() {
- int numFullColumns = getChildCount() / getColumnCount();
- boolean hasPartiallyFullColumn = getChildCount() % getColumnCount() != 0;
- return numFullColumns + (hasPartiallyFullColumn ? 1 : 0);
- }
-
- @Override
public int getHeight() {
return mView.getHeight();
}
@@ -1202,6 +1194,7 @@
}
mCurrentPosition = input.getOrigin();
+ mModel.resizeSelection(input.getOrigin());
scrollViewIfNecessary();
resizeBandSelectRectangle();
}
@@ -1549,11 +1542,7 @@
mColumnBounds, new Limits(absoluteChildRect.left, absoluteChildRect.right));
}
- if (mRowBounds.size() != mHelper.getRowCount()) {
- // If not all y-limits have been recorded, record this one.
- recordLimits(
- mRowBounds, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
- }
+ recordLimits(mRowBounds, new Limits(absoluteChildRect.top, absoluteChildRect.bottom));
SparseIntArray columnList = mColumns.get(absoluteChildRect.left);
if (columnList == null) {
@@ -1747,6 +1736,11 @@
return ((Limits) other).lowerLimit == lowerLimit &&
((Limits) other).upperLimit == upperLimit;
}
+
+ @Override
+ public String toString() {
+ return "(" + lowerLimit + ", " + upperLimit + ")";
+ }
}
/**
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
index 3536593..c6ad511 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -284,7 +284,7 @@
String id = Integer.toString(i);
row.add(RootCursorWrapper.COLUMN_AUTHORITY, AUTHORITY);
row.add(Document.COLUMN_DOCUMENT_ID, id);
- currentDownloads.add(id);
+ currentDownloads.add(Model.createModelId(AUTHORITY, id));
}
DirectoryResult r = new DirectoryResult();
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
index 353d4bd..0c0e0b7 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
@@ -27,6 +27,7 @@
import com.android.documentsui.dirlist.MultiSelectManager.GridModel;
import java.util.ArrayList;
+import java.util.List;
import java.util.Set;
@SmallTest
@@ -42,6 +43,17 @@
private Set<String> lastSelection;
private int viewWidth;
+ // TLDR: Don't call model.{start|resize}Selection; use the local #startSelection and
+ // #resizeSelection methods instead.
+ //
+ // The reason for this is that selection is stateful and involves operations that take the
+ // current UI state (e.g scrolling) into account. This test maintains its own copy of the
+ // selection bounds as control data for verifying selections. Keep this data in sync by calling
+ // #startSelection and
+ // #resizeSelection.
+ private Point mSelectionOrigin;
+ private Point mSelectionPoint;
+
private void initData(final int numChildren, int numColumns) {
env = new TestEnvironment(numChildren, numColumns);
adapter = new TestDocumentsAdapter(new ArrayList<String>()) {
@@ -76,139 +88,241 @@
public void testSelectionLeftOfItems() {
initData(20, 5);
- model.startSelection(new Point(0, 10));
- model.resizeSelection(new Point(1, 11));
- assertSelected();
+ startSelection(new Point(0, 10));
+ resizeSelection(new Point(1, 11));
+ assertNoSelection();
assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testSelectionRightOfItems() {
initData(20, 4);
- model.startSelection(new Point(viewWidth - 1, 10));
- model.resizeSelection(new Point(viewWidth - 2, 11));
- assertSelected();
+ startSelection(new Point(viewWidth - 1, 10));
+ resizeSelection(new Point(viewWidth - 2, 11));
+ assertNoSelection();
assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testSelectionAboveItems() {
initData(20, 4);
- model.startSelection(new Point(10, 0));
- model.resizeSelection(new Point(11, 1));
- assertSelected();
+ startSelection(new Point(10, 0));
+ resizeSelection(new Point(11, 1));
+ assertNoSelection();
assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testSelectionBelowItems() {
initData(5, 4);
- model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
- model.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
- assertSelected();
+ startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
+ resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
+ assertNoSelection();
assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testVerticalSelectionBetweenItems() {
initData(20, 4);
- model.startSelection(new Point(106, 0));
- model.resizeSelection(new Point(107, 200));
- assertSelected();
+ startSelection(new Point(106, 0));
+ resizeSelection(new Point(107, 200));
+ assertNoSelection();
assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testHorizontalSelectionBetweenItems() {
initData(20, 4);
- model.startSelection(new Point(0, 105));
- model.resizeSelection(new Point(200, 106));
- assertSelected();
+ startSelection(new Point(0, 105));
+ resizeSelection(new Point(200, 106));
+ assertNoSelection();
assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testGrowingAndShrinkingSelection() {
initData(20, 4);
- model.startSelection(new Point(0, 0));
- model.resizeSelection(new Point(5, 5));
- assertSelected(0);
- model.resizeSelection(new Point(109, 109));
- assertSelected(0);
- model.resizeSelection(new Point(110, 109));
- assertSelected(0, 1);
- model.resizeSelection(new Point(110, 110));
- assertSelected(0, 1, 4, 5);
- model.resizeSelection(new Point(214, 214));
- assertSelected(0, 1, 4, 5);
- model.resizeSelection(new Point(215, 214));
- assertSelected(0, 1, 2, 4, 5, 6);
- model.resizeSelection(new Point(214, 214));
- assertSelected(0, 1, 4, 5);
- model.resizeSelection(new Point(110, 110));
- assertSelected(0, 1, 4, 5);
- model.resizeSelection(new Point(110, 109));
- assertSelected(0, 1);
- model.resizeSelection(new Point(109, 109));
- assertSelected(0);
- model.resizeSelection(new Point(5, 5));
- assertSelected(0);
- model.resizeSelection(new Point(0, 0));
- assertSelected();
+ startSelection(new Point(0, 0));
+
+ resizeSelection(new Point(5, 5));
+ verifySelection();
+
+ resizeSelection(new Point(109, 109));
+ verifySelection();
+
+ resizeSelection(new Point(110, 109));
+ verifySelection();
+
+ resizeSelection(new Point(110, 110));
+ verifySelection();
+
+ resizeSelection(new Point(214, 214));
+ verifySelection();
+
+ resizeSelection(new Point(215, 214));
+ verifySelection();
+
+ resizeSelection(new Point(214, 214));
+ verifySelection();
+
+ resizeSelection(new Point(110, 110));
+ verifySelection();
+
+ resizeSelection(new Point(110, 109));
+ verifySelection();
+
+ resizeSelection(new Point(109, 109));
+ verifySelection();
+
+ resizeSelection(new Point(5, 5));
+ verifySelection();
+
+ resizeSelection(new Point(0, 0));
+ verifySelection();
+
assertEquals(NOT_SET, model.getPositionNearestOrigin());
}
public void testSelectionMovingAroundOrigin() {
initData(16, 4);
- model.startSelection(new Point(210, 210));
- model.resizeSelection(new Point(viewWidth - 1, 0));
- assertSelected(2, 3, 6, 7);
- model.resizeSelection(new Point(0, 0));
- assertSelected(0, 1, 4, 5);
- model.resizeSelection(new Point(0, 420));
- assertSelected(8, 9, 12, 13);
- model.resizeSelection(new Point(viewWidth - 1, 420));
- assertSelected(10, 11, 14, 15);
- assertEquals(10, model.getPositionNearestOrigin());
+
+ startSelection(new Point(210, 210));
+ resizeSelection(new Point(viewWidth - 1, 0));
+ verifySelection();
+
+ resizeSelection(new Point(0, 0));
+ verifySelection();
+
+ resizeSelection(new Point(0, 420));
+ verifySelection();
+
+ resizeSelection(new Point(viewWidth - 1, 420));
+ verifySelection();
+
+ // This is manually figured and will need to be adjusted if the separator position is
+ // changed.
+ assertEquals(7, model.getPositionNearestOrigin());
}
public void testScrollingBandSelect() {
initData(40, 4);
- model.startSelection(new Point(0, 0));
- model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
- assertSelected(0, 4, 8, 12, 16);
+
+ startSelection(new Point(0, 0));
+ resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+ verifySelection();
+
scroll(CHILD_VIEW_EDGE_PX);
- assertSelected(0, 4, 8, 12, 16, 20);
- model.resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
- assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21);
+ verifySelection();
+
+ resizeSelection(new Point(200, VIEWPORT_HEIGHT - 1));
+ verifySelection();
+
scroll(CHILD_VIEW_EDGE_PX);
- assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17, 20, 21, 24, 25);
+ verifySelection();
+
scroll(-2 * CHILD_VIEW_EDGE_PX);
- assertSelected(0, 1, 4, 5, 8, 9, 12, 13, 16, 17);
- model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
- assertSelected(0, 4, 8, 12, 16);
+ verifySelection();
+
+ resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
+ verifySelection();
+
assertEquals(0, model.getPositionNearestOrigin());
}
- private void assertSelected(int... selectedPositions) {
- assertEquals(selectedPositions.length, lastSelection.size());
- for (int position : selectedPositions) {
- assertTrue(lastSelection.contains(Integer.toString(position)));
+ /** Returns the current selection area as a Rect. */
+ private Rect getSelectionArea() {
+ // Construct a rect from the two selection points.
+ Rect selectionArea = new Rect(
+ mSelectionOrigin.x, mSelectionOrigin.y, mSelectionOrigin.x, mSelectionOrigin.y);
+ selectionArea.union(mSelectionPoint.x, mSelectionPoint.y);
+ // Rect intersection tests are exclusive of bounds, while the MSM's selection code is
+ // inclusive. Expand the rect by 1 pixel in all directions to account for this.
+ selectionArea.inset(-1, -1);
+
+ return selectionArea;
+ }
+
+ /** Asserts that the selection is currently empty. */
+ private void assertNoSelection() {
+ assertEquals("Unexpected items " + lastSelection + " in selection " + getSelectionArea(),
+ 0, lastSelection.size());
+ }
+
+ /** Verifies the selection using actual bbox checks. */
+ private void verifySelection() {
+ Rect selectionArea = getSelectionArea();
+ for (TestEnvironment.Item item: env.items) {
+ if (Rect.intersects(selectionArea, item.rect)) {
+ assertTrue("Expected item " + item + " was not in selection " + selectionArea,
+ lastSelection.contains(item.name));
+ } else {
+ assertFalse("Unexpected item " + item + " in selection" + selectionArea,
+ lastSelection.contains(item.name));
+ }
}
}
+ private void startSelection(Point p) {
+ model.startSelection(p);
+ mSelectionOrigin = env.createAbsolutePoint(p);
+ }
+
+ private void resizeSelection(Point p) {
+ model.resizeSelection(p);
+ mSelectionPoint = env.createAbsolutePoint(p);
+ }
+
private void scroll(int dy) {
assertTrue(env.verticalOffset + VIEWPORT_HEIGHT + dy <= env.getTotalHeight());
env.verticalOffset += dy;
+ // Correct the cached selection point as well.
+ mSelectionPoint.y += dy;
model.onScrolled(null, 0, dy);
}
private static final class TestEnvironment implements MultiSelectManager.SelectionEnvironment {
- public int horizontalOffset = 0;
- public int verticalOffset = 0;
private final int mNumColumns;
private final int mNumRows;
private final int mNumChildren;
+ private final int mSeparatorPosition;
+
+ public int horizontalOffset = 0;
+ public int verticalOffset = 0;
+ private List<Item> items = new ArrayList<>();
public TestEnvironment(int numChildren, int numColumns) {
mNumChildren = numChildren;
mNumColumns = numColumns;
- mNumRows = (int) Math.ceil((double) numChildren / mNumColumns);
+ mSeparatorPosition = mNumColumns + 1;
+ mNumRows = setupGrid();
+ }
+
+ private int setupGrid() {
+ // Split the input set into folders and documents. Do this such that there is a
+ // partially-populated row in the middle of the grid, to test corner cases in layout
+ // code.
+ int y = VIEW_PADDING_PX;
+ int i = 0;
+ int numRows = 0;
+ while (i < mNumChildren) {
+ int top = y;
+ int height = CHILD_VIEW_EDGE_PX;
+ int width = CHILD_VIEW_EDGE_PX;
+ for (int j = 0; j < mNumColumns && i < mNumChildren; j++) {
+ int left = VIEW_PADDING_PX + (j * (width + VIEW_PADDING_PX));
+ items.add(new Item(
+ Integer.toString(i),
+ new Rect(
+ left,
+ top,
+ left + width - 1,
+ top + height - 1)));
+
+ // Create a partially populated row at the separator position.
+ if (++i == mSeparatorPosition) {
+ break;
+ }
+ }
+ y += height + VIEW_PADDING_PX;
+ numRows++;
+ }
+
+ return numRows;
}
private int getTotalHeight() {
@@ -227,8 +341,16 @@
private int getNumItemsInRow(int index) {
assertTrue(index >= 0 && index < mNumRows);
- if (index == mNumRows - 1 && mNumChildren % mNumColumns != 0) {
- return mNumChildren % mNumColumns;
+ int mod = mSeparatorPosition % mNumColumns;
+ if (index == (mSeparatorPosition / mNumColumns)) {
+ // The row containing the separator may be incomplete
+ return mod > 0 ? mod : mNumColumns;
+ }
+ // Account for the partial separator row in the final row tally.
+ if (index == mNumRows - 1) {
+ // The last row may be incomplete
+ int finalRowCount = (mNumChildren - mod) % mNumColumns;
+ return finalRowCount > 0 ? finalRowCount : mNumColumns;
}
return mNumColumns;
@@ -257,21 +379,18 @@
@Override
public int getAdapterPositionAt(int index) {
- return index + mNumColumns * (getFirstVisibleRowIndex());
+ // Account for partial rows by actually tallying up the items in hidden rows.
+ int hiddenCount = 0;
+ for (int i = 0; i < getFirstVisibleRowIndex(); i++) {
+ hiddenCount += getNumItemsInRow(i);
+ }
+ return index + hiddenCount;
}
@Override
public Rect getAbsoluteRectForChildViewAt(int index) {
- int adapterPosition = (getFirstVisibleRowIndex() * mNumColumns) + index;
- int rowIndex = adapterPosition / mNumColumns;
- int columnIndex = adapterPosition % mNumColumns;
-
- Rect rect = new Rect();
- rect.top = VIEW_PADDING_PX + rowIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
- rect.bottom = rect.top + CHILD_VIEW_EDGE_PX - 1;
- rect.left = VIEW_PADDING_PX + columnIndex * (CHILD_VIEW_EDGE_PX + VIEW_PADDING_PX);
- rect.right = rect.left + CHILD_VIEW_EDGE_PX - 1;
- return rect;
+ int adapterPosition = getAdapterPositionAt(index);
+ return items.get(adapterPosition).rect;
}
@Override
@@ -285,11 +404,6 @@
}
@Override
- public int getRowCount() {
- return mNumRows;
- }
-
- @Override
public void showBand(Rect rect) {
throw new UnsupportedOperationException();
}
@@ -328,5 +442,19 @@
public boolean isLayoutItem(int adapterPosition) {
return false;
}
+
+ public static final class Item {
+ public String name;
+ public Rect rect;
+
+ public Item(String n, Rect r) {
+ name = n;
+ rect = r;
+ }
+
+ public String toString() {
+ return name + ": " + rect;
+ }
+ }
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
index 2d819ff..d8c29db 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
@@ -62,7 +62,9 @@
update(r);
}
+ // Note that model id includes authority qualifier and is distinct
+ // WRT documentId because of this.
String idForPosition(int p) {
- return Integer.toString(p);
+ return createModelId(mAuthority, Integer.toString(p));
}
}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
index 8e624a0..56e54a6 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
@@ -87,11 +87,6 @@
}
@Override
- public int getRowCount() {
- return 0;
- }
-
- @Override
public int getChildCount() {
return 0;
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java b/packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java
similarity index 83%
rename from packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
rename to packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java
index 55f55b0..83488cd 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/BusyDeviceException.java
@@ -14,12 +14,15 @@
* limitations under the License.
*/
-package com.android.mtp.exceptions;
+package com.android.mtp;
import java.io.IOException;
/**
* Exception thrown when the device is busy and the requested operation cannon be completed.
*/
-public class BusyDeviceException extends IOException {
+class BusyDeviceException extends IOException {
+ BusyDeviceException() {
+ super("The MTP device is busy.");
+ }
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 4582226..68c1992 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -30,6 +30,8 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.CancellationSignal;
+import android.os.FileUriExposedException;
+import android.os.FileUtils;
import android.os.ParcelFileDescriptor;
import android.os.storage.StorageManager;
import android.provider.DocumentsContract.Document;
@@ -41,7 +43,6 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -324,25 +325,61 @@
if (DEBUG) {
Log.d(TAG, "createDocument: " + displayName);
}
+ final Identifier parentId;
+ final MtpDeviceRecord record;
+ final ParcelFileDescriptor[] pipe;
try {
- final Identifier parentId = mDatabase.createIdentifier(parentDocumentId);
+ parentId = mDatabase.createIdentifier(parentDocumentId);
openDevice(parentId.mDeviceId);
- final MtpDeviceRecord record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord;
+ record = getDeviceToolkit(parentId.mDeviceId).mDeviceRecord;
if (!MtpDeviceRecord.isWritingSupported(record.operationsSupported)) {
- throw new UnsupportedOperationException();
+ throw new UnsupportedOperationException(
+ "Writing operation is not supported by the device.");
}
- final ParcelFileDescriptor pipe[] = ParcelFileDescriptor.createReliablePipe();
- pipe[0].close(); // 0 bytes for a new document.
- final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
- MtpConstants.FORMAT_ASSOCIATION :
- MediaFile.getFormatCode(displayName, mimeType);
- final MtpObjectInfo info = new MtpObjectInfo.Builder()
- .setStorageId(parentId.mStorageId)
- .setParent(parentId.mObjectHandle)
- .setFormat(formatCode)
- .setName(displayName)
- .build();
- final int objectHandle = mMtpManager.createDocument(parentId.mDeviceId, info, pipe[1]);
+ pipe = ParcelFileDescriptor.createReliablePipe();
+ int objectHandle = -1;
+ MtpObjectInfo info = null;
+ try {
+ pipe[0].close(); // 0 bytes for a new document.
+
+ final int formatCode = Document.MIME_TYPE_DIR.equals(mimeType) ?
+ MtpConstants.FORMAT_ASSOCIATION :
+ MediaFile.getFormatCode(displayName, mimeType);
+ info = new MtpObjectInfo.Builder()
+ .setStorageId(parentId.mStorageId)
+ .setParent(parentId.mObjectHandle)
+ .setFormat(formatCode)
+ .setName(displayName)
+ .build();
+
+ final String[] parts = FileUtils.splitFileName(mimeType, displayName);
+ final String baseName = parts[0];
+ final String extension = parts[1];
+ for (int i = 0; i <= 32; i++) {
+ final MtpObjectInfo infoUniqueName;
+ if (i == 0) {
+ infoUniqueName = info;
+ } else {
+ infoUniqueName = new MtpObjectInfo.Builder(info).setName(
+ baseName + " (" + i + ")." + extension).build();
+ }
+ try {
+ objectHandle = mMtpManager.createDocument(
+ parentId.mDeviceId, infoUniqueName, pipe[1]);
+ break;
+ } catch (SendObjectInfoFailure exp) {
+ // This can be caused when we have an existing file with the same name.
+ continue;
+ }
+ }
+ } finally {
+ pipe[1].close();
+ }
+ if (objectHandle == -1) {
+ throw new IllegalArgumentException(
+ "The file name \"" + displayName + "\" is conflicted with existing files " +
+ "and the provider failed to find unique name.");
+ }
final MtpObjectInfo infoWithHandle =
new MtpObjectInfo.Builder(info).setObjectHandle(objectHandle).build();
final String documentId = mDatabase.putNewDocument(
@@ -351,9 +388,12 @@
getDocumentLoader(parentId).clearTask(parentId);
notifyChildDocumentsChange(parentDocumentId);
return documentId;
+ } catch (FileNotFoundException | RuntimeException error) {
+ Log.e(TAG, "createDocument", error);
+ throw error;
} catch (IOException error) {
Log.e(TAG, "createDocument", error);
- throw new FileNotFoundException(error.getMessage());
+ throw new IllegalStateException(error);
}
}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 0202343..6fb2a78 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -33,7 +33,6 @@
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.mtp.exceptions.BusyDeviceException;
import java.io.FileNotFoundException;
import java.io.IOException;
@@ -190,7 +189,7 @@
synchronized (device) {
final MtpObjectInfo sendObjectInfoResult = device.sendObjectInfo(objectInfo);
if (sendObjectInfoResult == null) {
- throw new IOException("Failed to create a document");
+ throw new SendObjectInfoFailure();
}
if (objectInfo.getFormat() != MtpConstants.FORMAT_ASSOCIATION) {
if (!device.sendObject(sendObjectInfoResult.getObjectHandle(),
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java b/packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java
similarity index 75%
copy from packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
copy to packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java
index 55f55b0..db7d777 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/exceptions/BusyDeviceException.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/SendObjectInfoFailure.java
@@ -14,12 +14,15 @@
* limitations under the License.
*/
-package com.android.mtp.exceptions;
+package com.android.mtp;
import java.io.IOException;
/**
- * Exception thrown when the device is busy and the requested operation cannon be completed.
+ * Exception thrown when sendObjectInfo failed.
*/
-public class BusyDeviceException extends IOException {
+class SendObjectInfoFailure extends IOException {
+ SendObjectInfoFailure() {
+ super("Failed to MtpDevice#sendObjectInfo.");
+ }
}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index afcb457..9c1880a 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -30,8 +30,6 @@
import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.MediumTest;
-import com.android.mtp.exceptions.BusyDeviceException;
-
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Arrays;
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
index 606f4eb..645e182 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PageAdapter.java
@@ -20,6 +20,8 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
+import android.os.Handler;
+import android.os.Looper;
import android.os.ParcelFileDescriptor;
import android.print.PageRange;
import android.print.PrintAttributes.MediaSize;
@@ -570,7 +572,14 @@
if (DEBUG) {
Log.i(LOG_TAG, "Requesting pages: " + Arrays.toString(mRequestedPages));
}
- mCallbacks.onRequestContentUpdate();
+
+ // This call might come from a recylerview that is currently updating. Hence delay to
+ // after the update
+ (new Handler(Looper.getMainLooper())).post(new Runnable() {
+ @Override public void run() {
+ mCallbacks.onRequestContentUpdate();
+ }
+ });
}
}
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index e4c2cbc..1aee490 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -687,7 +687,7 @@
<!-- Developer settings: select WebView provider dialog title [CHAR LIMIT=30] -->
<string name="select_webview_provider_dialog_title">Set WebView implementation</string>
<!-- Developer settings: text for the WebView provider selection toast shown if an invalid provider was chosen (i.e. the setting list was stale). [CHAR LIMIT=NONE] -->
- <string name="select_webview_provider_toast_text">The chosen WebView implementation is invalid because the list of implementation choices grew stale. The list should now be updated.</string>
+ <string name="select_webview_provider_toast_text">This choice is no longer valid. Try again.</string>
<!-- Developer settings screen, convert userdata to file encryption option name -->
<string name="convert_to_file_encryption">Convert to file encryption</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index fa2226d..74c1ebd 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -151,10 +151,17 @@
if (sSystemSignature == null) {
sSystemSignature = new Signature[]{ getSystemSignature(pm) };
}
- return sSystemSignature[0] != null && sSystemSignature[0].equals(getFirstSignature(pkg));
+ if (sPermissionControllerPackageName == null) {
+ sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
+ }
+ return (sSystemSignature[0] != null
+ && sSystemSignature[0].equals(getFirstSignature(pkg)))
+ || (sPermissionControllerPackageName != null
+ && sPermissionControllerPackageName.equals(pkg.packageName));
}
private static Signature[] sSystemSignature;
+ private static String sPermissionControllerPackageName;
private static Signature getFirstSignature(PackageInfo pkg) {
if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index 7a1c741..ce69c5a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -103,16 +103,6 @@
}
@Override
- public void onBackPressed() {
- if (mShowingMenu) {
- // If we are showing the menu, then we are a top level activity and the back should
- // kick back to settings home.
- openTile(null);
- }
- super.onBackPressed();
- }
-
- @Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
&& mDrawerAdapter.getCount() != 0) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 987b5ea..743912a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -207,6 +207,10 @@
@Override
public Bundle call(String method, String name, Bundle args) {
+ // If the remote side sent us bad parcelables, they won't get the
+ // results they want, which is their loss.
+ if (args != null) args.setDefusable(true);
+
final int requestingUserId = getRequestingUserId(args);
switch (method) {
case Settings.CALL_METHOD_GET_GLOBAL: {
diff --git a/packages/SystemUI/res/drawable-hdpi/recents_empty.png b/packages/SystemUI/res/drawable-hdpi/recents_empty.png
deleted file mode 100755
index dec97b6..0000000
--- a/packages/SystemUI/res/drawable-hdpi/recents_empty.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/recents_empty.png b/packages/SystemUI/res/drawable-mdpi/recents_empty.png
deleted file mode 100755
index d16763a..0000000
--- a/packages/SystemUI/res/drawable-mdpi/recents_empty.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/recents_empty.png b/packages/SystemUI/res/drawable-xhdpi/recents_empty.png
deleted file mode 100755
index 1e02844..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/recents_empty.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/recents_empty.png b/packages/SystemUI/res/drawable-xxhdpi/recents_empty.png
deleted file mode 100755
index 9d94be7..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/recents_empty.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/recents_empty.png b/packages/SystemUI/res/drawable-xxxhdpi/recents_empty.png
deleted file mode 100755
index 24599c3..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/recents_empty.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_empty.xml b/packages/SystemUI/res/drawable/recents_empty.xml
new file mode 100644
index 0000000..5506de1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_empty.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="100dp"
+ android:height="132dp"
+ android:viewportWidth="100"
+ android:viewportHeight="132">
+
+ <path
+ android:fillColor="#5AFFFFFF"
+ android:pathData="M86.91,68.67H13.09c-4.96,0-9,4.04-9,9V119c0,4.96,4.04,9,9,9h73.82c4.96,0,9-4.04,9-9V77.67
+C95.91,72.7,91.87,68.67,86.91,68.67z M27.59,77.27h26.72v3.94H27.59V77.27z
+M18.73,74.74c2.49,0,4.5,2.01,4.5,4.5
+c0,2.49-2.01,4.5-4.5,4.5s-4.5-2.01-4.5-4.5C14.23,76.75,16.24,74.74,18.73,74.74z
+M89.91,119c0,1.65-1.35,3-3,3H13.09 c-1.65,0-3-1.35-3-3V88.67h79.82V119z" />
+ <path
+ android:fillColor="#5AFFFFFF"
+ android:pathData="M86.91,36.3H13.09c-4.96,0-9,4.04-9,9v23c1.65-1.58,3.71-2.73,6-3.28v-9.08h79.82v9.08
+c2.29,0.55,4.35,1.69,6,3.28v-23C95.91,40.34,91.87,36.3,86.91,36.3z
+M18.73,51.38c-2.49,0-4.5-2.01-4.5-4.5s2.01-4.5,4.5-4.5
+s4.5,2.01,4.5,4.5S21.22,51.38,18.73,51.38z M54.31,48.84H27.59v-3.94h26.72V48.84z" />
+ <path
+ android:fillColor="#5AFFFFFF"
+ android:pathData="M86.91,4H13.09c-4.96,0-9,4.04-9,9v22.94c1.65-1.58,3.71-2.73,6-3.28V24h79.82v8.67
+c2.29,0.55,4.35,1.69,6,3.28V13C95.91,8.04,91.87,4,86.91,4z
+M18.73,18.5c-2.49,0-4.5-2.01-4.5-4.5s2.01-4.5,4.5-4.5
+s4.5,2.01,4.5,4.5S21.22,18.5,18.73,18.5z M54.31,15.97H27.59v-3.94h26.72V15.97z" />
+ <path
+ android:pathData="M 0 0 H 100 V 132 H 0 V 0 Z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_detail_header.xml b/packages/SystemUI/res/layout/qs_detail_header.xml
index df46271..c062b6d 100644
--- a/packages/SystemUI/res/layout/qs_detail_header.xml
+++ b/packages/SystemUI/res/layout/qs_detail_header.xml
@@ -30,6 +30,7 @@
android:padding="16dp"
android:clickable="true"
android:background="?android:attr/selectableItemBackground"
+ android:contentDescription="@*android:string/action_bar_up_description"
android:src="?android:attr/homeAsUpIndicator" />
<TextView
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 420a939..5295ccb 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1432,6 +1432,9 @@
<!-- Label for area where tiles can be dragged out of [CHAR LIMIT=60] -->
<string name="drag_to_add_tiles">Drag to add tiles</string>
+ <!-- Label for area where tiles can be dragged in to [CHAR LIMIT=60] -->
+ <string name="drag_to_remove_tiles">Drag here to remove</string>
+
<!-- Button to edit the tile ordering of quick settings [CHAR LIMIT=60] -->
<string name="qs_edit">Edit</string>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 72a59d7..aeca840 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -128,6 +128,7 @@
public void hide(int x, int y) {
if (isShown) {
isShown = false;
+ mToolbar.dismissPopupMenus();
setCustomizing(false);
save();
mClipper.animateCircularClip(x, y, false, mCollapseAnimationListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index d9b3b3f..57db3a6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -28,6 +28,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
+import android.widget.TextView;
import com.android.systemui.R;
import com.android.systemui.qs.QSIconView;
import com.android.systemui.qs.QSTileView;
@@ -153,7 +154,12 @@
@Override
public void onBindViewHolder(final Holder holder, int position) {
- if (holder.getItemViewType() == TYPE_EDIT) return;
+ if (holder.getItemViewType() == TYPE_EDIT) {
+ ((TextView) holder.itemView.findViewById(android.R.id.title)).setText(
+ mCurrentDrag != null ? R.string.drag_to_remove_tiles
+ : R.string.drag_to_add_tiles);
+ return;
+ }
TileInfo info = mTiles.get(position);
holder.mTileView.onStateChanged(info.state);
@@ -250,11 +256,13 @@
super.onSelectedChanged(viewHolder, actionState);
if (mCurrentDrag != null) {
mCurrentDrag.stopDrag();
+ mCurrentDrag = null;
}
if (viewHolder != null) {
mCurrentDrag = (Holder) viewHolder;
mCurrentDrag.startDrag();
}
+ notifyItemChanged(mDividerIndex);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 143f160..8f1517d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -20,6 +20,7 @@
import android.animation.AnimatorListenerAdapter;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
+import android.app.KeyguardManager;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -31,6 +32,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.IntentSender;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -138,6 +140,8 @@
protected static final boolean ENABLE_HEADS_UP = true;
protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
+ private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
+
// Should match the values in PhoneWindowManager
public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
@@ -146,6 +150,8 @@
"com.android.systemui.statusbar.banner_action_cancel";
private static final String BANNER_ACTION_SETUP =
"com.android.systemui.statusbar.banner_action_setup";
+ private static final String WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION
+ = "com.android.systemui.statusbar.work_challenge_unlocked_notification_action";
protected CommandQueue mCommandQueue;
protected IStatusBarService mBarService;
@@ -199,6 +205,9 @@
private UserManager mUserManager;
private int mDensity;
+ private KeyguardManager mKeyguardManager;
+ private LockPatternUtils mLockPatternUtils;
+
// UI-specific methods
/**
@@ -499,6 +508,20 @@
);
}
+ } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
+ final IntentSender intentSender = (IntentSender) intent
+ .getParcelableExtra(Intent.EXTRA_INTENT);
+ final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
+ try {
+ mContext.startIntentSender(intentSender, null, 0, 0, 0);
+ } catch (IntentSender.SendIntentException e) {
+ /* ignore */
+ }
+ try {
+ mBarService.onNotificationClick(notificationKey);
+ } catch (RemoteException e) {
+ /* ignore */
+ }
}
}
};
@@ -661,6 +684,8 @@
mDensity = currentConfig.densityDpi;
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mKeyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
+ mLockPatternUtils = new LockPatternUtils(mContext);
// Connect in to the status bar manager service
mCommandQueue = new CommandQueue(this);
@@ -723,10 +748,14 @@
filter.addAction(Intent.ACTION_USER_SWITCHED);
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_PRESENT);
- filter.addAction(BANNER_ACTION_CANCEL);
- filter.addAction(BANNER_ACTION_SETUP);
mContext.registerReceiver(mBroadcastReceiver, filter);
+ IntentFilter internalFilter = new IntentFilter();
+ internalFilter.addAction(WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+ internalFilter.addAction(BANNER_ACTION_CANCEL);
+ internalFilter.addAction(BANNER_ACTION_SETUP);
+ mContext.registerReceiver(mBroadcastReceiver, internalFilter, PERMISSION_SELF, null);
+
IntentFilter allUsersFilter = new IntentFilter();
allUsersFilter.addAction(
DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
@@ -739,8 +768,7 @@
if (0 != Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 1)) {
Log.d(TAG, "user hasn't seen notification about hidden notifications");
- final LockPatternUtils lockPatternUtils = new LockPatternUtils(mContext);
- if (!lockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
+ if (!mLockPatternUtils.isSecure(KeyguardUpdateMonitor.getCurrentUser())) {
Log.d(TAG, "insecure lockscreen, skipping notification");
Settings.Secure.putInt(mContext.getContentResolver(),
Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING, 0);
@@ -1680,7 +1708,6 @@
ActivityManagerNative.getDefault().resumeAppSwitches();
} catch (RemoteException e) {
}
-
try {
intent.send();
} catch (PendingIntent.CanceledException e) {
@@ -1773,8 +1800,22 @@
ActivityManagerNative.getDefault().resumeAppSwitches();
} catch (RemoteException e) {
}
-
if (intent != null) {
+ // If we are launching a work activity and require to launch
+ // separate work challenge, we defer the activity action and cancel
+ // notification until work challenge is unlocked.
+ if (intent.isActivity()) {
+ final int userId = intent.getCreatorUserHandle()
+ .getIdentifier();
+ if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)
+ && mKeyguardManager.isDeviceLocked(userId)) {
+ // Show work challenge, do not run pendingintent and
+ // remove notification
+ startWorkChallenge(userId, intent.getIntentSender(),
+ notificationKey);
+ return;
+ }
+ }
try {
intent.send();
} catch (PendingIntent.CanceledException e) {
@@ -1809,6 +1850,23 @@
}, afterKeyguardGone);
}
+ public void startWorkChallenge(int userId, IntentSender intendSender,
+ String notificationKey) {
+ final Intent callBackIntent = new Intent(
+ WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION);
+ callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender);
+ callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
+ callBackIntent.setPackage(mContext.getPackageName());
+
+ final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null,
+ null, userId);
+ newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+ | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ newIntent.putExtra(Intent.EXTRA_INTENT, PendingIntent
+ .getBroadcast(mContext, 0, callBackIntent, 0).getIntentSender());
+ mContext.startActivity(newIntent);
+ }
+
public void register(ExpandableNotificationRow row, StatusBarNotification sbn) {
Notification notification = sbn.getNotification();
if (notification.contentIntent != null || notification.fullScreenIntent != null) {
@@ -1856,15 +1914,16 @@
/**
* The LEDs are turned off when the notification panel is shown, even just a little bit.
+ * See also NotificationStackScrollLayout.setIsExpanded() for another place where we
+ * attempt to do this.
*/
protected void handleVisibleToUserChanged(boolean visibleToUser) {
try {
if (visibleToUser) {
boolean pinnedHeadsUp = mHeadsUpManager.hasPinnedHeadsUp();
boolean clearNotificationEffects =
- ((mShowLockscreenNotifications && mState == StatusBarState.KEYGUARD) ||
- (!pinnedHeadsUp && (mState == StatusBarState.SHADE
- || mState == StatusBarState.SHADE_LOCKED)));
+ !isPanelFullyCollapsed() &&
+ (mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
int notificationLoad = mNotificationData.getActiveNotifications().size();
if (pinnedHeadsUp && isPanelFullyCollapsed()) {
notificationLoad = 1;
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 e53f044..99896f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,7 +36,6 @@
import android.util.Log;
import android.util.SparseArray;
import android.view.Display;
-import android.view.Gravity;
import android.view.IDockedStackListener.Stub;
import android.view.MotionEvent;
import android.view.Surface;
@@ -46,7 +45,6 @@
import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
import android.widget.LinearLayout;
-
import com.android.systemui.R;
import com.android.systemui.RecentsComponent;
import com.android.systemui.stackdivider.Divider;
@@ -54,7 +52,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import java.util.ArrayList;
public class NavigationBarView extends LinearLayout {
final static boolean DEBUG = false;
@@ -100,6 +97,7 @@
private boolean mDockedStackExists;
private final SparseArray<ButtonDispatcher> mButtonDisatchers = new SparseArray<>();
+ private int mDensity;
private class NavTransitionListener implements TransitionListener {
private boolean mBackTransitioning;
@@ -190,6 +188,7 @@
mShowMenu = false;
mGestureHelper = new NavigationBarGestureHelper(context);
+ mDensity = context.getResources().getConfiguration().densityDpi;
getIcons(context);
mBarTransitions = new NavigationBarTransitions(this);
@@ -599,6 +598,10 @@
// we are switching to.
setNavigationIconHints(mNavigationIconHints, true);
}
+ if (mDensity != newConfig.densityDpi) {
+ mDensity = newConfig.densityDpi;
+ getIcons(getContext());
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
index f03d9e9..c6b1cdf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HotspotControllerImpl.java
@@ -69,18 +69,22 @@
@Override
public void addCallback(Callback callback) {
- if (callback == null || mCallbacks.contains(callback)) return;
- if (DEBUG) Log.d(TAG, "addCallback " + callback);
- mCallbacks.add(callback);
- mReceiver.setListening(!mCallbacks.isEmpty());
+ synchronized (mCallbacks) {
+ if (callback == null || mCallbacks.contains(callback)) return;
+ if (DEBUG) Log.d(TAG, "addCallback " + callback);
+ mCallbacks.add(callback);
+ mReceiver.setListening(!mCallbacks.isEmpty());
+ }
}
@Override
public void removeCallback(Callback callback) {
if (callback == null) return;
if (DEBUG) Log.d(TAG, "removeCallback " + callback);
- mCallbacks.remove(callback);
- mReceiver.setListening(!mCallbacks.isEmpty());
+ synchronized (mCallbacks) {
+ mCallbacks.remove(callback);
+ mReceiver.setListening(!mCallbacks.isEmpty());
+ }
}
@Override
@@ -110,8 +114,10 @@
}
private void fireCallback(boolean isEnabled) {
- for (Callback callback : mCallbacks) {
- callback.onHotspotChanged(isEnabled);
+ synchronized (mCallbacks) {
+ for (Callback callback : mCallbacks) {
+ callback.onHotspotChanged(isEnabled);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index d9b78a2..59ec6112 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2691,6 +2691,16 @@
if (changed) {
if (!mIsExpanded) {
mGroupManager.collapseAllGroups();
+ } else {
+ // XXX: HACK: we should not be clearing notification effects from way down here.
+ // But at the moment we don't have a reliable way to know when the window is
+ // actually exposed to the air, so
+ if (mPhoneStatusBar.getBarState() != StatusBarState.KEYGUARD) {
+ if (DEBUG) {
+ Log.v(TAG, "clearing notification effects from scroller");
+ }
+ mPhoneStatusBar.clearNotificationEffects();
+ }
}
updateNotificationAnimationStates();
updateChronometers();
diff --git a/services/core/Android.mk b/services/core/Android.mk
index aaa2211..99c5dd6 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -7,7 +7,8 @@
LOCAL_SRC_FILES += \
$(call all-java-files-under,java) \
java/com/android/server/EventLogTags.logtags \
- java/com/android/server/am/EventLogTags.logtags
+ java/com/android/server/am/EventLogTags.logtags \
+ ../../../../system/netd/server/binder/android/net/INetd.aidl
LOCAL_JAVA_LIBRARIES := services.net telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index bfe9e8e..a94c8b8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -121,6 +121,8 @@
* - SparseArray w/ mapping:
* AppOp code --> Set of packages that are not restricted for this code
*
+ * For efficiency, a core assumption here is that the number of per-package exemptions stored
+ * here will be relatively small. If this changes, this data structure should be revisited.
*/
private final ArrayMap<IBinder, SparseArray<Pair<boolean[], SparseArray<ArraySet<String>>>>>
mOpUserRestrictions = new ArrayMap<>();
@@ -445,8 +447,12 @@
int[] ops) {
mContext.enforcePermission(android.Manifest.permission.GET_APP_OPS_STATS,
Binder.getCallingPid(), Binder.getCallingUid(), null);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return Collections.emptyList();
+ }
synchronized (this) {
- Ops pkgOps = getOpsLocked(uid, packageName, false);
+ Ops pkgOps = getOpsRawLocked(uid, resolvedPackageName, false);
if (pkgOps == null) {
return null;
}
@@ -464,7 +470,7 @@
private void pruneOp(Op op, int uid, String packageName) {
if (op.time == 0 && op.rejectTime == 0) {
- Ops ops = getOpsLocked(uid, packageName, false);
+ Ops ops = getOpsRawLocked(uid, packageName, false);
if (ops != null) {
ops.remove(op.op);
if (ops.size() <= 0) {
@@ -878,8 +884,12 @@
public int checkOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
synchronized (this) {
- if (isOpRestricted(uid, code, packageName)) {
+ if (isOpRestricted(uid, code, resolvedPackageName)) {
return AppOpsManager.MODE_IGNORED;
}
code = AppOpsManager.opToSwitch(code);
@@ -890,7 +900,7 @@
return uidMode;
}
}
- Op op = getOpLocked(code, uid, packageName, false);
+ Op op = getOpLocked(code, uid, resolvedPackageName, false);
if (op == null) {
return AppOpsManager.opToDefaultMode(code);
}
@@ -966,6 +976,7 @@
@Override
public int checkPackage(int uid, String packageName) {
+ Preconditions.checkNotNull(packageName);
synchronized (this) {
if (getOpsRawLocked(uid, packageName, true) != null) {
return AppOpsManager.MODE_ALLOWED;
@@ -979,26 +990,39 @@
public int noteProxyOperation(int code, String proxyPackageName,
int proxiedUid, String proxiedPackageName) {
verifyIncomingOp(code);
- final int proxyMode = noteOperationUnchecked(code, Binder.getCallingUid(),
- proxyPackageName, -1, null);
+ final int proxyUid = Binder.getCallingUid();
+ String resolveProxyPackageName = resolvePackageName(proxyUid, proxyPackageName);
+ if (resolveProxyPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ final int proxyMode = noteOperationUnchecked(code, proxyUid,
+ resolveProxyPackageName, -1, null);
if (proxyMode != AppOpsManager.MODE_ALLOWED || Binder.getCallingUid() == proxiedUid) {
return proxyMode;
}
- return noteOperationUnchecked(code, proxiedUid, proxiedPackageName,
- Binder.getCallingUid(), proxyPackageName);
+ String resolveProxiedPackageName = resolvePackageName(proxiedUid, proxiedPackageName);
+ if (resolveProxiedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ return noteOperationUnchecked(code, proxiedUid, resolveProxiedPackageName,
+ proxyMode, resolveProxyPackageName);
}
@Override
public int noteOperation(int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- return noteOperationUnchecked(code, uid, packageName, 0, null);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
+ return noteOperationUnchecked(code, uid, resolvedPackageName, 0, null);
}
private int noteOperationUnchecked(int code, int uid, String packageName,
int proxyUid, String proxyPackageName) {
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, packageName, true);
if (ops == null) {
if (DEBUG) Log.d(TAG, "noteOperation: no op for code " + code + " uid " + uid
+ " package " + packageName);
@@ -1046,16 +1070,20 @@
public int startOperation(IBinder token, int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return AppOpsManager.MODE_IGNORED;
+ }
ClientState client = (ClientState)token;
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, resolvedPackageName, true);
if (ops == null) {
if (DEBUG) Log.d(TAG, "startOperation: no op for code " + code + " uid " + uid
- + " package " + packageName);
+ + " package " + resolvedPackageName);
return AppOpsManager.MODE_ERRORED;
}
Op op = getOpLocked(ops, code, true);
- if (isOpRestricted(uid, code, packageName)) {
+ if (isOpRestricted(uid, code, resolvedPackageName)) {
return AppOpsManager.MODE_IGNORED;
}
final int switchCode = AppOpsManager.opToSwitch(code);
@@ -1065,7 +1093,7 @@
if (uidMode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Log.d(TAG, "noteOperation: reject #" + op.mode + " for code "
+ switchCode + " (" + code + ") uid " + uid + " package "
- + packageName);
+ + resolvedPackageName);
op.rejectTime = System.currentTimeMillis();
return uidMode;
}
@@ -1073,12 +1101,13 @@
final Op switchOp = switchCode != code ? getOpLocked(ops, switchCode, true) : op;
if (switchOp.mode != AppOpsManager.MODE_ALLOWED) {
if (DEBUG) Log.d(TAG, "startOperation: reject #" + op.mode + " for code "
- + switchCode + " (" + code + ") uid " + uid + " package " + packageName);
+ + switchCode + " (" + code + ") uid " + uid + " package "
+ + resolvedPackageName);
op.rejectTime = System.currentTimeMillis();
return switchOp.mode;
}
if (DEBUG) Log.d(TAG, "startOperation: allowing code " + code + " uid " + uid
- + " package " + packageName);
+ + " package " + resolvedPackageName);
if (op.nesting == 0) {
op.time = System.currentTimeMillis();
op.rejectTime = 0;
@@ -1096,9 +1125,16 @@
public void finishOperation(IBinder token, int code, int uid, String packageName) {
verifyIncomingUid(uid);
verifyIncomingOp(code);
- ClientState client = (ClientState)token;
+ String resolvedPackageName = resolvePackageName(uid, packageName);
+ if (resolvedPackageName == null) {
+ return;
+ }
+ if (!(token instanceof ClientState)) {
+ return;
+ }
+ ClientState client = (ClientState) token;
synchronized (this) {
- Op op = getOpLocked(code, uid, packageName, true);
+ Op op = getOpLocked(code, uid, resolvedPackageName, true);
if (op == null) {
return;
}
@@ -1114,6 +1150,9 @@
@Override
public int permissionToOpCode(String permission) {
+ if (permission == null) {
+ return AppOpsManager.OP_NONE;
+ }
return AppOpsManager.permissionToOpCode(permission);
}
@@ -1163,15 +1202,6 @@
return uidState;
}
- private Ops getOpsLocked(int uid, String packageName, boolean edit) {
- if (uid == 0) {
- packageName = "root";
- } else if (uid == Process.SHELL_UID) {
- packageName = "com.android.shell";
- }
- return getOpsRawLocked(uid, packageName, edit);
- }
-
private Ops getOpsRawLocked(int uid, String packageName, boolean edit) {
UidState uidState = getUidStateLocked(uid, edit);
if (uidState == null) {
@@ -1257,7 +1287,7 @@
}
private Op getOpLocked(int code, int uid, String packageName, boolean edit) {
- Ops ops = getOpsLocked(uid, packageName, edit);
+ Ops ops = getOpsRawLocked(uid, packageName, edit);
if (ops == null) {
return null;
}
@@ -1304,15 +1334,18 @@
}
if (opRestrictions[code]) {
- if (opExceptions != null && opExceptions.get(code) != null &&
- opExceptions.get(code).contains(packageName)) {
- continue; // AppOps code is restricted, but this package is exempt
+
+ if (opExceptions != null) {
+ ArraySet<String> ex = opExceptions.get(code);
+ if (ex != null && ex.contains(packageName)) {
+ continue; // AppOps code is restricted, but this package is exempt
+ }
}
if (AppOpsManager.opAllowSystemBypassRestriction(code)) {
// If we are the system, bypass user restrictions for certain codes
synchronized (this) {
- Ops ops = getOpsLocked(uid, packageName, true);
+ Ops ops = getOpsRawLocked(uid, packageName, true);
if ((ops != null) && ops.isPrivileged) {
return false;
}
@@ -1577,7 +1610,7 @@
out.startTag(null, "uid");
out.attribute(null, "n", Integer.toString(pkg.getUid()));
synchronized (this) {
- Ops ops = getOpsLocked(pkg.getUid(), pkg.getPackageName(), false);
+ Ops ops = getOpsRawLocked(pkg.getUid(), pkg.getPackageName(), false);
// Should always be present as the list of PackageOps is generated
// from Ops.
if (ops != null) {
@@ -2098,6 +2131,7 @@
@Override
public void setUserRestrictions(Bundle restrictions, IBinder token, int userHandle) {
checkSystemUid("setUserRestrictions");
+ Preconditions.checkNotNull(restrictions);
Preconditions.checkNotNull(token);
final boolean[] opRestrictions = getOrCreateUserRestrictionsForToken(token, userHandle);
for (int i = 0; i < opRestrictions.length; ++i) {
@@ -2143,9 +2177,8 @@
final SparseArray<ArraySet<String>> opExceptions =
getUserPackageExemptionsForToken(token, userHandle);
- // If exceptionPackages is not null, update the exception packages for this AppOps code
ArraySet<String> exceptions = opExceptions.get(code);
- if (exceptionPackages != null) {
+ if (exceptionPackages != null && exceptionPackages.length > 0) {
if (exceptions == null) {
exceptions = new ArraySet<>(exceptionPackages.length);
opExceptions.put(code, exceptions);
@@ -2153,7 +2186,11 @@
exceptions.clear();
}
- exceptions.addAll(Arrays.asList(exceptionPackages));
+ for (String p : exceptionPackages) {
+ exceptions.add(p);
+ }
+ } else {
+ opExceptions.remove(code);
}
}
@@ -2219,14 +2256,23 @@
if (restrictions != null) {
final boolean[] opRestrictions = restrictions.first;
+ final SparseArray<ArraySet<String>> opExceptions = restrictions.second;
+ boolean stillHasRestrictions = false;
if (opRestrictions != null) {
- for (boolean restriction : opRestrictions) {
+ for (int i = 0; i < opRestrictions.length; i++) {
+ boolean restriction = opRestrictions[i];
if (restriction) {
- return;
+ stillHasRestrictions = true;
+ } else {
+ opExceptions.remove(i);
}
}
}
+ if (stillHasRestrictions) {
+ return;
+ }
+
// No restrictions set for this client
perTokenRestrictions.remove(userHandle);
if (perTokenRestrictions.size() <= 0) {
@@ -2300,6 +2346,15 @@
}
}
+ private static String resolvePackageName(int uid, String packageName) {
+ if (uid == 0) {
+ return "root";
+ } else if (uid == Process.SHELL_UID) {
+ return "com.android.shell";
+ }
+ return packageName;
+ }
+
private static String[] getPackagesForUid(int uid) {
String[] packageNames = null;
try {
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 9b8f2d2..00a49bd 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -456,6 +456,7 @@
class SettingsObserver extends ContentObserver {
int mUserId;
boolean mRegistered = false;
+ @NonNull
String mLastEnabled = "";
/**
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 329f716..07c10b0 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -49,6 +49,7 @@
import android.app.ActivityManagerNative;
import android.content.Context;
import android.net.ConnectivityManager;
+import android.net.INetd;
import android.net.INetworkManagementEventObserver;
import android.net.InterfaceConfiguration;
import android.net.IpPrefix;
@@ -122,7 +123,7 @@
private static final String TAG = "NetworkManagement";
private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
private static final String NETD_TAG = "NetdConnector";
- private static final String NETD_SOCKET_NAME = "netd";
+ private static final String NETD_SERVICE_NAME = "netd";
private static final int MAX_UID_RANGES_PER_COMMAND = 10;
@@ -188,6 +189,8 @@
private final Handler mFgHandler;
private final Handler mDaemonHandler;
+ private INetd mNetdService;
+
private IBatteryStats mBatteryStats;
private final Thread mThread;
@@ -306,7 +309,7 @@
}
public static NetworkManagementService create(Context context) throws InterruptedException {
- return create(context, NETD_SOCKET_NAME);
+ return create(context, NETD_SERVICE_NAME);
}
public void systemReady() {
@@ -515,6 +518,15 @@
* existing in-memory rules.
*/
private void prepareNativeDaemon() {
+ boolean nativeServiceAvailable = false;
+ try {
+ mNetdService = INetd.Stub.asInterface(ServiceManager.getService(NETD_SERVICE_NAME));
+ nativeServiceAvailable = mNetdService.isAlive();
+ } catch (RemoteException e) {}
+ if (!nativeServiceAvailable) {
+ Slog.wtf(TAG, "Can't connect to NativeNetdService " + NETD_SERVICE_NAME);
+ }
+
mBandwidthControlEnabled = false;
// only enable bandwidth control when support exists
diff --git a/services/core/java/com/android/server/TextServicesManagerService.java b/services/core/java/com/android/server/TextServicesManagerService.java
index 306e933..3eb20a0 100644
--- a/services/core/java/com/android/server/TextServicesManagerService.java
+++ b/services/core/java/com/android/server/TextServicesManagerService.java
@@ -28,6 +28,7 @@
import org.xmlpull.v1.XmlPullParserException;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.annotation.UserIdInt;
import android.app.ActivityManagerNative;
import android.app.AppGlobals;
@@ -464,9 +465,10 @@
return null;
}
synchronized (mSpellCheckerMap) {
- final String subtypeHashCodeStr = mSettings.getSelectedSpellCheckerSubtype();
+ final int subtypeHashCode =
+ mSettings.getSelectedSpellCheckerSubtype(SpellCheckerSubtype.SUBTYPE_ID_NONE);
if (DBG) {
- Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCodeStr);
+ Slog.w(TAG, "getCurrentSpellCheckerSubtype: " + subtypeHashCode);
}
final SpellCheckerInfo sci = getCurrentSpellChecker(null);
if (sci == null || sci.getSubtypeCount() == 0) {
@@ -475,17 +477,12 @@
}
return null;
}
- final int hashCode;
- if (!TextUtils.isEmpty(subtypeHashCodeStr)) {
- hashCode = Integer.valueOf(subtypeHashCodeStr);
- } else {
- hashCode = 0;
- }
- if (hashCode == 0 && !allowImplicitlySelectedSubtype) {
+ if (subtypeHashCode == SpellCheckerSubtype.SUBTYPE_ID_NONE
+ && !allowImplicitlySelectedSubtype) {
return null;
}
String candidateLocale = null;
- if (hashCode == 0) {
+ if (subtypeHashCode == 0) {
// Spell checker language settings == "auto"
final InputMethodManager imm = mContext.getSystemService(InputMethodManager.class);
if (imm != null) {
@@ -507,7 +504,7 @@
SpellCheckerSubtype candidate = null;
for (int i = 0; i < sci.getSubtypeCount(); ++i) {
final SpellCheckerSubtype scs = sci.getSubtypeAt(i);
- if (hashCode == 0) {
+ if (subtypeHashCode == 0) {
final String scsLocale = scs.getLocale();
if (candidateLocale.equals(scsLocale)) {
return scs;
@@ -518,7 +515,7 @@
candidate = scs;
}
}
- } else if (scs.hashCode() == hashCode) {
+ } else if (scs.hashCode() == subtypeHashCode) {
if (DBG) {
Slog.w(TAG, "Return subtype " + scs.hashCode() + ", input= " + locale
+ ", " + scs.getLocale());
@@ -1096,12 +1093,15 @@
}
}
- private String getString(final String key) {
+ @Nullable
+ private String getString(@NonNull final String key, @Nullable final String defaultValue) {
+ final String result;
if (mCopyOnWrite && mCopyOnWriteDataStore.containsKey(key)) {
- final String result = mCopyOnWriteDataStore.get(key);
- return result != null ? result : "";
+ result = mCopyOnWriteDataStore.get(key);
+ } else {
+ result = Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
}
- return Settings.Secure.getStringForUser(mResolver, key, mCurrentUserId);
+ return result != null ? result : defaultValue;
}
private void putInt(final String key, final int value) {
@@ -1149,24 +1149,31 @@
return mCurrentUserId;
}
- public void putSelectedSpellChecker(String sciId) {
- putString(Settings.Secure.SELECTED_SPELL_CHECKER, sciId);
+ public void putSelectedSpellChecker(@Nullable String sciId) {
+ if (TextUtils.isEmpty(sciId)) {
+ // OK to coalesce to null, since getSelectedSpellChecker() can take care of the
+ // empty data scenario.
+ putString(Settings.Secure.SELECTED_SPELL_CHECKER, null);
+ } else {
+ putString(Settings.Secure.SELECTED_SPELL_CHECKER, sciId);
+ }
}
public void putSelectedSpellCheckerSubtype(int hashCode) {
- putString(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, String.valueOf(hashCode));
+ putInt(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, hashCode);
}
public void setSpellCheckerEnabled(boolean enabled) {
putBoolean(Settings.Secure.SPELL_CHECKER_ENABLED, enabled);
}
+ @NonNull
public String getSelectedSpellChecker() {
- return getString(Settings.Secure.SELECTED_SPELL_CHECKER);
+ return getString(Settings.Secure.SELECTED_SPELL_CHECKER, "");
}
- public String getSelectedSpellCheckerSubtype() {
- return getString(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE);
+ public int getSelectedSpellCheckerSubtype(final int defaultValue) {
+ return getInt(Settings.Secure.SELECTED_SPELL_CHECKER_SUBTYPE, defaultValue);
}
public boolean isSpellCheckerEnabled() {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 95dbd0f..6361db5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -6913,6 +6913,14 @@
}
}
+ // We're going to be splicing together extras before sending, so we're
+ // okay poking into any contained extras.
+ if (intents != null) {
+ for (int i = 0; i < intents.length; i++) {
+ intents[i].setDefusable(true);
+ }
+ }
+
final boolean noCreate = (flags&PendingIntent.FLAG_NO_CREATE) != 0;
final boolean cancelCurrent = (flags&PendingIntent.FLAG_CANCEL_CURRENT) != 0;
final boolean updateCurrent = (flags&PendingIntent.FLAG_UPDATE_CURRENT) != 0;
diff --git a/services/core/java/com/android/server/am/ProcessStartLogger.java b/services/core/java/com/android/server/am/ProcessStartLogger.java
index d2aa966..39fbeb5 100644
--- a/services/core/java/com/android/server/am/ProcessStartLogger.java
+++ b/services/core/java/com/android/server/am/ProcessStartLogger.java
@@ -4,7 +4,7 @@
import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
import android.app.AppGlobals;
-import android.auditing.SecurityLog;
+import android.app.admin.SecurityLog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index e7580f4..5320221 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -205,7 +205,6 @@
private static final int MSG_SET_FORCE_USE = 8;
private static final int MSG_BT_HEADSET_CNCT_FAILED = 9;
private static final int MSG_SET_ALL_VOLUMES = 10;
- private static final int MSG_PERSIST_MASTER_VOLUME_MUTE = 11;
private static final int MSG_REPORT_NEW_ROUTES = 12;
private static final int MSG_SET_FORCE_BT_A2DP_USE = 13;
private static final int MSG_CHECK_MUSIC_ACTIVE = 14;
@@ -217,7 +216,6 @@
private static final int MSG_UNLOAD_SOUND_EFFECTS = 20;
private static final int MSG_SYSTEM_READY = 21;
private static final int MSG_PERSIST_MUSIC_ACTIVE_MS = 22;
- private static final int MSG_PERSIST_MICROPHONE_MUTE = 23;
private static final int MSG_UNMUTE_STREAM = 24;
private static final int MSG_DYN_POLICY_MIX_STATE_UPDATE = 25;
private static final int MSG_INDICATE_SYSTEM_READY = 26;
@@ -665,6 +663,7 @@
// array initialized by updateStreamVolumeAlias()
updateStreamVolumeAlias(false /*updateVolumes*/, TAG);
readPersistedSettings();
+ readUserRestrictions();
mSettingsObserver = new SettingsObserver();
createStreamStates();
@@ -1111,35 +1110,6 @@
System.MUTE_STREAMS_AFFECTED, AudioSystem.DEFAULT_MUTE_STREAMS_AFFECTED,
UserHandle.USER_CURRENT);
- final int currentUser = getCurrentUserId();
-
- // In addition to checking the system setting, also check the current user restriction.
- // Because of the delay before persisting VOLUME_MASTER_MUTE, there's a window where
- // DISALLOW_ADJUST_VOLUME will be ignored when it's set right before switching users.
- boolean masterMute = (System.getIntForUser(cr, System.VOLUME_MASTER_MUTE,
- 0, UserHandle.USER_CURRENT) == 1)
- || mUserManagerInternal.getUserRestriction(
- currentUser, UserManager.DISALLOW_ADJUST_VOLUME);
- if (mUseFixedVolume) {
- masterMute = false;
- AudioSystem.setMasterVolume(1.0f);
- }
- if (DEBUG_VOL) {
- Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
- }
- setSystemAudioMute(masterMute);
- AudioSystem.setMasterMute(masterMute);
- broadcastMasterMuteStatus(masterMute);
-
- boolean microphoneMute =
- (System.getIntForUser(cr, System.MICROPHONE_MUTE, 0, UserHandle.USER_CURRENT) == 1)
- || mUserManagerInternal.getUserRestriction(
- currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
- if (DEBUG_VOL) {
- Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
- }
- AudioSystem.muteMicrophone(microphoneMute);
-
updateMasterMono(cr);
// Each stream will read its own persisted settings
@@ -1156,6 +1126,31 @@
mVolumeController.loadSettings(cr);
}
+ private void readUserRestrictions() {
+ final int currentUser = getCurrentUserId();
+
+ // Check the current user restriction.
+ boolean masterMute = mUserManagerInternal.getUserRestriction(
+ currentUser, UserManager.DISALLOW_ADJUST_VOLUME);
+ if (mUseFixedVolume) {
+ masterMute = false;
+ AudioSystem.setMasterVolume(1.0f);
+ }
+ if (DEBUG_VOL) {
+ Log.d(TAG, String.format("Master mute %s, user=%d", masterMute, currentUser));
+ }
+ setSystemAudioMute(masterMute);
+ AudioSystem.setMasterMute(masterMute);
+ broadcastMasterMuteStatus(masterMute);
+
+ boolean microphoneMute = mUserManagerInternal.getUserRestriction(
+ currentUser, UserManager.DISALLOW_UNMUTE_MICROPHONE);
+ if (DEBUG_VOL) {
+ Log.d(TAG, String.format("Mic mute %s, user=%d", microphoneMute, currentUser));
+ }
+ AudioSystem.muteMicrophone(microphoneMute);
+ }
+
private int rescaleIndex(int index, int srcStream, int dstStream) {
return (index * mStreamStates[dstStream].getMaxIndex() + mStreamStates[srcStream].getMaxIndex() / 2) / mStreamStates[srcStream].getMaxIndex();
}
@@ -1911,20 +1906,12 @@
if (mute != AudioSystem.getMasterMute()) {
setSystemAudioMute(mute);
AudioSystem.setMasterMute(mute);
- // Post a persist master volume msg
- sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
- : 0, userId, null, PERSIST_DELAY);
sendMasterMuteUpdate(mute, flags);
Intent intent = new Intent(AudioManager.MASTER_MUTE_CHANGED_ACTION);
intent.putExtra(AudioManager.EXTRA_MASTER_VOLUME_MUTED, mute);
sendBroadcastToAll(intent);
}
- } else {
- // If not the current user just persist the setting which will be loaded
- // on user switch.
- sendMsg(mAudioHandler, MSG_PERSIST_MASTER_VOLUME_MUTE, SENDMSG_REPLACE, mute ? 1
- : 0, userId, null, PERSIST_DELAY);
}
}
@@ -2017,8 +2004,6 @@
AudioSystem.muteMicrophone(on);
}
// Post a persist microphone msg.
- sendMsg(mAudioHandler, MSG_PERSIST_MICROPHONE_MUTE, SENDMSG_REPLACE, on ? 1
- : 0, userId, null, PERSIST_DELAY);
}
@Override
@@ -2607,6 +2592,7 @@
private void readAudioSettings(boolean userSwitch) {
// restore ringer mode, ringer mode affected streams, mute affected streams and vibrate settings
readPersistedSettings();
+ readUserRestrictions();
// restore volume settings
int numStreamTypes = AudioSystem.getNumStreamTypes();
@@ -4545,16 +4531,6 @@
persistVolume((VolumeStreamState) msg.obj, msg.arg1);
break;
- case MSG_PERSIST_MASTER_VOLUME_MUTE:
- if (mUseFixedVolume) {
- return;
- }
- Settings.System.putIntForUser(mContentResolver,
- Settings.System.VOLUME_MASTER_MUTE,
- msg.arg1,
- msg.arg2);
- break;
-
case MSG_PERSIST_RINGER_MODE:
// note that the value persisted is the current ringer mode, not the
// value of ringer mode as of the time the request was made to persist
@@ -4677,15 +4653,11 @@
Settings.Secure.UNSAFE_VOLUME_MUSIC_ACTIVE_MS, musicActiveMs,
UserHandle.USER_CURRENT);
break;
- case MSG_PERSIST_MICROPHONE_MUTE:
- Settings.System.putIntForUser(mContentResolver,
- Settings.System.MICROPHONE_MUTE,
- msg.arg1,
- msg.arg2);
- break;
+
case MSG_UNMUTE_STREAM:
onUnmuteStream(msg.arg1, msg.arg2);
break;
+
case MSG_DYN_POLICY_MIX_STATE_UPDATE:
onDynPolicyMixStateUpdate((String) msg.obj, msg.arg1);
break;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 3baf894..e8a6528 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -160,6 +160,7 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
@@ -276,9 +277,6 @@
// Persistent storage for notification policy
private AtomicFile mPolicyFile;
- // Temporary holder for <blocked-packages> config coming from old policy files.
- private HashSet<String> mBlockedPackages = new HashSet<String>();
-
private static final int DB_VERSION = 1;
private static final String TAG_NOTIFICATION_POLICY = "notification-policy";
@@ -354,27 +352,7 @@
final XmlPullParser parser = Xml.newPullParser();
parser.setInput(stream, StandardCharsets.UTF_8.name());
- int type;
- String tag;
- int version = DB_VERSION;
- while ((type = parser.next()) != END_DOCUMENT) {
- tag = parser.getName();
- if (type == START_TAG) {
- if (TAG_NOTIFICATION_POLICY.equals(tag)) {
- version = Integer.parseInt(
- parser.getAttributeValue(null, ATTR_VERSION));
- } else if (TAG_BLOCKED_PKGS.equals(tag)) {
- while ((type = parser.next()) != END_DOCUMENT) {
- tag = parser.getName();
- if (TAG_PACKAGE.equals(tag)) {
- mBlockedPackages.add(
- parser.getAttributeValue(null, ATTR_NAME));
- } else if (TAG_BLOCKED_PKGS.equals(tag) && type == END_TAG) {
- break;
- }
- }
- }
- }
+ while (parser.next() != END_DOCUMENT) {
mZenModeHelper.readXml(parser, forRestore);
mRankingHelper.readXml(parser, forRestore);
}
@@ -383,7 +361,6 @@
private void loadPolicyFile() {
if (DBG) Slog.d(TAG, "loadPolicyFile");
synchronized(mPolicyFile) {
- mBlockedPackages.clear();
FileInputStream infile = null;
try {
@@ -941,7 +918,7 @@
final File systemDir = new File(Environment.getDataDirectory(), "system");
mPolicyFile = new AtomicFile(new File(systemDir, "notification_policy.xml"));
- importOldBlockDb();
+ syncBlockDb();
// This is a MangedServices object that keeps track of the listeners.
mListeners = new NotificationListeners();
@@ -1041,22 +1018,43 @@
}
/**
- * Read the old XML-based app block database and import those blockages into the AppOps system.
+ * Make sure the XML config and the the AppOps system agree about blocks.
*/
- private void importOldBlockDb() {
+ private void syncBlockDb() {
loadPolicyFile();
- PackageManager pm = getContext().getPackageManager();
- for (String pkg : mBlockedPackages) {
- PackageInfo info = null;
- try {
- info = pm.getPackageInfo(pkg, 0);
- setNotificationsEnabledForPackageImpl(pkg, info.applicationInfo.uid, false);
- } catch (NameNotFoundException e) {
- // forget you
+ // sync bans from ranker into app opps
+ Map<Integer, String> packageBans = mRankingHelper.getPackageBans();
+ for(Entry<Integer, String> ban : packageBans.entrySet()) {
+ final int uid = ban.getKey();
+ final String packageName = ban.getValue();
+ setNotificationsEnabledForPackageImpl(packageName, uid, false);
+ }
+
+ // sync bans from app opps into ranker
+ packageBans.clear();
+ for (UserInfo user : UserManager.get(getContext()).getUsers()) {
+ final int userId = user.getUserHandle().getIdentifier();
+ final PackageManager packageManager = getContext().getPackageManager();
+ List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
+ final int packageCount = packages.size();
+ for (int p = 0; p < packageCount; p++) {
+ final String packageName = packages.get(p).packageName;
+ try {
+ final int uid = packageManager.getPackageUidAsUser(packageName, userId);
+ if (!checkNotificationOp(packageName, uid)) {
+ packageBans.put(uid, packageName);
+ }
+ } catch (NameNotFoundException e) {
+ // forget you
+ }
}
}
- mBlockedPackages.clear();
+ for (Entry<Integer, String> ban : packageBans.entrySet()) {
+ mRankingHelper.setImportance(ban.getValue(), ban.getKey(), IMPORTANCE_NONE);
+ }
+
+ savePolicyFile();
}
@Override
@@ -1261,6 +1259,8 @@
checkCallerIsSystem();
setNotificationsEnabledForPackageImpl(pkg, uid, enabled);
+ mRankingHelper.setEnabled(pkg, uid, enabled);
+ savePolicyFile();
}
/**
@@ -2034,21 +2034,8 @@
JSONObject dump = new JSONObject();
try {
dump.put("service", "Notification Manager");
- JSONArray bans = new JSONArray();
- try {
- ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
- for (Integer userId : packageBans.keySet()) {
- for (String packageName : packageBans.get(userId)) {
- JSONObject ban = new JSONObject();
- ban.put("userId", userId);
- ban.put("packageName", packageName);
- bans.put(ban);
- }
- }
- } catch (NameNotFoundException e) {
- // pass
- }
- dump.put("bans", bans);
+ dump.put("bans", mRankingHelper.dumpBansJson(filter));
+ dump.put("ranking", mRankingHelper.dumpJson(filter));
dump.put("stats", mUsageStats.dumpJson(filter));
} catch (JSONException e) {
e.printStackTrace();
@@ -2175,47 +2162,9 @@
r.dump(pw, " ", getContext(), filter.redact);
}
}
-
- try {
- pw.println("\n Banned Packages:");
- ArrayMap<Integer, ArrayList<String>> packageBans = getPackageBans(filter);
- for (Integer userId : packageBans.keySet()) {
- for (String packageName : packageBans.get(userId)) {
- pw.println(" " + userId + ": " + packageName);
- }
- }
- } catch (NameNotFoundException e) {
- // pass
- }
}
}
- private ArrayMap<Integer, ArrayList<String>> getPackageBans(DumpFilter filter)
- throws NameNotFoundException {
- ArrayMap<Integer, ArrayList<String>> packageBans = new ArrayMap<>();
- ArrayList<String> packageNames = new ArrayList<>();
- for (UserInfo user : UserManager.get(getContext()).getUsers()) {
- final int userId = user.getUserHandle().getIdentifier();
- final PackageManager packageManager = getContext().getPackageManager();
- List<PackageInfo> packages = packageManager.getInstalledPackagesAsUser(0, userId);
- final int packageCount = packages.size();
- for (int p = 0; p < packageCount; p++) {
- final String packageName = packages.get(p).packageName;
- if (filter == null || filter.matches(packageName)) {
- final int uid = packageManager.getPackageUidAsUser(packageName, userId);
- if (!checkNotificationOp(packageName, uid)) {
- packageNames.add(packageName);
- }
- }
- }
- if (!packageNames.isEmpty()) {
- packageBans.put(userId, packageNames);
- packageNames = new ArrayList<>();
- }
- }
- return packageBans;
- }
-
/**
* The private API only accessible to the system process.
*/
@@ -2298,6 +2247,11 @@
// Sanitize inputs
notification.priority = clamp(notification.priority, Notification.PRIORITY_MIN,
Notification.PRIORITY_MAX);
+ if (notification.extras != null) {
+ // If the remote side sent us bad parcelables, they won't get the
+ // results they want, which is their loss.
+ notification.extras.setDefusable(true);
+ }
// setup local book-keeping
final StatusBarNotification n = new StatusBarNotification(
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index fd96a78..4a41705 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -25,6 +25,11 @@
import android.util.ArrayMap;
import android.util.Slog;
+import com.android.server.notification.NotificationManagerService.DumpFilter;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlSerializer;
@@ -33,6 +38,8 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Map;
+import java.util.Map.Entry;
public class RankingHelper implements RankingConfig {
private static final String TAG = "RankingHelper";
@@ -358,6 +365,14 @@
updateConfig();
}
+ public void setEnabled(String packageName, int uid, boolean enabled) {
+ boolean wasEnabled = getImportance(packageName, uid) != Ranking.IMPORTANCE_NONE;
+ if (wasEnabled == enabled) {
+ return;
+ }
+ setImportance(packageName, uid, enabled ? DEFAULT_IMPORTANCE : Ranking.IMPORTANCE_NONE);
+ }
+
public void dump(PrintWriter pw, String prefix, NotificationManagerService.DumpFilter filter) {
if (filter == null) {
final int N = mSignalExtractors.length;
@@ -398,17 +413,97 @@
}
if (r.priority != DEFAULT_PRIORITY) {
pw.print(" priority=");
- pw.print(Ranking.importanceToString(r.priority));
+ pw.print(Notification.priorityToString(r.priority));
}
if (r.visibility != DEFAULT_VISIBILITY) {
pw.print(" visibility=");
- pw.print(Ranking.importanceToString(r.visibility));
+ pw.print(Notification.visibilityToString(r.visibility));
}
pw.println();
}
}
}
+ public JSONObject dumpJson(NotificationManagerService.DumpFilter filter) {
+ JSONObject ranking = new JSONObject();
+ JSONArray records = new JSONArray();
+ try {
+ ranking.put("noUid", mRestoredWithoutUids.size());
+ } catch (JSONException e) {
+ // pass
+ }
+ final int N = mRecords.size();
+ for (int i = 0; i < N; i++) {
+ final Record r = mRecords.valueAt(i);
+ if (filter == null || filter.matches(r.pkg)) {
+ JSONObject record = new JSONObject();
+ try {
+ record.put("userId", UserHandle.getUserId(r.uid));
+ record.put("packageName", r.pkg);
+ if (r.importance != DEFAULT_IMPORTANCE) {
+ record.put("importance", Ranking.importanceToString(r.importance));
+ }
+ if (r.priority != DEFAULT_PRIORITY) {
+ record.put("priority", Notification.priorityToString(r.priority));
+ }
+ if (r.visibility != DEFAULT_VISIBILITY) {
+ record.put("visibility", Notification.visibilityToString(r.visibility));
+ }
+ } catch (JSONException e) {
+ // pass
+ }
+ records.put(record);
+ }
+ }
+ try {
+ ranking.put("records", records);
+ } catch (JSONException e) {
+ // pass
+ }
+ return ranking;
+ }
+
+ /**
+ * Dump only the ban information as structured JSON for the stats collector.
+ *
+ * This is intentionally redundant with {#link dumpJson} because the old
+ * scraper will expect this format.
+ *
+ * @param filter
+ * @return
+ */
+ public JSONArray dumpBansJson(NotificationManagerService.DumpFilter filter) {
+ JSONArray bans = new JSONArray();
+ Map<Integer, String> packageBans = getPackageBans();
+ for(Entry<Integer, String> ban : packageBans.entrySet()) {
+ final int userId = UserHandle.getUserId(ban.getKey());
+ final String packageName = ban.getValue();
+ if (filter == null || filter.matches(packageName)) {
+ JSONObject banJson = new JSONObject();
+ try {
+ banJson.put("userId", userId);
+ banJson.put("packageName", packageName);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ bans.put(banJson);
+ }
+ }
+ return bans;
+ }
+
+ public Map<Integer, String> getPackageBans() {
+ final int N = mRecords.size();
+ ArrayMap<Integer, String> packageBans = new ArrayMap<>(N);
+ for (int i = 0; i < N; i++) {
+ final Record r = mRecords.valueAt(i);
+ if (r.importance == Ranking.IMPORTANCE_NONE) {
+ packageBans.put(r.uid, r.pkg);
+ }
+ }
+ return packageBans;
+ }
+
public void onPackagesChanged(boolean queryReplace, String[] pkgList) {
if (queryReplace || pkgList == null || pkgList.length == 0
|| mRestoredWithoutUids.isEmpty()) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b624087..c7578f0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16459,10 +16459,22 @@
return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
}
- ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
- int userId) {
+ private Intent getHomeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
+ return intent;
+ }
+
+ private IntentFilter getHomeFilter() {
+ IntentFilter filter = new IntentFilter(Intent.ACTION_MAIN);
+ filter.addCategory(Intent.CATEGORY_HOME);
+ filter.addCategory(Intent.CATEGORY_DEFAULT);
+ return filter;
+ }
+
+ ComponentName getHomeActivitiesAsUser(List<ResolveInfo> allHomeCandidates,
+ int userId) {
+ Intent intent = getHomeIntent();
List<ResolveInfo> list = queryIntentActivitiesInternal(intent, null,
PackageManager.GET_META_DATA, userId);
ResolveInfo preferred = findPreferredActivity(intent, null, 0, list, 0,
@@ -16481,6 +16493,32 @@
}
@Override
+ public void setHomeActivity(ComponentName comp, int userId) {
+ ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
+ getHomeActivitiesAsUser(homeActivities, userId);
+
+ boolean found = false;
+
+ final int size = homeActivities.size();
+ final ComponentName[] set = new ComponentName[size];
+ for (int i = 0; i < size; i++) {
+ final ResolveInfo candidate = homeActivities.get(i);
+ final ActivityInfo info = candidate.activityInfo;
+ final ComponentName activityName = new ComponentName(info.packageName, info.name);
+ set[i] = activityName;
+ if (!found && activityName.equals(comp)) {
+ found = true;
+ }
+ }
+ if (!found) {
+ throw new IllegalArgumentException("Component " + comp + " cannot be home on user "
+ + userId);
+ }
+ replacePreferredActivity(getHomeFilter(), IntentFilter.MATCH_CATEGORY_EMPTY,
+ set, comp, userId);
+ }
+
+ @Override
public void setApplicationEnabledSetting(String appPackageName,
int newState, int flags, int userId, String callingPackage) {
if (!sUserManager.exists(userId)) return;
@@ -16624,6 +16662,22 @@
}
}
+ @Override
+ public void flushPackageRestrictionsAsUser(int userId) {
+ if (!sUserManager.exists(userId)) {
+ return;
+ }
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, false /* requireFullPermission*/,
+ false /* checkShell */, "flushPackageRestrictions");
+ synchronized (mPackages) {
+ mSettings.writePackageRestrictionsLPr(userId);
+ mDirtyUsers.remove(userId);
+ if (mDirtyUsers.isEmpty()) {
+ mHandler.removeMessages(WRITE_PACKAGE_RESTRICTIONS);
+ }
+ }
+ }
+
private void sendPackageChangedBroadcast(String packageName,
boolean killFlag, ArrayList<String> componentNames, int packageUid) {
if (DEBUG_INSTALL)
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index d77168c..319fc37 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -117,6 +117,8 @@
return runSuspend(true);
case "unsuspend":
return runSuspend(false);
+ case "set-home-activity":
+ return runSetHomeActivity();
default:
return handleDefaultCommands(cmd);
}
@@ -963,6 +965,39 @@
return params;
}
+ private int runSetHomeActivity() {
+ final PrintWriter pw = getOutPrintWriter();
+ int userId = UserHandle.USER_SYSTEM;
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "--user":
+ userId = UserHandle.parseUserArg(getNextArgRequired());
+ break;
+ default:
+ pw.println("Error: Unknown option: " + opt);
+ return 1;
+ }
+ }
+
+ String component = getNextArg();
+ ComponentName componentName =
+ component != null ? ComponentName.unflattenFromString(component) : null;
+
+ if (componentName == null) {
+ pw.println("Error: component name not specified or invalid");
+ return 1;
+ }
+
+ try {
+ mInterface.setHomeActivity(componentName, userId);
+ return 0;
+ } catch (RemoteException e) {
+ pw.println(e.toString());
+ return 1;
+ }
+ }
+
private static String checkAbiArgument(String abi) {
if (TextUtils.isEmpty(abi)) {
throw new IllegalArgumentException("Missing ABI argument");
@@ -1303,6 +1338,8 @@
pw.println(" Suspends the specified package (as user).");
pw.println(" unsuspend [--user USER_ID] TARGET-PACKAGE");
pw.println(" Unsuspends the specified package (as user).");
+ pw.println(" set-home-activity [--user USER_ID] TARGET-COMPONENT");
+ pw.println(" set the default home activity (aka launcher).");
pw.println();
Intent.printIntentArgsHelp(pw , "");
}
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index cd771ba..1695615 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -645,15 +645,23 @@
final boolean fullscreenTask = !inMultiWindowMode();
final boolean windowsAreFloating = task != null && task.isFloating();
- if (fullscreenTask || (isChildWindow()
- && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0)) {
+ // If the task has temp inset bounds set, we have to make sure all its windows uses
+ // the temp inset frame. Otherwise different display frames get applied to the main
+ // window and the child window, making them misaligned.
+ if (fullscreenTask) {
+ mInsetFrame.setEmpty();
+ } else {
+ task.getTempInsetBounds(mInsetFrame);
+ }
+
+ if (mInsetFrame.isEmpty() && (fullscreenTask
+ || (isChildWindow() && (mAttrs.privateFlags
+ & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0))) {
// We use the parent frame as the containing frame for fullscreen and child windows
mContainingFrame.set(pf);
mDisplayFrame.set(df);
- mInsetFrame.setEmpty();
} else {
task.getBounds(mContainingFrame);
- task.getTempInsetBounds(mInsetFrame);
if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) {
// If the bounds are frozen, we still want to translate the window freely and only
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 252bc1e..41eafe7 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -711,8 +711,6 @@
// Start a new transaction and apply position & offset.
final int layerStack = w.getDisplayContent().getDisplay().getLayerStack();
- if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
- "POS " + mTmpSize.left + ", " + mTmpSize.top, false);
mSurfaceController.setPositionAndLayer(mTmpSize.left, mTmpSize.top, layerStack, mAnimLayer);
mLastHidden = true;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index fb07512..11f3771 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -119,6 +119,8 @@
mSurfaceY = top;
try {
+ if (SHOW_TRANSACTIONS) logSurface(
+ "POS (setPositionAndLayer) @ (" + left + "," + top + ")", null);
mSurfaceControl.setPosition(left, top);
mSurfaceControl.setLayerStack(layerStack);
@@ -205,6 +207,9 @@
mSurfaceY = top;
try {
+ if (SHOW_TRANSACTIONS) logSurface(
+ "POS (setPositionInTransaction) @ (" + left + "," + top + ")", null);
+
mSurfaceControl.setPosition(left, top);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + this
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 16e73fc..6ddc6c8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -26,8 +26,6 @@
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.TEXT;
-import com.google.android.collect.Sets;
-
import android.Manifest.permission;
import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.AccountManager;
@@ -50,10 +48,10 @@
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
+import android.app.admin.SecurityLog;
+import android.app.admin.SecurityLog.SecurityEvent;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
-import android.auditing.SecurityLog;
-import android.auditing.SecurityLog.SecurityEvent;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -142,6 +140,7 @@
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerService.ActiveAdmin.TrustAgentInfo;
import com.android.server.pm.UserRestrictionsUtils;
+import com.google.android.collect.Sets;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -484,9 +483,9 @@
new MonitoringCertNotificationTask().execute(intent);
}
if (Intent.ACTION_USER_ADDED.equals(action)) {
- disableDeviceLoggingIfNotCompliant();
+ disableSecurityLoggingIfNotCompliant();
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
- disableDeviceLoggingIfNotCompliant();
+ disableSecurityLoggingIfNotCompliant();
removeUserData(userHandle);
} else if (Intent.ACTION_USER_STARTED.equals(action)) {
synchronized (DevicePolicyManagerService.this) {
@@ -1672,7 +1671,7 @@
if (mOwners.hasDeviceOwner()) {
mInjector.systemPropertiesSet(PROPERTY_DEVICE_OWNER_PRESENT, "true");
Slog.i(LOG_TAG, "Set ro.device_owner property to true");
- disableDeviceLoggingIfNotCompliant();
+ disableSecurityLoggingIfNotCompliant();
if (mInjector.securityLogGetLoggingEnabledProperty()) {
mSecurityLogMonitor.start();
}
@@ -5612,7 +5611,7 @@
mOwners.clearDeviceOwner();
mOwners.writeDeviceOwner();
updateDeviceOwnerLocked();
- disableDeviceLoggingIfNotCompliant();
+ disableSecurityLoggingIfNotCompliant();
// Reactivate backup service.
long ident = mInjector.binderClearCallingIdentity();
try {
@@ -8598,15 +8597,15 @@
return false;
}
- private synchronized void disableDeviceLoggingIfNotCompliant() {
+ private synchronized void disableSecurityLoggingIfNotCompliant() {
if (!isDeviceOwnerManagedSingleUserDevice()) {
mInjector.securityLogSetLoggingEnabledProperty(false);
- Slog.w(LOG_TAG, "Device logging turned off as it's no longer a single user device.");
+ Slog.w(LOG_TAG, "Security logging turned off as it's no longer a single user device.");
}
}
@Override
- public void setDeviceLoggingEnabled(ComponentName admin, boolean enabled) {
+ public void setSecurityLoggingEnabled(ComponentName admin, boolean enabled) {
Preconditions.checkNotNull(admin);
ensureDeviceOwnerManagingSingleUser(admin);
@@ -8624,7 +8623,7 @@
}
@Override
- public boolean getDeviceLoggingEnabled(ComponentName admin) {
+ public boolean isSecurityLoggingEnabled(ComponentName admin) {
Preconditions.checkNotNull(admin);
synchronized (this) {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
@@ -8633,7 +8632,7 @@
}
@Override
- public ParceledListSlice<SecurityEvent> retrievePreviousDeviceLogs(ComponentName admin) {
+ public ParceledListSlice<SecurityEvent> retrievePreRebootSecurityLogs(ComponentName admin) {
Preconditions.checkNotNull(admin);
ensureDeviceOwnerManagingSingleUser(admin);
@@ -8648,7 +8647,7 @@
}
@Override
- public ParceledListSlice<SecurityEvent> retrieveDeviceLogs(ComponentName admin) {
+ public ParceledListSlice<SecurityEvent> retrieveSecurityLogs(ComponentName admin) {
Preconditions.checkNotNull(admin);
ensureDeviceOwnerManagingSingleUser(admin);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
index cacc671..79702a8 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/SecurityLogMonitor.java
@@ -17,8 +17,8 @@
package com.android.server.devicepolicy;
import android.app.admin.DeviceAdminReceiver;
-import android.auditing.SecurityLog;
-import android.auditing.SecurityLog.SecurityEvent;
+import android.app.admin.SecurityLog;
+import android.app.admin.SecurityLog.SecurityEvent;
import android.util.Log;
import android.util.Slog;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 19c073c..5975405 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -28,6 +28,7 @@
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources.Theme;
+import android.os.BaseBundle;
import android.os.Build;
import android.os.Environment;
import android.os.FactoryTest;
@@ -35,7 +36,6 @@
import android.os.IPowerManager;
import android.os.Looper;
import android.os.PowerManager;
-import android.os.RecoverySystem;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
@@ -53,6 +53,7 @@
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.os.ZygoteInit;
+import com.android.internal.widget.ILockSettings;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accounts.AccountManagerService;
import com.android.server.am.ActivityManagerService;
@@ -69,10 +70,9 @@
import com.android.server.input.InputManagerService;
import com.android.server.job.JobSchedulerService;
import com.android.server.lights.LightsService;
-import com.android.internal.widget.ILockSettings;
+import com.android.server.media.MediaResourceMonitorService;
import com.android.server.media.MediaRouterService;
import com.android.server.media.MediaSessionService;
-import com.android.server.media.MediaResourceMonitorService;
import com.android.server.media.projection.MediaProjectionManagerService;
import com.android.server.net.NetworkPolicyManagerService;
import com.android.server.net.NetworkStatsService;
@@ -271,6 +271,10 @@
// explicitly specifying a user.
Environment.setUserRequired(true);
+ // Within the system server, any incoming Bundles should be defused
+ // to avoid throwing BadParcelableException.
+ BaseBundle.setShouldDefuse(true);
+
// Ensure binder calls into the system always run at foreground priority.
BinderInternal.disableBackgroundScheduling(true);
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 69f12eb..34f2e2e 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -161,9 +161,11 @@
assertNull("BUG: only one idle handler allowed", mIdleHandler);
mIdleHandler = new IdleHandler() {
public boolean queueIdle() {
- cv.open();
- mIdleHandler = null;
- return false; // Remove the handler.
+ synchronized (queue) {
+ cv.open();
+ mIdleHandler = null;
+ return false; // Remove the handler.
+ }
}
};
queue.addIdleHandler(mIdleHandler);
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ea437d0..86518b5 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -444,6 +444,11 @@
public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
/**
+ * 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";
+
+ /**
* Flag specifying whether an additional (client initiated) intent needs to be sent on System
* update
*/
@@ -680,6 +685,7 @@
sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN,false);
sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOLEAN,true);
sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
+ 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, "");
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_EXTRA_STRING, "");
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index e851c8d..91e891f 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -758,6 +758,12 @@
throw new UnsupportedOperationException();
}
+ /** @hide */
+ @Override
+ public void flushPackageRestrictionsAsUser(int userId) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public void addPreferredActivity(IntentFilter filter,
int match, ComponentName[] set, ComponentName activity) {
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml
new file mode 100644
index 0000000..d5d86d8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_evenodd.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 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.
+ */
+-->
+<vector android:height="24dp" android:viewportHeight="400.0"
+ android:viewportWidth="1200.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillType="evenOdd"
+ android:fillColor="#f00"
+ android:pathData="M250,75L323,301 131,161 369,161 177,301z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+ <path android:fillType="evenOdd"
+ android:fillColor="#f00"
+ android:pathData="M600,81A107,107 0,0 1,600 295A107,107 0,0 1,600 81zM600,139A49,49 0,0 1,600 237A49,49 0,0 1,600 139z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+ <path android:fillType="evenOdd"
+ android:fillColor="#f00"
+ android:pathData="M950,81A107,107 0,0 1,950 295A107,107 0,0 1,950 81zM950,139A49,49 0,0 0,950 237A49,49 0,0 0,950 139z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml
new file mode 100644
index 0000000..9754e4b
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_filltype_nonzero.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 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.
+ */
+-->
+<vector android:height="24dp" android:viewportHeight="400.0"
+ android:viewportWidth="1200.0" android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
+ <path android:fillType="nonZero"
+ android:fillColor="#f00"
+ android:pathData="M250,75L323,301 131,161 369,161 177,301z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+ <path android:fillType="nonZero"
+ android:fillColor="#f00"
+ android:pathData="M600,81A107,107 0,0 1,600 295A107,107 0,0 1,600 81zM600,139A49,49 0,0 1,600 237A49,49 0,0 1,600 139z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+ <path android:fillType="nonZero"
+ android:fillColor="#f00"
+ android:pathData="M950,81A107,107 0,0 1,950 295A107,107 0,0 1,950 81zM950,139A49,49 0,0 0,950 237A49,49 0,0 0,950 139z"
+ android:strokeColor="#000" android:strokeWidth="3"/>
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index 495d620..5856f49 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -35,6 +35,8 @@
public class VectorDrawablePerformance extends Activity {
private static final String LOGCAT = "VectorDrawable1";
protected int[] icon = {
+ R.drawable.vector_icon_filltype_nonzero,
+ R.drawable.vector_icon_filltype_evenodd,
R.drawable.vector_icon_gradient_1,
R.drawable.vector_icon_gradient_2,
R.drawable.vector_icon_gradient_3,
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index fb2213c..fb172d4 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -67,6 +67,20 @@
sys.exit('None of characters in %s were found in %s' % (chars, font))
+def assert_font_supports_all_of_chars(font, chars):
+ best_cmap = get_best_cmap(font)
+ for char in chars:
+ assert char in best_cmap, (
+ 'U+%04X was not found in %s' % (char, font))
+
+
+def assert_font_supports_none_of_chars(font, chars):
+ best_cmap = get_best_cmap(font)
+ for char in chars:
+ assert char not in best_cmap, (
+ 'U+%04X was found in %s' % (char, font))
+
+
def check_hyphens(hyphens_dir):
# Find all the scripts that need automatic hyphenation
scripts = set()
@@ -141,6 +155,70 @@
_script_to_font_map[script].add((font_file, index))
+def check_emoji_availability():
+ emoji_fonts = [font[5] for font in _fallback_chain if 'Zsye' in font[1]]
+ emoji_chars = _emoji_properties['Emoji']
+ for emoji_font in emoji_fonts:
+ assert_font_supports_all_of_chars(emoji_font, emoji_chars)
+
+
+def check_emoji_defaults():
+ default_emoji_chars = _emoji_properties['Emoji_Presentation']
+ emoji_font_seen = False
+ for name, scripts, variant, weight, style, font in _fallback_chain:
+ if 'Zsye' in scripts:
+ emoji_font_seen = True
+ # No need to check the emoji font
+ continue
+ # For later fonts, we only check them if they have a script
+ # defined, since the defined script may get them to a higher
+ # score even if they appear after the emoji font.
+ if emoji_font_seen and not scripts:
+ continue
+
+ if font[1] is None:
+ emoji_to_skip = set()
+ else:
+ # CJK font, skip checking the following characters for now.
+ # See b/26153752
+ emoji_to_skip = ({
+ 0x26BD, # SOCCER BALL
+ 0x26BE, # BASEBALL
+ 0x1F18E, # NEGATIVE SQUARED AB
+ 0x1F201, # SQUARED KATAKANA KOKO
+ 0x1F21A, # SQUARED CJK UNIFIED IDEOGRAPH-7121
+ 0x1F22F, # SQUARED CJK UNIFIED IDEOGRAPH-6307
+ } | set(xrange(0x1F191, 0x1F19A+1))
+ | set(xrange(0x1F232, 0x1F236+1))
+ | set(xrange(0x1F238, 0x1F23A+1))
+ | set(xrange(0x1F250, 0x1F251+1)))
+
+ assert_font_supports_none_of_chars(font,
+ sorted(default_emoji_chars - emoji_to_skip))
+
+
+def parse_ucd(ucd_path):
+ global _emoji_properties
+ _emoji_properties = collections.defaultdict(set)
+ with open(path.join(ucd_path, 'emoji-data.txt')) as emoji_data_txt:
+ for line in emoji_data_txt:
+ if '#' in line:
+ line = line[:line.index('#')]
+ line = line.strip()
+ if not line:
+ continue
+ char_range, prop = line.split(';')
+ char_range = char_range.strip()
+ prop = prop.strip()
+ if '..' in char_range:
+ char_start, char_end = char_range.split('..')
+ else:
+ char_start = char_end = char_range
+ char_start = int(char_start, 16)
+ char_end = int(char_end, 16)
+ _emoji_properties[prop].update(xrange(char_start, char_end+1))
+
+
def main():
target_out = sys.argv[1]
global _fonts_dir
@@ -152,6 +230,11 @@
hyphens_dir = path.join(target_out, 'usr', 'hyphen-data')
check_hyphens(hyphens_dir)
+ ucd_path = sys.argv[2]
+ parse_ucd(ucd_path)
+ check_emoji_availability()
+ check_emoji_defaults()
+
if __name__ == '__main__':
main()
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 4039cdf..42c0ae0 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -715,6 +715,10 @@
}
@Override
+ public void flushPackageRestrictionsAsUser(int userId) {
+ }
+
+ @Override
public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
UserHandle userHandle) {
return false;