Merge "Revert "Revert "Add some View methods overrides and WebViewDelegate interfaces.""" 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 aa943f6..672eb4d9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3537,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();
@@ -4219,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);
@@ -5853,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);
@@ -5902,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);
@@ -5911,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);
@@ -5924,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);
@@ -5957,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);
@@ -6042,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();
@@ -6246,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();
@@ -6259,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
@@ -6582,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 {
@@ -43696,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);
@@ -57462,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 fd26f08..91d6292 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -3654,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();
@@ -4351,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);
@@ -5992,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();
@@ -6048,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);
@@ -6058,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);
@@ -6072,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);
@@ -6105,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);
@@ -6199,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();
@@ -6512,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();
@@ -6525,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
@@ -6849,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 {
@@ -9935,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);
@@ -46452,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);
@@ -48706,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
@@ -60556,6 +60552,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 46a5b4a..55d6ecd 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3537,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();
@@ -4219,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);
@@ -5857,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);
@@ -5906,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);
@@ -5915,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);
@@ -5928,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);
@@ -5961,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);
@@ -6046,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();
@@ -6250,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();
@@ -6263,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
@@ -6586,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 {
@@ -43770,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);
@@ -57536,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/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index 8bcbf51..7590325 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -305,7 +305,7 @@
}
if (zygote) {
- PreloadPublicNativeLibraries();
+ InitializeNativeLoader();
runtime.start("com.android.internal.os.ZygoteInit", args, zygote);
} else if (className) {
runtime.start("com.android.internal.os.RuntimeInit", args, zygote);
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 132b6dd..1e288de 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4580,13 +4580,13 @@
private void buildIntoRemoteViewContent(RemoteViews remoteViews,
RemoteViews customContent) {
- remoteViews.removeAllViews(R.id.notification_main_column);
- // Need to clone customContent before adding, because otherwise it can no longer be
- // parceled independently of remoteViews.
if (customContent != null) {
+ // Need to clone customContent before adding, because otherwise it can no longer be
+ // parceled independently of remoteViews.
customContent = customContent.clone();
+ remoteViews.removeAllViews(R.id.notification_main_column);
+ remoteViews.addView(R.id.notification_main_column, customContent);
}
- remoteViews.addView(R.id.notification_main_column, customContent);
// also update the end margin if there is an image
int endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
R.dimen.notification_content_margin_end);
@@ -4689,13 +4689,13 @@
private RemoteViews buildIntoRemoteView(RemoteViews remoteViews, int id,
RemoteViews customContent) {
- remoteViews.removeAllViews(id);
- // Need to clone customContent before adding, because otherwise it can no longer be
- // parceled independently of remoteViews.
if (customContent != null) {
+ // Need to clone customContent before adding, because otherwise it can no longer be
+ // parceled independently of remoteViews.
customContent = customContent.clone();
+ remoteViews.removeAllViews(id);
+ remoteViews.addView(id, customContent);
}
- remoteViews.addView(id, customContent);
return remoteViews;
}
}
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/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 56dcdb7..ed8143e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1057,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/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index e41136c..b5c1f30 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -524,7 +524,7 @@
}
/** @hide*/
- public void setFlags(@ShortcutFlags int flags) {
+ public void replaceFlags(@ShortcutFlags int flags) {
mFlags = flags;
}
diff --git a/core/java/android/os/Bundle.java b/core/java/android/os/Bundle.java
index f334e77..1097cad 100644
--- a/core/java/android/os/Bundle.java
+++ b/core/java/android/os/Bundle.java
@@ -51,7 +51,7 @@
*/
public Bundle() {
super();
- mFlags = FLAG_HAS_FDS_KNOWN;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -62,7 +62,7 @@
*/
Bundle(Parcel parcelledData) {
super(parcelledData);
- mFlags = FLAG_HAS_FDS_KNOWN;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
if (mParcelledData.hasFileDescriptors()) {
mFlags |= FLAG_HAS_FDS;
}
@@ -70,7 +70,7 @@
/* package */ Bundle(Parcel parcelledData, int length) {
super(parcelledData, length);
- mFlags = FLAG_HAS_FDS_KNOWN;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
if (mParcelledData.hasFileDescriptors()) {
mFlags |= FLAG_HAS_FDS;
}
@@ -85,7 +85,7 @@
*/
public Bundle(ClassLoader loader) {
super(loader);
- mFlags = FLAG_HAS_FDS_KNOWN;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -96,7 +96,7 @@
*/
public Bundle(int capacity) {
super(capacity);
- mFlags = FLAG_HAS_FDS_KNOWN;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -118,7 +118,7 @@
*/
public Bundle(PersistableBundle b) {
super(b);
- mFlags = FLAG_HAS_FDS_KNOWN;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -196,7 +196,7 @@
@Override
public void clear() {
super.clear();
- mFlags = FLAG_HAS_FDS_KNOWN;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
}
/**
@@ -1122,7 +1122,7 @@
*/
public void readFromParcel(Parcel parcel) {
super.readFromParcelInner(parcel);
- mFlags = FLAG_HAS_FDS_KNOWN;
+ mFlags = FLAG_HAS_FDS_KNOWN | FLAG_ALLOW_FDS;
if (mParcelledData.hasFileDescriptors()) {
mFlags |= FLAG_HAS_FDS;
}
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/provider/Settings.java b/core/java/android/provider/Settings.java
index 049d585..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());
}
}
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/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/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/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/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..f3ae688 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];
@@ -908,14 +909,6 @@
return imsList;
}
- @Deprecated
- public InputMethodSettings(
- Resources res, ContentResolver resolver,
- HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
- @UserIdInt int userId) {
- this(res, resolver, methodMap, methodList, userId, false /* copyOnWrite */);
- }
-
public InputMethodSettings(
Resources res, ContentResolver resolver,
HashMap<String, InputMethodInfo> methodMap, ArrayList<InputMethodInfo> methodList,
@@ -949,7 +942,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 +950,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 +1120,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 +1191,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 +1318,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 +1343,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_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 c699339..7496124 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -389,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)
{
@@ -1540,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
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_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index a9003c1..a7ac5b8 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -28,6 +28,7 @@
#include <DamageAccumulator.h>
#include <Matrix.h>
#include <RenderNode.h>
+#include <renderthread/CanvasContext.h>
#include <TreeInfo.h>
#include <Paint.h>
@@ -487,15 +488,7 @@
virtual void onPositionUpdated(RenderNode& node, const TreeInfo& info) override {
if (CC_UNLIKELY(!mWeakRef || !info.updateWindowPositions)) return;
- ATRACE_NAME("Update SurfaceView position");
- JNIEnv* env = jnienv();
- jobject localref = env->NewLocalRef(mWeakRef);
- if (CC_UNLIKELY(!localref)) {
- jnienv()->DeleteWeakGlobalRef(mWeakRef);
- mWeakRef = nullptr;
- return;
- }
Matrix4 transform;
info.damageAccumulator->computeCurrentTransform(&transform);
const RenderProperties& props = node.properties();
@@ -505,10 +498,13 @@
bounds.right -= info.windowInsetLeft;
bounds.top -= info.windowInsetTop;
bounds.bottom -= info.windowInsetTop;
- env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
- (jlong) info.frameNumber, (jint) bounds.left, (jint) bounds.top,
- (jint) bounds.right, (jint) bounds.bottom);
- env->DeleteLocalRef(localref);
+
+ auto functor = std::bind(
+ std::mem_fn(&SurfaceViewPositionUpdater::doUpdatePosition), this,
+ (jlong) info.frameNumber, (jint) bounds.left, (jint) bounds.top,
+ (jint) bounds.right, (jint) bounds.bottom);
+
+ info.canvasContext.enqueueFrameWork(std::move(functor));
}
private:
@@ -520,6 +516,23 @@
return env;
}
+ void doUpdatePosition(jlong frameNumber, jint left, jint top,
+ jint right, jint bottom) {
+ ATRACE_NAME("Update SurfaceView position");
+
+ JNIEnv* env = jnienv();
+ jobject localref = env->NewLocalRef(mWeakRef);
+ if (CC_UNLIKELY(!localref)) {
+ jnienv()->DeleteWeakGlobalRef(mWeakRef);
+ mWeakRef = nullptr;
+ return;
+ }
+
+ env->CallVoidMethod(localref, gSurfaceViewPositionUpdateMethod,
+ frameNumber, left, top, right, bottom);
+ env->DeleteLocalRef(localref);
+ }
+
JavaVM* mVm;
jobject mWeakRef;
};
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/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 3e86e6f..3973f2f 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -17,10 +17,13 @@
package android.graphics;
import android.annotation.FloatRange;
+import android.annotation.IntDef;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.graphics.drawable.Drawable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
/**
* Defines a simple shape, used for bounding graphical regions.
* <p>
@@ -34,11 +37,28 @@
public final class Outline {
private static final float RADIUS_UNDEFINED = Float.NEGATIVE_INFINITY;
- /** @hide */
- public Path mPath;
+ private static final int MODE_EMPTY = 0;
+ private static final int MODE_RECT = 1;
+ private static final int MODE_CONVEX_PATH = 2;
/** @hide */
- public Rect mRect;
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = false,
+ value = {
+ MODE_EMPTY,
+ MODE_RECT,
+ MODE_CONVEX_PATH,
+ })
+ public @interface Mode {}
+
+ @Mode
+ private int mMode = MODE_EMPTY;
+
+ /** @hide */
+ public final Path mPath = new Path();
+
+ /** @hide */
+ public final Rect mRect = new Rect();
/** @hide */
public float mRadius = RADIUS_UNDEFINED;
/** @hide */
@@ -63,8 +83,9 @@
* @see #isEmpty()
*/
public void setEmpty() {
- mPath = null;
- mRect = null;
+ mMode = MODE_EMPTY;
+ mPath.rewind();
+ mRect.setEmpty();
mRadius = RADIUS_UNDEFINED;
}
@@ -77,7 +98,7 @@
* @see #setEmpty()
*/
public boolean isEmpty() {
- return mRect == null && mPath == null;
+ return mMode == MODE_EMPTY;
}
@@ -90,7 +111,7 @@
* @see {@link android.view.View#setClipToOutline(boolean)}
*/
public boolean canClip() {
- return !isEmpty() && mRect != null;
+ return mMode != MODE_CONVEX_PATH;
}
/**
@@ -122,19 +143,9 @@
* @param src Source outline to copy from.
*/
public void set(@NonNull Outline src) {
- if (src.mPath != null) {
- if (mPath == null) {
- mPath = new Path();
- }
- mPath.set(src.mPath);
- mRect = null;
- }
- if (src.mRect != null) {
- if (mRect == null) {
- mRect = new Rect();
- }
- mRect.set(src.mRect);
- }
+ mMode = src.mMode;
+ mPath.set(src.mPath);
+ mRect.set(src.mRect);
mRadius = src.mRadius;
mAlpha = src.mAlpha;
}
@@ -165,10 +176,10 @@
return;
}
- if (mRect == null) mRect = new Rect();
+ mMode = MODE_RECT;
mRect.set(left, top, right, bottom);
mRadius = radius;
- mPath = null;
+ mPath.rewind();
}
/**
@@ -188,7 +199,7 @@
* bounds, or {@code false} if no outline bounds are set
*/
public boolean getRect(@NonNull Rect outRect) {
- if (mRect == null) {
+ if (mMode != MODE_RECT) {
return false;
}
outRect.set(mRect);
@@ -221,10 +232,10 @@
return;
}
- if (mPath == null) mPath = new Path();
- mPath.reset();
+ mMode = MODE_CONVEX_PATH;
+ mPath.rewind();
mPath.addOval(left, top, right, bottom, Path.Direction.CW);
- mRect = null;
+ mRect.setEmpty();
mRadius = RADIUS_UNDEFINED;
}
@@ -248,10 +259,10 @@
if (!convexPath.isConvex()) {
throw new IllegalArgumentException("path must be convex");
}
- if (mPath == null) mPath = new Path();
+ mMode = MODE_CONVEX_PATH;
mPath.set(convexPath);
- mRect = null;
+ mRect.setEmpty();
mRadius = RADIUS_UNDEFINED;
}
@@ -259,9 +270,9 @@
* Offsets the Outline by (dx,dy)
*/
public void offset(int dx, int dy) {
- if (mRect != null) {
+ if (mMode == MODE_RECT) {
mRect.offset(dx, dy);
- } else if (mPath != null) {
+ } else if (mMode == MODE_CONVEX_PATH) {
mPath.offset(dx, dy);
}
}
diff --git a/libs/hwui/Caches.h b/libs/hwui/Caches.h
index 330dc29..eac9359 100644
--- a/libs/hwui/Caches.h
+++ b/libs/hwui/Caches.h
@@ -92,6 +92,8 @@
*/
bool init();
+ bool isInitialized() { return mInitialized; }
+
/**
* Flush the cache.
*
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/Layer.cpp b/libs/hwui/Layer.cpp
index 114347d..cdbbbab 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -197,7 +197,12 @@
}
void Layer::clearTexture() {
- caches.textureState().unbindTexture(texture.mId);
+ // There's a rare possibility that Caches could have been destroyed already
+ // since this method is queued up as a task.
+ // Since this is a reset method, treat this as non-fatal.
+ if (caches.isInitialized()) {
+ caches.textureState().unbindTexture(texture.mId);
+ }
texture.mId = 0;
}
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index a496b49..c539d63 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -484,6 +484,8 @@
bool drew = mCanvas->finish();
#endif
+ waitOnFences();
+
GL_CHECKPOINT(LOW);
// Even if we decided to cancel the frame, from the perspective of jank
@@ -726,6 +728,37 @@
#endif
}
+void CanvasContext::waitOnFences() {
+ if (mFrameFences.size()) {
+ ATRACE_CALL();
+ for (auto& fence : mFrameFences) {
+ fence->getResult();
+ }
+ mFrameFences.clear();
+ }
+}
+
+class CanvasContext::FuncTaskProcessor : public TaskProcessor<bool> {
+public:
+ FuncTaskProcessor(Caches& caches)
+ : TaskProcessor<bool>(&caches.tasks) {}
+
+ virtual void onProcess(const sp<Task<bool> >& task) override {
+ FuncTask* t = static_cast<FuncTask*>(task.get());
+ t->func();
+ task->setResult(true);
+ }
+};
+
+void CanvasContext::enqueueFrameWork(std::function<void()>&& func) {
+ if (!mFrameWorkProcessor.get()) {
+ mFrameWorkProcessor = new FuncTaskProcessor(Caches::getInstance());
+ }
+ sp<FuncTask> task(new FuncTask());
+ task->func = func;
+ mFrameWorkProcessor->add(task);
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index cb61e51..6706c30 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -24,6 +24,8 @@
#include "IContextFactory.h"
#include "LayerUpdateQueue.h"
#include "RenderNode.h"
+#include "thread/Task.h"
+#include "thread/TaskProcessor.h"
#include "utils/RingBuffer.h"
#include "renderthread/RenderTask.h"
#include "renderthread/RenderThread.h"
@@ -41,6 +43,7 @@
#include <utils/Functor.h>
#include <gui/Surface.h>
+#include <functional>
#include <set>
#include <string>
#include <vector>
@@ -159,6 +162,9 @@
}
}
+ // Used to queue up work that needs to be completed before this frame completes
+ ANDROID_API void enqueueFrameWork(std::function<void()>&& func);
+
private:
friend class RegisterFrameCallbackTask;
// TODO: Replace with something better for layer & other GL object
@@ -170,6 +176,8 @@
void freePrefetechedLayers();
+ void waitOnFences();
+
EGLint mLastFrameWidth = 0;
EGLint mLastFrameHeight = 0;
@@ -213,6 +221,16 @@
// Stores the bounds of the main content.
Rect mContentDrawBounds;
+
+ // TODO: This is really a Task<void> but that doesn't really work
+ // when Future<> expects to be able to get/set a value
+ struct FuncTask : public Task<bool> {
+ std::function<void()> func;
+ };
+ class FuncTaskProcessor;
+
+ std::vector< sp<FuncTask> > mFrameFences;
+ sp<TaskProcessor<bool> > mFrameWorkProcessor;
};
} /* namespace renderthread */
diff --git a/libs/hwui/tests/scripts/prep_volantis.sh b/libs/hwui/tests/scripts/prep_volantis.sh
index 09d4869..0572ee55 100755
--- a/libs/hwui/tests/scripts/prep_volantis.sh
+++ b/libs/hwui/tests/scripts/prep_volantis.sh
@@ -49,6 +49,6 @@
# 684000 708000 756000 804000 852000 (kHz)
S=324000000
-echo "set gpu to $s hz"
+echo "set gpu to $S hz"
adb shell "echo 1 > /d/clock/override.gbus/state"
adb shell "echo $S > /d/clock/override.gbus/rate"
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/thread/Barrier.h b/libs/hwui/thread/Barrier.h
index 6cb23e5..0a7acb0 100644
--- a/libs/hwui/thread/Barrier.h
+++ b/libs/hwui/thread/Barrier.h
@@ -33,11 +33,6 @@
mCondition.signal(mType);
}
- void close() {
- Mutex::Autolock l(mLock);
- mOpened = false;
- }
-
void wait() const {
Mutex::Autolock l(mLock);
while (!mOpened) {
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/MediaFormat.java b/media/java/android/media/MediaFormat.java
index 26061e4..346f083 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -508,7 +508,8 @@
* The associated value is an integer.
* Constants are declared in {@link MediaCodecInfo.CodecProfileLevel}.
* This key is used as a hint, and is only supported for codecs
- * that specify a profile.
+ * that specify a profile. Note: Codecs are free to use all the available
+ * coding tools at the specified profile.
*
* @see MediaCodecInfo.CodecCapabilities#profileLevels
*/
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/native/android/sensor.cpp b/native/android/sensor.cpp
index 76c701a..5cfe300 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -105,6 +105,14 @@
/*****************************************************************************/
+int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
+ int32_t samplingPeriodUs, int maxBatchReportLatencyUs)
+{
+ return static_cast<SensorEventQueue*>(queue)->enableSensor(
+ static_cast<Sensor const*>(sensor)->getHandle(), samplingPeriodUs,
+ maxBatchReportLatencyUs, 0);
+}
+
int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor)
{
return static_cast<SensorEventQueue*>(queue)->enableSensor(
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/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 606f4eb7..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/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/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/layout/recents_on_tv.xml b/packages/SystemUI/res/layout/recents_on_tv.xml
index 3a7c1d1..567e009 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout/recents_on_tv.xml
@@ -18,7 +18,6 @@
android:id="@+id/recents_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:background="@drawable/recents_tv_background_gradient"
android:clipChildren="false"
android:clipToPadding="false"
android:layoutDirection="rtl">
diff --git a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
index c5b1a7a..54e97da 100644
--- a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
+++ b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
@@ -59,7 +59,7 @@
<ImageView
android:id="@+id/card_view_thumbnail"
android:layout_width="match_parent"
- android:layout_height="@dimen/recents_tv_card_height"
+ android:layout_height="@dimen/recents_tv_screenshot_height"
android:scaleType="centerCrop"
android:gravity="center"
android:layout_alignParentTop="true"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index d65ab04..eeed0cf 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -155,6 +155,8 @@
<color name="default_remote_input_background">@*android:color/notification_default_color</color>
<color name="remote_input_hint">#4dffffff</color>
+ <color name="remote_input_accent">#eeeeee</color>
+
<color name="qs_tile_tint_unavailable">#40ffffff</color>
<color name="qs_tile_tint_inactive">#4dffffff</color>
<color name="qs_tile_tint_active">#ffffffff</color>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index b589110..6b153d1 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -19,7 +19,7 @@
<resources>
<!-- Dimens for recents card in the recents view on tv -->
<dimen name="recents_tv_card_width">268dip</dimen>
- <dimen name="recents_tv_card_height">151dip</dimen>
+ <dimen name="recents_tv_screenshot_height">151dip</dimen>
<dimen name="recents_tv_card_extra_badge_size">20dip</dimen>
<dimen name="recents_tv_banner_width">114dip</dimen>
<dimen name="recents_tv_banner_height">64dip</dimen>
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/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 2660926..b0c1e95 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -201,8 +201,8 @@
<item name="android:colorControlActivated">@color/system_accent_color</item>
</style>
- <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault">
- <item name="android:colorControlActivated">@android:color/white</item>
+ <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
+ <item name="android:colorAccent">@color/remote_input_accent</item>
</style>
<style name="Theme.SystemUI.Dialog" parent="@android:style/Theme.DeviceDefault.Light.Dialog">
diff --git a/packages/SystemUI/res/values/values_tv.xml b/packages/SystemUI/res/values/values_tv.xml
index 1fcc9e4..6a72e54 100644
--- a/packages/SystemUI/res/values/values_tv.xml
+++ b/packages/SystemUI/res/values/values_tv.xml
@@ -15,4 +15,5 @@
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item format="float" type="integer" name="unselected_scale">1.0</item>
+ <item format="float" type="integer" name="selected_scale">1.1</item>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 358674c..aa3f6e5 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -535,31 +535,43 @@
boolean nowExpanded;
int naturalHeight = mScaler.getNaturalHeight();
if (wasClosed) {
- nowExpanded = (force || currentHeight > mOldHeight);
+ nowExpanded = (force || currentHeight > mOldHeight && velocity >= 0);
} else {
- nowExpanded = !force && currentHeight >= mOldHeight;
+ nowExpanded = !force && (currentHeight >= mOldHeight || velocity > 0);
}
nowExpanded |= mNaturalHeight == mSmallSize;
if (mScaleAnimation.isRunning()) {
mScaleAnimation.cancel();
}
- mCallback.setUserExpandedChild(mResizedView, nowExpanded);
mCallback.expansionStateChanged(false);
float targetHeight = nowExpanded ? naturalHeight : mSmallSize;
if (targetHeight != currentHeight) {
mScaleAnimation.setFloatValues(targetHeight);
mScaleAnimation.setupStartValues();
final View scaledView = mResizedView;
+ final boolean expand = nowExpanded;
mScaleAnimation.addListener(new AnimatorListenerAdapter() {
+ public boolean mCancelled;
+
@Override
public void onAnimationEnd(Animator animation) {
+ if (!mCancelled) {
+ mCallback.setUserExpandedChild(scaledView, expand);
+ }
mCallback.setUserLockedChild(scaledView, false);
mScaleAnimation.removeListener(this);
}
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ mCancelled = true;
+ }
});
+ velocity = nowExpanded == velocity >= 0 ? velocity : 0;
mFlingAnimationUtils.apply(mScaleAnimation, currentHeight, targetHeight, velocity);
mScaleAnimation.start();
} else {
+ mCallback.setUserExpandedChild(mResizedView, nowExpanded);
mCallback.setUserLockedChild(mResizedView, false);
}
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/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index d864df8..9be24de 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -66,6 +66,7 @@
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskGrouping;
import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.TaskCardView;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskStackViewScroller;
@@ -166,6 +167,7 @@
boolean mCanReuseTaskStackViews = true;
boolean mDraggingInRecents;
boolean mLaunchedWhileDocking;
+ private boolean mIsRunningOnTv;
// Task launching
Rect mSearchBarBounds = new Rect();
@@ -230,8 +232,10 @@
UiModeManager uiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
mRecentsIntentActivityName = RECENTS_TV_ACTIVITY;
+ mIsRunningOnTv = true;
} else {
mRecentsIntentActivityName = RECENTS_ACTIVITY;
+ mIsRunningOnTv = false;
}
}
@@ -793,6 +797,22 @@
}
}
+ /**
+ * Creates the activity options for an app->recents transition on TV.
+ */
+ private ActivityOptions getThumbnailTransitionActivityOptionsForTV(
+ ActivityManager.RunningTaskInfo topTask) {
+ Bitmap thumbnail = mThumbnailTransitionBitmapCache;
+ Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext);
+ if (thumbnail != null) {
+ return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
+ null, (int) rect.left, (int) rect.top,
+ (int) rect.width(), (int) rect.height(), mHandler, null);
+ }
+ // If both the screenshot and thumbnail fails, then just fall back to the default transition
+ return getUnknownTransitionActivityOptions();
+ }
+
private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask,
TaskViewTransform toTransform) {
Bitmap thumbnail;
@@ -872,6 +892,11 @@
boolean isTopTaskHome, boolean animate) {
RecentsTaskLoader loader = Recents.getTaskLoader();
+ // If we are on TV, divert to a different helper method
+ if (mIsRunningOnTv) {
+ setUpAndStartTvRecents(topTask, isTopTaskHome, animate);
+ return;
+ }
// In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
// should always preload the tasks now. If we are dragging in recents, reload them as
// the stacks might have changed.
@@ -947,6 +972,90 @@
}
/**
+ * Used to set up the animations of Tv Recents, then start the Recents Activity.
+ * TODO: Add the Transitions for Home -> Recents TV
+ * TODO: Shift Transition code to separate class under /tv directory and access
+ * from here
+ */
+ private void setUpAndStartTvRecents(ActivityManager.RunningTaskInfo topTask,
+ boolean isTopTaskHome, boolean animate) {
+ RecentsTaskLoader loader = Recents.getTaskLoader();
+
+ // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
+ // should always preload the tasks now. If we are dragging in recents, reload them as
+ // the stacks might have changed.
+ if (mLaunchedWhileDocking || mTriggeredFromAltTab || sInstanceLoadPlan == null) {
+ // Create a new load plan if preloadRecents() was never triggered
+ sInstanceLoadPlan = loader.createLoadPlan(mContext);
+ }
+ if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
+ loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome);
+ }
+ TaskStack stack = sInstanceLoadPlan.getTaskStack();
+
+ // Update the header bar if necessary
+ updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
+
+ // Prepare the dummy stack for the transition
+ TaskStackLayoutAlgorithm.VisibilityReport stackVr =
+ mDummyStackView.computeStackVisibilityReport();
+
+ if (!animate) {
+ ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
+ startRecentsActivity(topTask, opts, false /* fromHome */,
+ false /* fromSearchHome */, false /* fromThumbnail*/, stackVr);
+ return;
+ }
+
+ boolean hasRecentTasks = stack.getTaskCount() > 0;
+ boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
+
+ if (useThumbnailTransition) {
+ // Try starting with a thumbnail transition
+ ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(topTask);
+ if (opts != null) {
+ startRecentsActivity(topTask, opts, false /* fromHome */,
+ false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
+ } else {
+ // Fall through below to the non-thumbnail transition
+ useThumbnailTransition = false;
+ }
+ }
+
+ if (!useThumbnailTransition) {
+ // If there is no thumbnail transition, but is launching from home into recents, then
+ // use a quick home transition and do the animation from home
+ if (hasRecentTasks) {
+ SystemServicesProxy ssp = Recents.getSystemServices();
+ String homeActivityPackage = ssp.getHomeActivityPackageName();
+ String searchWidgetPackage = null;
+ if (RecentsDebugFlags.Static.EnableSearchBar) {
+ searchWidgetPackage = Prefs.getString(mContext,
+ Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
+ } else {
+ AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget();
+ if (searchWidgetInfo != null) {
+ searchWidgetPackage = searchWidgetInfo.provider.getPackageName();
+ }
+ }
+
+ // Determine whether we are coming from a search owned home activity
+ boolean fromSearchHome = (homeActivityPackage != null) &&
+ homeActivityPackage.equals(searchWidgetPackage);
+ ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
+ startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
+ false /* fromThumbnail */, stackVr);
+ } else {
+ // Otherwise we do the normal fade from an unknown source
+ ActivityOptions opts = getUnknownTransitionActivityOptions();
+ startRecentsActivity(topTask, opts, true /* fromHome */,
+ false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
+ }
+ }
+ mLastToggleTime = SystemClock.elapsedRealtime();
+ }
+
+ /**
* Starts the recents activity.
*/
private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
index 48a1904..365b29d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -29,6 +29,7 @@
public class ViewFocusAnimator implements View.OnFocusChangeListener {
private final float mUnselectedScale;
+ private final float mSelectedScale;
private final float mSelectedScaleDelta;
private final float mUnselectedZ;
private final float mSelectedZDelta;
@@ -49,8 +50,9 @@
TypedValue out = new TypedValue();
res.getValue(R.integer.unselected_scale, out, true);
mUnselectedScale = out.getFloat();
- mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
- mUnselectedScale;
+ res.getValue(R.integer.selected_scale, out, true);
+ mSelectedScale = out.getFloat();
+ mSelectedScaleDelta = mSelectedScale - mUnselectedScale;
mUnselectedZ = res.getDimensionPixelOffset(R.dimen.recents_tv_unselected_item_z);
mSelectedZDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_selected_item_z_delta);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
index ef8d48e..bd3143f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
@@ -16,10 +16,8 @@
package com.android.systemui.recents.tv.views;
import android.annotation.Nullable;
-import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.Context;
-import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
@@ -121,10 +119,10 @@
};
}
try {
- Rect taskRect = taskView.getGlobalRect();
+ Rect taskRect = taskView.getFocusedThumbnailRect();
WindowManagerGlobal.getWindowManagerService()
- .overridePendingAppTransitionThumb(task.thumbnail, taskRect.left,
- taskRect.top, callback, true);
+ .overridePendingAppTransitionAspectScaledThumb(task.thumbnail, taskRect.left,
+ taskRect.top, taskRect.width(), taskRect.height(), callback, true);
} catch (RemoteException e) {
Log.w(TAG, "Failed to override transition: " + e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index 7d8a3ce..5775b60 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -16,8 +16,13 @@
package com.android.systemui.recents.tv.views;
import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.Display;
+import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -71,15 +76,46 @@
mThumbnailView.getFocusedRect(r);
}
- public Rect getFocusedRect() {
+ public Rect getFocusedThumbnailRect() {
Rect r = new Rect();
- getFocusedRect(r);
+ mThumbnailView.getGlobalVisibleRect(r);
+ TypedValue out = new TypedValue();
+ getContext().getResources().getValue(R.integer.selected_scale, out, true);
+ float deltaScale = (out.getFloat() - 1.0f) / 2;
+ r.set((int) (r.left - r.left * deltaScale),
+ (int) (r.top - r.top * deltaScale),
+ (int) (r.right + r.right * deltaScale),
+ (int) (r.bottom + r.bottom * deltaScale));
return r;
}
- public Rect getGlobalRect() {
- Rect r = new Rect();
- getGlobalVisibleRect(r);
- return r;
+ public static Rect getStartingCardThumbnailRect(Context context) {
+ Resources res = context.getResources();
+
+ TypedValue out = new TypedValue();
+ res.getValue(R.integer.selected_scale, out, true);
+ float scale = out.getFloat();
+
+ int width = res.getDimensionPixelOffset(R.dimen.recents_tv_card_width);
+ int widthDelta = (int) (width * scale - width);
+ int height = (int) (res.getDimensionPixelOffset(
+ R.dimen.recents_tv_screenshot_height) * scale);
+ int padding = res.getDimensionPixelOffset(R.dimen.recents_tv_grid_row_padding);
+
+ int headerHeight = (int) ((res.getDimensionPixelOffset(
+ R.dimen.recents_tv_card_extra_badge_size) +
+ res.getDimensionPixelOffset(R.dimen.recents_tv_icon_padding_bottom)) * scale);
+
+ WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
+ Display display = wm.getDefaultDisplay();
+ Point size = new Point();
+ display.getSize(size);
+ int screenWidth = size.x;
+ int screenHeight = size.y;
+
+ return new Rect(screenWidth - width - padding - widthDelta / 2,
+ screenHeight / 2 - height / 2 + headerHeight / 2,
+ screenWidth - padding + widthDelta / 2,
+ screenHeight / 2 + height / 2 + headerHeight / 2);
}
}
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 e7db2a8..a94c8b8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -447,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;
}
@@ -466,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) {
@@ -880,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);
@@ -892,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);
}
@@ -968,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;
@@ -981,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);
@@ -1048,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);
@@ -1067,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;
}
@@ -1075,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;
@@ -1098,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;
}
@@ -1116,6 +1150,9 @@
@Override
public int permissionToOpCode(String permission) {
+ if (permission == null) {
+ return AppOpsManager.OP_NONE;
+ }
return AppOpsManager.permissionToOpCode(permission);
}
@@ -1165,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) {
@@ -1259,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;
}
@@ -1317,7 +1345,7 @@
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;
}
@@ -1582,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) {
@@ -2103,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) {
@@ -2317,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/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/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 703d812..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.
*/
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/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index 0641749..197b2fa 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -159,6 +159,8 @@
static final String TAG_EXTRAS = "extras";
static final String TAG_SHORTCUT = "shortcut";
static final String TAG_LAUNCHER = "launcher";
+ static final String TAG_PIN = "pin";
+ static final String TAG_LAUNCHER_PINS = "launcher-pins";
static final String ATTR_VALUE = "value";
static final String ATTR_NAME = "name";
@@ -174,6 +176,7 @@
static final String ATTR_FLAGS = "flags";
static final String ATTR_ICON_RES = "icon-res";
static final String ATTR_BITMAP_PATH = "bitmap-path";
+ static final String ATTR_PACKAGE_NAME = "package-name";
@VisibleForTesting
interface ConfigConstants {
@@ -723,7 +726,7 @@
/** Return the per-user state. */
@GuardedBy("mLock")
@NonNull
- private UserShortcuts getUserShortcutsLocked(@UserIdInt int userId) {
+ UserShortcuts getUserShortcutsLocked(@UserIdInt int userId) {
UserShortcuts userPackages = mUsers.get(userId);
if (userPackages == null) {
userPackages = loadUserLocked(userId);
@@ -738,15 +741,16 @@
/** Return the per-user per-package state. */
@GuardedBy("mLock")
@NonNull
- private PackageShortcuts getPackageShortcutsLocked(
+ PackageShortcuts getPackageShortcutsLocked(
@NonNull String packageName, @UserIdInt int userId) {
- final UserShortcuts userPackages = getUserShortcutsLocked(userId);
- PackageShortcuts shortcuts = userPackages.getPackages().get(packageName);
- if (shortcuts == null) {
- shortcuts = new PackageShortcuts(userId, packageName);
- userPackages.getPackages().put(packageName, shortcuts);
- }
- return shortcuts;
+ return getUserShortcutsLocked(userId).getPackageShortcuts(packageName);
+ }
+
+ @GuardedBy("mLock")
+ @NonNull
+ LauncherShortcuts getLauncherShortcuts(
+ @NonNull String packageName, @UserIdInt int userId) {
+ return getUserShortcutsLocked(userId).getLauncherShortcuts(packageName);
}
// === Caller validation ===
@@ -1057,7 +1061,7 @@
validatePersistableBundleForXml(shortcut.getIntentPersistableExtras());
validatePersistableBundleForXml(shortcut.getExtras());
- shortcut.setFlags(0);
+ shortcut.replaceFlags(0);
}
// KXmlSerializer is strict and doesn't allow certain characters, so we disallow those
@@ -1129,8 +1133,7 @@
// Then, add/update all. We need to make sure to take over "pinned" flag.
for (int i = 0; i < size; i++) {
final ShortcutInfo newShortcut = newShortcuts.get(i);
- newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
- ps.updateShortcutWithCapping(this, newShortcut);
+ ps.addDynamicShortcut(this, newShortcut);
}
}
userPackageChanged(packageName, userId);
@@ -1194,8 +1197,7 @@
fixUpIncomingShortcutInfo(newShortcut, /* forUpdate= */ false);
// Add it.
- newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
- ps.updateShortcutWithCapping(this, newShortcut);
+ ps.addDynamicShortcut(this, newShortcut);
}
userPackageChanged(packageName, userId);
@@ -1251,7 +1253,8 @@
final ArrayList<ShortcutInfo> ret = new ArrayList<>();
- getPackageShortcutsLocked(packageName, userId).findAll(ret, query, cloneFlags);
+ getPackageShortcutsLocked(packageName, userId).findAll(this, ret, query, cloneFlags,
+ /* callingLauncher= */ null);
return new ParceledListSlice<>(ret);
}
@@ -1406,25 +1409,27 @@
synchronized (mLock) {
if (packageName != null) {
- getShortcutsInnerLocked(packageName, changedSince, componentName, queryFlags,
- userId, ret, cloneFlag);
+ getShortcutsInnerLocked(
+ callingPackage, packageName, changedSince,
+ componentName, queryFlags, userId, ret, cloneFlag);
} else {
final ArrayMap<String, PackageShortcuts> packages =
getUserShortcutsLocked(userId).getPackages();
for (int i = packages.size() - 1; i >= 0; i--) {
getShortcutsInnerLocked(
- packages.keyAt(i),
- changedSince, componentName, queryFlags, userId, ret, cloneFlag);
+ callingPackage, packages.keyAt(i), changedSince,
+ componentName, queryFlags, userId, ret, cloneFlag);
}
}
}
return ret;
}
- private void getShortcutsInnerLocked(@Nullable String packageName,long changedSince,
+ private void getShortcutsInnerLocked(@NonNull String callingPackage,
+ @Nullable String packageName,long changedSince,
@Nullable ComponentName componentName, int queryFlags,
int userId, ArrayList<ShortcutInfo> ret, int cloneFlag) {
- getPackageShortcutsLocked(packageName, userId).findAll(ret,
+ getPackageShortcutsLocked(packageName, userId).findAll(ShortcutService.this, ret,
(ShortcutInfo si) -> {
if (si.getLastChangedTimestamp() < changedSince) {
return false;
@@ -1435,12 +1440,12 @@
}
final boolean matchDynamic =
((queryFlags & ShortcutQuery.FLAG_GET_DYNAMIC) != 0)
- && si.isDynamic();
+ && si.isDynamic();
final boolean matchPinned =
((queryFlags & ShortcutQuery.FLAG_GET_PINNED) != 0)
&& si.isPinned();
return matchDynamic || matchPinned;
- }, cloneFlag);
+ }, cloneFlag, callingPackage);
}
@Override
@@ -1453,9 +1458,10 @@
final ArrayList<ShortcutInfo> ret = new ArrayList<>(ids.size());
final ArraySet<String> idSet = new ArraySet<>(ids);
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).findAll(ret,
+ getPackageShortcutsLocked(packageName, userId).findAll(
+ ShortcutService.this, ret,
(ShortcutInfo si) -> idSet.contains(si.getId()),
- ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
+ ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER, callingPackage);
}
return ret;
}
@@ -1468,8 +1474,8 @@
Preconditions.checkNotNull(shortcutIds, "shortcutIds");
synchronized (mLock) {
- getPackageShortcutsLocked(packageName, userId).replacePinned(
- ShortcutService.this, callingPackage, shortcutIds);
+ getLauncherShortcuts(callingPackage, userId).pinShortcuts(
+ ShortcutService.this, packageName, shortcutIds);
}
userPackageChanged(packageName, userId);
}
@@ -1812,6 +1818,14 @@
Binder.restoreCallingIdentity(token);
}
+ final void wtf(String message) {
+ Slog.wtf(TAG, message, /* exception= */ null);
+ }
+
+ void wtf(String message, Exception e) {
+ Slog.wtf(TAG, message, e);
+ }
+
File injectSystemDataPath() {
return Environment.getDataSystemDirectory();
}
@@ -1887,6 +1901,8 @@
private final ArrayMap<String, PackageShortcuts> mPackages = new ArrayMap<>();
+ private final ArrayMap<String, LauncherShortcuts> mLaunchers = new ArrayMap<>();
+
private ComponentName mLauncherComponent;
public UserShortcuts(int userId) {
@@ -1897,13 +1913,41 @@
return mPackages;
}
+ public ArrayMap<String, LauncherShortcuts> getLaunchers() {
+ return mLaunchers;
+ }
+
+ public PackageShortcuts getPackageShortcuts(@NonNull String packageName) {
+ PackageShortcuts ret = mPackages.get(packageName);
+ if (ret == null) {
+ ret = new PackageShortcuts(mUserId, packageName);
+ mPackages.put(packageName, ret);
+ }
+ return ret;
+ }
+
+ public LauncherShortcuts getLauncherShortcuts(@NonNull String packageName) {
+ LauncherShortcuts ret = mLaunchers.get(packageName);
+ if (ret == null) {
+ ret = new LauncherShortcuts(mUserId, packageName);
+ mLaunchers.put(packageName, ret);
+ }
+ return ret;
+ }
+
public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
out.startTag(null, ShortcutService.TAG_USER);
ShortcutService.writeTagValue(out, ShortcutService.TAG_LAUNCHER,
mLauncherComponent);
- for (int i = 0; i < mPackages.size(); i++) {
+ final int lsize = mLaunchers.size();
+ for (int i = 0; i < lsize; i++) {
+ mLaunchers.valueAt(i).saveToXml(out);
+ }
+
+ final int psize = mPackages.size();
+ for (int i = 0; i < psize; i++) {
mPackages.valueAt(i).saveToXml(out);
}
@@ -1924,16 +1968,26 @@
final int depth = parser.getDepth();
final String tag = parser.getName();
switch (tag) {
- case ShortcutService.TAG_LAUNCHER:
+ case ShortcutService.TAG_LAUNCHER: {
ret.mLauncherComponent = ShortcutService.parseComponentNameAttribute(
parser, ShortcutService.ATTR_VALUE);
continue;
- case ShortcutService.TAG_PACKAGE:
+ }
+ case ShortcutService.TAG_PACKAGE: {
final PackageShortcuts shortcuts = PackageShortcuts.loadFromXml(parser, userId);
// Don't use addShortcut(), we don't need to save the icon.
ret.getPackages().put(shortcuts.mPackageName, shortcuts);
continue;
+ }
+
+ case ShortcutService.TAG_LAUNCHER_PINS: {
+ final LauncherShortcuts shortcuts =
+ LauncherShortcuts.loadFromXml(parser, userId);
+
+ ret.getLaunchers().put(shortcuts.mPackageName, shortcuts);
+ continue;
+ }
}
throw ShortcutService.throwForInvalidTag(depth, tag);
}
@@ -1970,12 +2024,166 @@
pw.print(mLauncherComponent);
pw.println();
+ for (int i = 0; i < mLaunchers.size(); i++) {
+ mLaunchers.valueAt(i).dump(s, pw, prefix + " ");
+ }
+
for (int i = 0; i < mPackages.size(); i++) {
mPackages.valueAt(i).dump(s, pw, prefix + " ");
}
}
}
+class LauncherShortcuts {
+ private static final String TAG = ShortcutService.TAG;
+
+ @UserIdInt
+ final int mUserId;
+
+ @NonNull
+ final String mPackageName;
+
+ /**
+ * Package name -> IDs.
+ */
+ final private ArrayMap<String, ArraySet<String>> mPinnedShortcuts = new ArrayMap<>();
+
+ LauncherShortcuts(@UserIdInt int userId, @NonNull String packageName) {
+ mUserId = userId;
+ mPackageName = packageName;
+ }
+
+ public void pinShortcuts(@NonNull ShortcutService s, @NonNull String packageName,
+ @NonNull List<String> ids) {
+ final int idSize = ids.size();
+ if (idSize == 0) {
+ mPinnedShortcuts.remove(packageName);
+ } else {
+ final ArraySet<String> prevSet = mPinnedShortcuts.get(packageName);
+
+ // Pin shortcuts. Make sure only pin the ones that were visible to the caller.
+ // i.e. a non-dynamic, pinned shortcut by *other launchers* shouldn't be pinned here.
+
+ final PackageShortcuts packageShortcuts =
+ s.getPackageShortcutsLocked(packageName, mUserId);
+ final ArraySet<String> newSet = new ArraySet<>();
+
+ for (int i = 0; i < idSize; i++) {
+ final String id = ids.get(i);
+ final ShortcutInfo si = packageShortcuts.findShortcutById(id);
+ if (si == null) {
+ continue;
+ }
+ if (si.isDynamic() || (prevSet != null && prevSet.contains(id))) {
+ newSet.add(id);
+ }
+ }
+ mPinnedShortcuts.put(packageName, newSet);
+ }
+ s.getPackageShortcutsLocked(packageName, mUserId).refreshPinnedFlags(s);
+ }
+
+ /**
+ * Return the pinned shortcut IDs for the publisher package.
+ */
+ public ArraySet<String> getPinnedShortcutIds(@NonNull String packageName) {
+ return mPinnedShortcuts.get(packageName);
+ }
+
+ /**
+ * Persist.
+ */
+ public void saveToXml(XmlSerializer out) throws IOException {
+ out.startTag(null, ShortcutService.TAG_LAUNCHER_PINS);
+ ShortcutService.writeAttr(out, ShortcutService.ATTR_PACKAGE_NAME,
+ mPackageName);
+
+ final int size = mPinnedShortcuts.size();
+ for (int i = 0; i < size; i++) {
+ out.startTag(null, ShortcutService.TAG_PACKAGE);
+ ShortcutService.writeAttr(out, ShortcutService.ATTR_PACKAGE_NAME,
+ mPinnedShortcuts.keyAt(i));
+
+ final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
+ final int idSize = ids.size();
+ for (int j = 0; j < idSize; j++) {
+ ShortcutService.writeTagValue(out, ShortcutService.TAG_PIN, ids.valueAt(j));
+ }
+ out.endTag(null, ShortcutService.TAG_PACKAGE);
+ }
+
+ out.endTag(null, ShortcutService.TAG_LAUNCHER_PINS);
+ }
+
+ /**
+ * Load.
+ */
+ public static LauncherShortcuts loadFromXml(XmlPullParser parser, int userId)
+ throws IOException, XmlPullParserException {
+ final String launcherPackageName = ShortcutService.parseStringAttribute(parser,
+ ShortcutService.ATTR_PACKAGE_NAME);
+
+ final LauncherShortcuts ret = new LauncherShortcuts(userId, launcherPackageName);
+
+ ArraySet<String> ids = null;
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+ final int depth = parser.getDepth();
+ final String tag = parser.getName();
+ switch (tag) {
+ case ShortcutService.TAG_PACKAGE: {
+ final String packageName = ShortcutService.parseStringAttribute(parser,
+ ShortcutService.ATTR_PACKAGE_NAME);
+ ids = new ArraySet<>();
+ ret.mPinnedShortcuts.put(packageName, ids);
+ continue;
+ }
+ case ShortcutService.TAG_PIN: {
+ ids.add(ShortcutService.parseStringAttribute(parser,
+ ShortcutService.ATTR_VALUE));
+ continue;
+ }
+ }
+ throw ShortcutService.throwForInvalidTag(depth, tag);
+ }
+ return ret;
+ }
+
+ public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
+ pw.println();
+
+ pw.print(prefix);
+ pw.print("Launcher: ");
+ pw.print(mPackageName);
+ pw.println();
+
+ final int size = mPinnedShortcuts.size();
+ for (int i = 0; i < size; i++) {
+ pw.println();
+
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print("Package: ");
+ pw.println(mPinnedShortcuts.keyAt(i));
+
+ final ArraySet<String> ids = mPinnedShortcuts.valueAt(i);
+ final int idSize = ids.size();
+
+ for (int j = 0; j < idSize; j++) {
+ pw.print(prefix);
+ pw.print(" ");
+ pw.print(ids.valueAt(j));
+ pw.println();
+ }
+ }
+ }
+}
+
/**
* All the information relevant to shortcuts from a single package (per-user).
*/
@@ -2039,27 +2247,34 @@
*
* It checks the max number of dynamic shortcuts.
*/
- public void updateShortcutWithCapping(@NonNull ShortcutService s,
+ public void addDynamicShortcut(@NonNull ShortcutService s,
@NonNull ShortcutInfo newShortcut) {
+ newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC);
+
final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId());
- int oldFlags = 0;
- int newDynamicCount = mDynamicShortcutCount;
+ final boolean wasPinned;
+ final int newDynamicCount;
- if (oldShortcut != null) {
- oldFlags = oldShortcut.getFlags();
+ if (oldShortcut == null) {
+ wasPinned = false;
+ newDynamicCount = mDynamicShortcutCount + 1; // adding a dynamic shortcut.
+ } else {
+ wasPinned = oldShortcut.isPinned();
if (oldShortcut.isDynamic()) {
- newDynamicCount--;
+ newDynamicCount = mDynamicShortcutCount; // not adding a dynamic shortcut.
+ } else {
+ newDynamicCount = mDynamicShortcutCount + 1; // adding a dynamic shortcut.
}
}
- if (newShortcut.isDynamic()) {
- newDynamicCount++;
- }
+
// Make sure there's still room.
s.enforceMaxDynamicShortcuts(newDynamicCount);
// Okay, make it dynamic and add.
- newShortcut.addFlags(oldFlags);
+ if (wasPinned) {
+ newShortcut.addFlags(ShortcutInfo.FLAG_PINNED);
+ }
addShortcut(s, newShortcut);
mDynamicShortcutCount = newDynamicCount;
@@ -2088,6 +2303,9 @@
}
}
+ /**
+ * Remove all dynamic shortcuts.
+ */
public void deleteAllDynamicShortcuts(@NonNull ShortcutService s) {
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_DYNAMIC);
@@ -2096,6 +2314,9 @@
mDynamicShortcutCount = 0;
}
+ /**
+ * Remove a dynamic shortcut by ID.
+ */
public void deleteDynamicWithId(@NonNull ShortcutService s, @NonNull String shortcutId) {
final ShortcutInfo oldShortcut = mShortcuts.get(shortcutId);
@@ -2112,24 +2333,40 @@
}
}
- public void replacePinned(@NonNull ShortcutService s, String launcherPackage,
- List<String> shortcutIds) {
-
- // TODO Should be per launcherPackage.
-
+ /**
+ * Called after a launcher updates the pinned set. For each shortcut in this package,
+ * set FLAG_PINNED if any launcher has pinned it. Otherwise, clear it.
+ *
+ * <p>Then remove all shortcuts that are not dynamic and no longer pinned either.
+ */
+ public void refreshPinnedFlags(@NonNull ShortcutService s) {
// First, un-pin all shortcuts
for (int i = mShortcuts.size() - 1; i >= 0; i--) {
mShortcuts.valueAt(i).clearFlags(ShortcutInfo.FLAG_PINNED);
}
- // Then pin ALL
- for (int i = shortcutIds.size() - 1; i >= 0; i--) {
- final ShortcutInfo shortcut = mShortcuts.get(shortcutIds.get(i));
- if (shortcut != null) {
- shortcut.addFlags(ShortcutInfo.FLAG_PINNED);
+ // Then, for the pinned set for each launcher, set the pin flag one by one.
+ final ArrayMap<String, LauncherShortcuts> launchers =
+ s.getUserShortcutsLocked(mUserId).getLaunchers();
+
+ for (int l = launchers.size() - 1; l >= 0; l--) {
+ final LauncherShortcuts launcherShortcuts = launchers.valueAt(l);
+ final ArraySet<String> pinned = launcherShortcuts.getPinnedShortcutIds(mPackageName);
+
+ if (pinned == null || pinned.size() == 0) {
+ continue;
+ }
+ for (int i = pinned.size() - 1; i >= 0; i--) {
+ final ShortcutInfo si = mShortcuts.get(pinned.valueAt(i));
+ if (si == null) {
+ s.wtf("Shortcut not found");
+ } else {
+ si.addFlags(ShortcutInfo.FLAG_PINNED);
+ }
}
}
+ // Lastly, remove the ones that are no longer pinned nor dynamic.
removeOrphans(s);
}
@@ -2173,12 +2410,40 @@
/**
* Find all shortcuts that match {@code query}.
*/
- public void findAll(@NonNull List<ShortcutInfo> result,
- @Nullable Predicate<ShortcutInfo> query, int cloneFlag) {
+ public void findAll(@NonNull ShortcutService s, @NonNull List<ShortcutInfo> result,
+ @Nullable Predicate<ShortcutInfo> query, int cloneFlag,
+ @Nullable String callingLauncher) {
+
+ // Set of pinned shortcuts by the calling launcher.
+ final ArraySet<String> pinnedByCallerSet = (callingLauncher == null) ? null
+ : s.getLauncherShortcuts(callingLauncher, mUserId)
+ .getPinnedShortcutIds(mPackageName);
+
for (int i = 0; i < mShortcuts.size(); i++) {
final ShortcutInfo si = mShortcuts.valueAt(i);
- if (query == null || query.test(si)) {
- result.add(si.clone(cloneFlag));
+
+ // If it's called by non-launcher (i.e. publisher, always include -> true.
+ // Otherwise, only include non-dynamic pinned one, if the calling launcher has pinned
+ // it.
+ final boolean isPinnedByCaller = (callingLauncher == null)
+ || ((pinnedByCallerSet != null) && pinnedByCallerSet.contains(si.getId()));
+ if (!si.isDynamic()) {
+ if (!si.isPinned()) {
+ s.wtf("Shortcut not pinned here");
+ continue;
+ }
+ if (!isPinnedByCaller) {
+ continue;
+ }
+ }
+ final ShortcutInfo clone = si.clone(cloneFlag);
+ // Fix up isPinned for the caller. Note we need to do it before the "test" callback,
+ // since it may check isPinned.
+ if (!isPinnedByCaller) {
+ clone.clearFlags(ShortcutInfo.FLAG_PINNED);
+ }
+ if (query == null || query.test(clone)) {
+ result.add(clone);
}
}
}
@@ -2188,6 +2453,8 @@
}
public void dump(@NonNull ShortcutService s, @NonNull PrintWriter pw, @NonNull String prefix) {
+ pw.println();
+
pw.print(prefix);
pw.print("Package: ");
pw.print(mPackageName);
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/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/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
index 6bcaf4d..5c51139 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest.java
@@ -57,6 +57,7 @@
import android.test.mock.MockContext;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
+import android.util.SparseArray;
import com.android.frameworks.servicestests.R;
import com.android.internal.util.Preconditions;
@@ -250,6 +251,12 @@
r.run();
mContext.injectRestoreCallingIdentity(token);
}
+
+ @Override
+ void wtf(String message, Exception e) {
+ // During tests, WTF is fatal.
+ fail(message + " exception: " + e);
+ }
}
/** ShortcutManager with injection override methods. */
@@ -1752,68 +1759,320 @@
public void testPinShortcutAndGetPinnedShortcuts() {
// Create some shortcuts.
- setCaller(CALLING_PACKAGE_1);
- final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
- final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ final ShortcutInfo s1_1 = makeShortcutWithTimestamp("s1", 1000);
+ final ShortcutInfo s1_2 = makeShortcutWithTimestamp("s2", 2000);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s1_1, s1_2)));
+ assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s1_1, s1_2)));
+ });
- setCaller(CALLING_PACKAGE_2);
- final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
- final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
- final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_2, s2_3, s2_4)));
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ final ShortcutInfo s2_2 = makeShortcutWithTimestamp("s2", 1500);
+ final ShortcutInfo s2_3 = makeShortcutWithTimestamp("s3", 3000);
+ final ShortcutInfo s2_4 = makeShortcutWithTimestamp("s4", 500);
+ assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_2, s2_3, s2_4)));
+ });
- setCaller(CALLING_PACKAGE_3);
- final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
- assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s2_2)));
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ final ShortcutInfo s3_2 = makeShortcutWithTimestamp("s2", 1000);
+ assertTrue(mManager.setDynamicShortcuts(Arrays.asList(s3_2)));
+ });
// Pin some.
- setCaller(LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ Arrays.asList("s2", "s3"), getCallingUser());
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
- Arrays.asList("s2", "s3"), getCallingUser());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+ Arrays.asList("s3", "s4", "s5"), getCallingUser());
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
- Arrays.asList("s3", "s4", "s5"), getCallingUser());
-
- mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
- Arrays.asList("s3"), getCallingUser()); // Note ID doesn't exist
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_3,
+ Arrays.asList("s3"), getCallingUser()); // Note ID doesn't exist
+ });
// Delete some.
- setCaller(CALLING_PACKAGE_1);
- assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
- mManager.deleteDynamicShortcut("s2");
- assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+ mManager.deleteDynamicShortcut("s2");
+ assertShortcutIds(mManager.getPinnedShortcuts(), "s2");
+ });
- setCaller(CALLING_PACKAGE_2);
- assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
- mManager.deleteDynamicShortcut("s3");
- assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+ mManager.deleteDynamicShortcut("s3");
+ assertShortcutIds(mManager.getPinnedShortcuts(), "s3", "s4");
+ });
- setCaller(CALLING_PACKAGE_3);
- assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
- mManager.deleteDynamicShortcut("s2");
- assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+ runWithCaller(CALLING_PACKAGE_3, USER_0, () -> {
+ assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+ mManager.deleteDynamicShortcut("s2");
+ assertShortcutIds(mManager.getPinnedShortcuts() /* none */);
+ });
// Get pinned shortcuts from launcher
- setCaller(LAUNCHER_1);
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s2");
- // CALLING_PACKAGE_1 deleted s2, but it's pinned, so it still exists.
- assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
- mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
- /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
- "s2");
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s3", "s4");
- assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
- mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
- /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
- "s3", "s4");
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
+ /* none */);
+ });
+ }
- assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
- mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_3,
- /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
- /* none */);
+ public void testPinShortcutAndGetPinnedShortcuts_multi() {
+ // Create some shortcuts.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertTrue(mManager.setDynamicShortcuts(Arrays.asList(
+ makeShortcut("s1"), makeShortcut("s2"), makeShortcut("s3"))));
+ });
+
+ dumpsysOnLogcat();
+
+ // Pin some.
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ Arrays.asList("s3", "s4"), getCallingUser());
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+ Arrays.asList("s1", "s2", "s4"), getCallingUser());
+ });
+
+ dumpsysOnLogcat();
+
+ // Delete some.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
+ mManager.deleteDynamicShortcut("s3");
+ assertShortcutIds(mManager.getPinnedShortcuts(), "s3");
+ });
+
+ dumpsysOnLogcat();
+
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
+ mManager.deleteDynamicShortcut("s1");
+ mManager.deleteDynamicShortcut("s3");
+ assertShortcutIds(mManager.getPinnedShortcuts(), "s1", "s2");
+ });
+
+ dumpsysOnLogcat();
+
+ // Get pinned shortcuts from launcher
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s3");
+
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s1", "s2");
+
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+ | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+ "s1", "s2", "s3");
+
+ assertShortcutIds(assertAllDynamicOrPinned(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+ | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+ "s1", "s2");
+ });
+
+ dumpsysOnLogcat();
+
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ // Launcher2 still has no pinned ones.
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
+ /* none */);
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser())))
+ /* none */);
+
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+ | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+ "s1", "s2");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+ | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+ "s2");
+
+ // Now pin some.
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+ Arrays.asList("s1", "s2"), getCallingUser());
+
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2,
+ Arrays.asList("s1", "s2"), getCallingUser());
+
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+ | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+ "s1", "s2");
+
+ // S1 was not visible to it, so shouldn't be pinned.
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+ | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+ "s2");
+ });
+
+ // Re-initialize and load from the files.
+ initService();
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s3");
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s1", "s2");
+ });
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+ | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+ "s1", "s2");
+ assertShortcutIds(assertAllDynamic(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED
+ | ShortcutQuery.FLAG_GET_DYNAMIC), getCallingUser())),
+ "s2");
+ });
+
+ // Delete all dynamic.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ mManager.deleteAllDynamicShortcuts();
+
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ mManager.deleteAllDynamicShortcuts();
+
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2", "s1");
+ });
+
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s3");
+
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s1", "s2");
+
+ // from all packages.
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, null,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s1", "s2", "s3");
+
+ // Update pined. Note s2 and s3 are actually available, but not visible to this
+ // launcher, so still can't be pinned.
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s1", "s2", "s3", "s4"),
+ getCallingUser());
+
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s3");
+ });
+ // Re-publish s1.
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertTrue(mManager.addDynamicShortcut(makeShortcut("s1")));
+
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2", "s3");
+ });
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s3");
+
+ // Now "s1" is visible, so can be pinned.
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList("s1", "s2", "s3", "s4"),
+ getCallingUser());
+
+ assertShortcutIds(assertAllPinned(assertAllNotKeyFieldsOnly(
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()))),
+ "s1", "s3");
+ });
+
+ // Now clear pinned shortcuts. First, from launcher 1.
+ runWithCaller(LAUNCHER_1, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList(), getCallingUser());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList(), getCallingUser());
+
+ assertEquals(0,
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+ assertEquals(0,
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s1", "s2");
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertShortcutIds(assertAllPinned(mManager.getPinnedShortcuts()), "s2");
+ });
+
+ // Clear all pins from launcher 2.
+ runWithCaller(LAUNCHER_2, USER_0, () -> {
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, Arrays.asList(), getCallingUser());
+ mLauncherApps.pinShortcuts(CALLING_PACKAGE_2, Arrays.asList(), getCallingUser());
+
+ assertEquals(0,
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_1,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+ assertEquals(0,
+ mLauncherApps.getShortcuts(buildQuery(/* time =*/ 0, CALLING_PACKAGE_2,
+ /* activity =*/ null, ShortcutQuery.FLAG_GET_PINNED), getCallingUser()).size());
+ });
+ runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+ assertShortcutIds(assertAllDynamic(mManager.getDynamicShortcuts()), "s1");
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
+ runWithCaller(CALLING_PACKAGE_2, USER_0, () -> {
+ assertEquals(0, mManager.getDynamicShortcuts().size());
+ assertEquals(0, mManager.getPinnedShortcuts().size());
+ });
}
public void testCreateShortcutIntent() {
@@ -1880,8 +2139,11 @@
}
public void testLauncherCallback() throws Throwable {
- LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
+ // TODO Add "multi" version -- run the test with two launchers and make sure the callback
+ // argument only contains the ones that are actually visible to each launcher.
+
+ LauncherApps.Callback c0 = mock(LauncherApps.Callback.class);
// Set listeners