summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--api/current.txt168
-rw-r--r--api/system-current.txt168
-rw-r--r--cmds/hid/Android.mk18
-rw-r--r--cmds/hid/MODULE_LICENSE_APACHE20
-rw-r--r--cmds/hid/NOTICE190
-rwxr-xr-xcmds/hid/hid8
-rw-r--r--cmds/hid/jni/Android.mk23
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.cpp253
-rw-r--r--cmds/hid/jni/com_android_commands_hid_Device.h61
-rw-r--r--cmds/hid/src/com/android/commands/hid/Device.java163
-rw-r--r--cmds/hid/src/com/android/commands/hid/Event.java255
-rw-r--r--cmds/hid/src/com/android/commands/hid/Hid.java133
-rw-r--r--cmds/wm/src/com/android/commands/wm/Wm.java31
-rw-r--r--core/java/android/app/Activity.java3
-rw-r--r--core/java/android/app/AssistContent.java219
-rw-r--r--core/java/android/app/AssistStructure.java1075
-rw-r--r--core/java/android/app/VoiceInteractor.java3
-rw-r--r--core/java/android/app/admin/DevicePolicyManager.java7
-rw-r--r--core/java/android/app/assist/AssistContent.java172
-rw-r--r--core/java/android/app/assist/AssistStructure.java1024
-rw-r--r--core/java/android/app/usage/UsageStatsManagerInternal.java11
-rw-r--r--core/java/android/content/AbstractThreadedSyncAdapter.java18
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl2
-rw-r--r--core/java/android/hardware/camera2/CameraCharacteristics.java22
-rw-r--r--core/java/android/hardware/camera2/CameraMetadata.java56
-rw-r--r--core/java/android/hardware/camera2/CaptureRequest.java15
-rw-r--r--core/java/android/hardware/camera2/CaptureResult.java13
-rw-r--r--core/java/android/hardware/camera2/impl/CameraMetadataNative.java12
-rw-r--r--core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java10
-rw-r--r--core/java/android/hardware/camera2/params/StreamConfigurationMap.java432
-rw-r--r--core/java/android/hardware/camera2/params/TonemapCurve.java2
-rw-r--r--core/java/android/hardware/camera2/utils/HashCodeHelpers.java58
-rw-r--r--core/java/android/hardware/camera2/utils/SurfaceUtils.java26
-rw-r--r--core/java/android/net/ConnectivityManager.java22
-rw-r--r--core/java/android/net/NetworkCapabilities.java9
-rw-r--r--core/java/android/os/Debug.java21
-rw-r--r--core/java/android/os/StrictMode.java4
-rw-r--r--core/java/android/provider/Settings.java11
-rw-r--r--core/java/android/service/voice/VoiceInteractionSession.java13
-rw-r--r--core/java/android/text/format/Formatter.java11
-rw-r--r--core/java/android/transition/Visibility.java43
-rw-r--r--core/java/android/util/Range.java2
-rw-r--r--core/java/android/view/MotionEvent.java11
-rw-r--r--core/java/android/view/SurfaceControl.java13
-rw-r--r--core/java/android/view/View.java10
-rw-r--r--core/java/android/view/ViewStructure.java2
-rw-r--r--core/java/android/view/accessibility/AccessibilityEvent.java11
-rw-r--r--core/java/android/view/accessibility/AccessibilityNodeInfo.java4
-rw-r--r--core/java/android/view/accessibility/AccessibilityRecord.java57
-rw-r--r--core/java/android/widget/TextView.java12
-rw-r--r--core/java/com/android/internal/app/ChooserActivity.java15
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java93
-rw-r--r--core/java/com/android/internal/logging/MetricsLogger.java3
-rw-r--r--core/java/com/android/internal/statusbar/IStatusBarService.aidl5
-rw-r--r--core/java/com/android/internal/statusbar/NotificationVisibility.aidl20
-rw-r--r--core/java/com/android/internal/statusbar/NotificationVisibility.java161
-rw-r--r--core/java/com/android/internal/widget/ResolverDrawerLayout.java16
-rw-r--r--core/jni/android_hardware_SensorManager.cpp2
-rw-r--r--core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp20
-rw-r--r--core/jni/android_view_DisplayEventReceiver.cpp2
-rw-r--r--core/jni/android_view_MotionEvent.cpp9
-rw-r--r--core/res/AndroidManifest.xml1
-rw-r--r--core/res/res/xml/sms_short_codes.xml6
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java2
-rw-r--r--keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java16
-rw-r--r--keystore/java/android/security/keystore/KeyGenParameterSpec.java2
-rw-r--r--libs/hwui/LayerRenderer.cpp9
-rw-r--r--libs/hwui/utils/GLUtils.cpp7
-rw-r--r--libs/hwui/utils/GLUtils.h5
-rw-r--r--media/java/android/media/CamcorderProfile.java66
-rw-r--r--media/java/android/media/tv/TvContract.java29
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java2
-rw-r--r--packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/assist/AssistManager.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java80
-rw-r--r--packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java27
-rw-r--r--services/core/java/com/android/server/ConnectivityService.java137
-rw-r--r--services/core/java/com/android/server/EventLogTags.logtags2
-rw-r--r--services/core/java/com/android/server/NetworkManagementService.java143
-rw-r--r--services/core/java/com/android/server/camera/CameraService.java39
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkAgentInfo.java9
-rw-r--r--services/core/java/com/android/server/content/AppIdleMonitor.java51
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java5
-rw-r--r--services/core/java/com/android/server/display/DisplayPowerController.java38
-rw-r--r--services/core/java/com/android/server/job/controllers/AppIdleController.java109
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java48
-rw-r--r--services/core/java/com/android/server/notification/NotificationDelegate.java5
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java19
-rw-r--r--services/core/java/com/android/server/notification/NotificationRecord.java6
-rw-r--r--services/core/java/com/android/server/notification/NotificationUsageStats.java142
-rw-r--r--services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java2
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java52
-rw-r--r--services/core/java/com/android/server/pm/PermissionsState.java16
-rw-r--r--services/core/java/com/android/server/statusbar/StatusBarManagerService.java4
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java21
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java23
-rw-r--r--services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java25
-rw-r--r--services/usage/java/com/android/server/usage/UsageStatsService.java42
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java2
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java41
-rw-r--r--tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java126
-rw-r--r--wifi/java/android/net/wifi/ScanResult.java119
-rw-r--r--wifi/java/android/net/wifi/WifiConfiguration.java20
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java14
-rw-r--r--wifi/java/android/net/wifi/WifiManager.java8
110 files changed, 4547 insertions, 2313 deletions
diff --git a/api/current.txt b/api/current.txt
index 457a9e8..2058ac9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4016,79 +4016,6 @@ package android.app {
field public java.lang.String serviceDetails;
}
- public deprecated class AssistContent {
- ctor public AssistContent();
- method public android.content.ClipData getClipData();
- method public android.os.Bundle getExtras();
- method public java.lang.String getStructuredData();
- method public android.net.Uri getWebUri();
- method public boolean isAppProvidedIntent();
- method public void setClipData(android.content.ClipData);
- method public void setIntent(android.content.Intent);
- method public void setStructuredData(java.lang.String);
- method public void setWebUri(android.net.Uri);
- }
-
- public deprecated class AssistStructure {
- ctor public AssistStructure();
- method public android.content.ComponentName getActivityComponent();
- method public int getWindowNodeCount();
- }
-
- public static class AssistStructure.ViewNode {
- method public android.app.AssistStructure.ViewNode getChildAt(int);
- method public int getChildCount();
- method public java.lang.String getClassName();
- method public java.lang.CharSequence getContentDescription();
- method public android.os.Bundle getExtras();
- method public int getHeight();
- method public java.lang.String getHint();
- method public int getId();
- method public java.lang.String getIdEntry();
- method public java.lang.String getIdPackage();
- method public java.lang.String getIdType();
- method public int getLeft();
- method public int getScrollX();
- method public int getScrollY();
- method public java.lang.CharSequence getText();
- method public int getTextBackgroundColor();
- method public int getTextColor();
- method public int getTextSelectionEnd();
- method public int getTextSelectionStart();
- method public float getTextSize();
- method public int getTextStyle();
- method public int getTop();
- method public int getVisibility();
- method public int getWidth();
- method public boolean isAccessibilityFocused();
- method public boolean isActivated();
- method public boolean isAssistBlocked();
- method public boolean isCheckable();
- method public boolean isChecked();
- method public boolean isClickable();
- method public boolean isContextClickable();
- method public boolean isEnabled();
- method public boolean isFocusable();
- method public boolean isFocused();
- method public boolean isLongClickable();
- method public boolean isSelected();
- field public static final int TEXT_COLOR_UNDEFINED = 1; // 0x1
- field public static final int TEXT_STYLE_BOLD = 1; // 0x1
- field public static final int TEXT_STYLE_ITALIC = 2; // 0x2
- field public static final int TEXT_STYLE_STRIKE_THRU = 8; // 0x8
- field public static final int TEXT_STYLE_UNDERLINE = 4; // 0x4
- }
-
- public static class AssistStructure.WindowNode {
- method public int getDisplayId();
- method public int getHeight();
- method public int getLeft();
- method public android.app.AssistStructure.ViewNode getRootViewNode();
- method public java.lang.CharSequence getTitle();
- method public int getTop();
- method public int getWidth();
- }
-
public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -5900,22 +5827,87 @@ package android.app.admin {
package android.app.assist {
- public final class AssistContent extends android.app.AssistContent implements android.os.Parcelable {
- ctor public AssistContent(android.os.Parcel);
+ public deprecated class AssistContent implements android.os.Parcelable {
+ ctor public AssistContent();
method public int describeContents();
+ method public android.content.ClipData getClipData();
+ method public android.os.Bundle getExtras();
method public android.content.Intent getIntent();
+ method public java.lang.String getStructuredData();
+ method public android.net.Uri getWebUri();
+ method public boolean isAppProvidedIntent();
+ method public void setClipData(android.content.ClipData);
+ method public void setIntent(android.content.Intent);
+ method public void setStructuredData(java.lang.String);
+ method public void setWebUri(android.net.Uri);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.assist.AssistContent> CREATOR;
}
- public final class AssistStructure extends android.app.AssistStructure implements android.os.Parcelable {
+ public class AssistStructure implements android.os.Parcelable {
ctor public AssistStructure();
method public int describeContents();
- method public android.app.AssistStructure.WindowNode getWindowNodeAt(int);
+ method public android.content.ComponentName getActivityComponent();
+ method public android.app.assist.AssistStructure.WindowNode getWindowNodeAt(int);
+ method public int getWindowNodeCount();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.assist.AssistStructure> CREATOR;
}
+ public static class AssistStructure.ViewNode {
+ method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
+ method public int getChildCount();
+ method public java.lang.String getClassName();
+ method public java.lang.CharSequence getContentDescription();
+ method public android.os.Bundle getExtras();
+ method public int getHeight();
+ method public java.lang.String getHint();
+ method public int getId();
+ method public java.lang.String getIdEntry();
+ method public java.lang.String getIdPackage();
+ method public java.lang.String getIdType();
+ method public int getLeft();
+ method public int getScrollX();
+ method public int getScrollY();
+ method public java.lang.CharSequence getText();
+ method public int getTextBackgroundColor();
+ method public int getTextColor();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public float getTextSize();
+ method public int getTextStyle();
+ method public int getTop();
+ method public int getVisibility();
+ method public int getWidth();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActivated();
+ method public boolean isAssistBlocked();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isContextClickable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isLongClickable();
+ method public boolean isSelected();
+ field public static final int TEXT_COLOR_UNDEFINED = 1; // 0x1
+ field public static final int TEXT_STYLE_BOLD = 1; // 0x1
+ field public static final int TEXT_STYLE_ITALIC = 2; // 0x2
+ field public static final int TEXT_STYLE_STRIKE_THRU = 8; // 0x8
+ field public static final int TEXT_STYLE_UNDERLINE = 4; // 0x4
+ }
+
+ public static class AssistStructure.WindowNode {
+ method public int getDisplayId();
+ method public int getHeight();
+ method public int getLeft();
+ method public android.app.assist.AssistStructure.ViewNode getRootViewNode();
+ method public java.lang.CharSequence getTitle();
+ method public int getTop();
+ method public int getWidth();
+ }
+
}
package android.app.backup {
@@ -7211,6 +7203,7 @@ package android.content {
method public android.content.Context getContext();
method public final android.os.IBinder getSyncAdapterBinder();
method public abstract void onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult);
+ method public void onSecurityException(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.SyncResult);
method public void onSyncCanceled();
method public void onSyncCanceled(java.lang.Thread);
field public static final deprecated int LOG_SYNC_DETAILS = 2743; // 0xab7
@@ -13505,7 +13498,6 @@ package android.hardware.camera2 {
field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
- field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION = 3; // 0x3
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
field public static final int LENS_FACING_BACK = 1; // 0x1
@@ -13858,6 +13850,7 @@ package android.hardware.camera2.params {
}
public final class StreamConfigurationMap {
+ method public android.util.Size[] getHighResolutionOutputSizes(int);
method public android.util.Range<java.lang.Integer>[] getHighSpeedVideoFpsRanges();
method public android.util.Range<java.lang.Integer>[] getHighSpeedVideoFpsRangesFor(android.util.Size);
method public android.util.Size[] getHighSpeedVideoSizes();
@@ -18207,7 +18200,6 @@ package android.net {
method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
method public void onLosing(android.net.Network, int);
method public void onLost(android.net.Network);
- method public void onPreCheck(android.net.Network);
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -18358,6 +18350,7 @@ package android.net {
method public boolean hasTransport(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
+ field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
field public static final int NET_CAPABILITY_CBS = 5; // 0x5
field public static final int NET_CAPABILITY_DUN = 2; // 0x2
field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
@@ -18372,6 +18365,7 @@ package android.net {
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
+ field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
@@ -19085,6 +19079,8 @@ package android.net.wifi {
public class ScanResult implements android.os.Parcelable {
method public int describeContents();
+ method public boolean is80211mcResponder();
+ method public boolean isPasspointNetwork();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
@@ -19092,18 +19088,19 @@ package android.net.wifi {
field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
+ field public static final long FLAG_80211mc_RESPONDER = 2L; // 0x2L
+ field public static final long FLAG_PASSPOINT_NETWORK = 1L; // 0x1L
field public java.lang.String SSID;
field public java.lang.String capabilities;
field public int centerFreq0;
field public int centerFreq1;
field public int channelWidth;
+ field public long flags;
field public int frequency;
- field public boolean is80211McRTTResponder;
field public int level;
- field public java.lang.String operatorFriendlyName;
- field public boolean passpointNetwork;
+ field public java.lang.CharSequence operatorFriendlyName;
field public long timestamp;
- field public java.lang.String venueName;
+ field public java.lang.CharSequence venueName;
}
public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -19146,7 +19143,7 @@ package android.net.wifi {
field public java.lang.String preSharedKey;
field public int priority;
field public java.lang.String providerFriendlyName;
- field public java.util.HashSet<java.lang.Long> roamingConsortiumIds;
+ field public java.lang.Long[] roamingConsortiumIds;
field public int status;
field public java.lang.String[] wepKeys;
field public int wepTxKeyIndex;
@@ -19208,7 +19205,7 @@ package android.net.wifi {
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate getClientCertificate();
- method public java.lang.String getDomainSubjectMatch();
+ method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
method public java.lang.String getIdentity();
method public java.lang.String getPassword();
@@ -26582,6 +26579,7 @@ package android.provider {
field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
field public static final java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+ field public static final java.lang.String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN = "wifi_device_owner_configs_lockdown";
field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
diff --git a/api/system-current.txt b/api/system-current.txt
index 08715cd..df18ce4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4112,79 +4112,6 @@ package android.app {
field public java.lang.String serviceDetails;
}
- public deprecated class AssistContent {
- ctor public AssistContent();
- method public android.content.ClipData getClipData();
- method public android.os.Bundle getExtras();
- method public java.lang.String getStructuredData();
- method public android.net.Uri getWebUri();
- method public boolean isAppProvidedIntent();
- method public void setClipData(android.content.ClipData);
- method public void setIntent(android.content.Intent);
- method public void setStructuredData(java.lang.String);
- method public void setWebUri(android.net.Uri);
- }
-
- public deprecated class AssistStructure {
- ctor public AssistStructure();
- method public android.content.ComponentName getActivityComponent();
- method public int getWindowNodeCount();
- }
-
- public static class AssistStructure.ViewNode {
- method public android.app.AssistStructure.ViewNode getChildAt(int);
- method public int getChildCount();
- method public java.lang.String getClassName();
- method public java.lang.CharSequence getContentDescription();
- method public android.os.Bundle getExtras();
- method public int getHeight();
- method public java.lang.String getHint();
- method public int getId();
- method public java.lang.String getIdEntry();
- method public java.lang.String getIdPackage();
- method public java.lang.String getIdType();
- method public int getLeft();
- method public int getScrollX();
- method public int getScrollY();
- method public java.lang.CharSequence getText();
- method public int getTextBackgroundColor();
- method public int getTextColor();
- method public int getTextSelectionEnd();
- method public int getTextSelectionStart();
- method public float getTextSize();
- method public int getTextStyle();
- method public int getTop();
- method public int getVisibility();
- method public int getWidth();
- method public boolean isAccessibilityFocused();
- method public boolean isActivated();
- method public boolean isAssistBlocked();
- method public boolean isCheckable();
- method public boolean isChecked();
- method public boolean isClickable();
- method public boolean isContextClickable();
- method public boolean isEnabled();
- method public boolean isFocusable();
- method public boolean isFocused();
- method public boolean isLongClickable();
- method public boolean isSelected();
- field public static final int TEXT_COLOR_UNDEFINED = 1; // 0x1
- field public static final int TEXT_STYLE_BOLD = 1; // 0x1
- field public static final int TEXT_STYLE_ITALIC = 2; // 0x2
- field public static final int TEXT_STYLE_STRIKE_THRU = 8; // 0x8
- field public static final int TEXT_STYLE_UNDERLINE = 4; // 0x4
- }
-
- public static class AssistStructure.WindowNode {
- method public int getDisplayId();
- method public int getHeight();
- method public int getLeft();
- method public android.app.AssistStructure.ViewNode getRootViewNode();
- method public java.lang.CharSequence getTitle();
- method public int getTop();
- method public int getWidth();
- }
-
public class BroadcastOptions {
method public static android.app.BroadcastOptions makeBasic();
method public void setTemporaryAppWhitelistDuration(long);
@@ -6018,22 +5945,87 @@ package android.app.admin {
package android.app.assist {
- public final class AssistContent extends android.app.AssistContent implements android.os.Parcelable {
- ctor public AssistContent(android.os.Parcel);
+ public deprecated class AssistContent implements android.os.Parcelable {
+ ctor public AssistContent();
method public int describeContents();
+ method public android.content.ClipData getClipData();
+ method public android.os.Bundle getExtras();
method public android.content.Intent getIntent();
+ method public java.lang.String getStructuredData();
+ method public android.net.Uri getWebUri();
+ method public boolean isAppProvidedIntent();
+ method public void setClipData(android.content.ClipData);
+ method public void setIntent(android.content.Intent);
+ method public void setStructuredData(java.lang.String);
+ method public void setWebUri(android.net.Uri);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.assist.AssistContent> CREATOR;
}
- public final class AssistStructure extends android.app.AssistStructure implements android.os.Parcelable {
+ public class AssistStructure implements android.os.Parcelable {
ctor public AssistStructure();
method public int describeContents();
- method public android.app.AssistStructure.WindowNode getWindowNodeAt(int);
+ method public android.content.ComponentName getActivityComponent();
+ method public android.app.assist.AssistStructure.WindowNode getWindowNodeAt(int);
+ method public int getWindowNodeCount();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.app.assist.AssistStructure> CREATOR;
}
+ public static class AssistStructure.ViewNode {
+ method public android.app.assist.AssistStructure.ViewNode getChildAt(int);
+ method public int getChildCount();
+ method public java.lang.String getClassName();
+ method public java.lang.CharSequence getContentDescription();
+ method public android.os.Bundle getExtras();
+ method public int getHeight();
+ method public java.lang.String getHint();
+ method public int getId();
+ method public java.lang.String getIdEntry();
+ method public java.lang.String getIdPackage();
+ method public java.lang.String getIdType();
+ method public int getLeft();
+ method public int getScrollX();
+ method public int getScrollY();
+ method public java.lang.CharSequence getText();
+ method public int getTextBackgroundColor();
+ method public int getTextColor();
+ method public int getTextSelectionEnd();
+ method public int getTextSelectionStart();
+ method public float getTextSize();
+ method public int getTextStyle();
+ method public int getTop();
+ method public int getVisibility();
+ method public int getWidth();
+ method public boolean isAccessibilityFocused();
+ method public boolean isActivated();
+ method public boolean isAssistBlocked();
+ method public boolean isCheckable();
+ method public boolean isChecked();
+ method public boolean isClickable();
+ method public boolean isContextClickable();
+ method public boolean isEnabled();
+ method public boolean isFocusable();
+ method public boolean isFocused();
+ method public boolean isLongClickable();
+ method public boolean isSelected();
+ field public static final int TEXT_COLOR_UNDEFINED = 1; // 0x1
+ field public static final int TEXT_STYLE_BOLD = 1; // 0x1
+ field public static final int TEXT_STYLE_ITALIC = 2; // 0x2
+ field public static final int TEXT_STYLE_STRIKE_THRU = 8; // 0x8
+ field public static final int TEXT_STYLE_UNDERLINE = 4; // 0x4
+ }
+
+ public static class AssistStructure.WindowNode {
+ method public int getDisplayId();
+ method public int getHeight();
+ method public int getLeft();
+ method public android.app.assist.AssistStructure.ViewNode getRootViewNode();
+ method public java.lang.CharSequence getTitle();
+ method public int getTop();
+ method public int getWidth();
+ }
+
}
package android.app.backup {
@@ -7436,6 +7428,7 @@ package android.content {
method public android.content.Context getContext();
method public final android.os.IBinder getSyncAdapterBinder();
method public abstract void onPerformSync(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.ContentProviderClient, android.content.SyncResult);
+ method public void onSecurityException(android.accounts.Account, android.os.Bundle, java.lang.String, android.content.SyncResult);
method public void onSyncCanceled();
method public void onSyncCanceled(java.lang.Thread);
field public static final deprecated int LOG_SYNC_DETAILS = 2743; // 0xab7
@@ -13836,7 +13829,6 @@ package android.hardware.camera2 {
field public static final int HOT_PIXEL_MODE_HIGH_QUALITY = 2; // 0x2
field public static final int HOT_PIXEL_MODE_OFF = 0; // 0x0
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_FULL = 1; // 0x1
- field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION = 3; // 0x3
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2; // 0x2
field public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED = 0; // 0x0
field public static final int LENS_FACING_BACK = 1; // 0x1
@@ -14189,6 +14181,7 @@ package android.hardware.camera2.params {
}
public final class StreamConfigurationMap {
+ method public android.util.Size[] getHighResolutionOutputSizes(int);
method public android.util.Range<java.lang.Integer>[] getHighSpeedVideoFpsRanges();
method public android.util.Range<java.lang.Integer>[] getHighSpeedVideoFpsRangesFor(android.util.Size);
method public android.util.Size[] getHighSpeedVideoSizes();
@@ -19708,7 +19701,6 @@ package android.net {
method public void onLinkPropertiesChanged(android.net.Network, android.net.LinkProperties);
method public void onLosing(android.net.Network, int);
method public void onLost(android.net.Network);
- method public void onPreCheck(android.net.Network);
}
public static abstract interface ConnectivityManager.OnNetworkActiveListener {
@@ -19859,6 +19851,7 @@ package android.net {
method public boolean hasTransport(int);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.NetworkCapabilities> CREATOR;
+ field public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17; // 0x11
field public static final int NET_CAPABILITY_CBS = 5; // 0x5
field public static final int NET_CAPABILITY_DUN = 2; // 0x2
field public static final int NET_CAPABILITY_EIMS = 10; // 0xa
@@ -19873,6 +19866,7 @@ package android.net {
field public static final int NET_CAPABILITY_RCS = 8; // 0x8
field public static final int NET_CAPABILITY_SUPL = 1; // 0x1
field public static final int NET_CAPABILITY_TRUSTED = 14; // 0xe
+ field public static final int NET_CAPABILITY_VALIDATED = 16; // 0x10
field public static final int NET_CAPABILITY_WIFI_P2P = 6; // 0x6
field public static final int NET_CAPABILITY_XCAP = 9; // 0x9
field public static final int TRANSPORT_BLUETOOTH = 2; // 0x2
@@ -20827,6 +20821,8 @@ package android.net.wifi {
public class ScanResult implements android.os.Parcelable {
method public int describeContents();
+ method public boolean is80211mcResponder();
+ method public boolean isPasspointNetwork();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
@@ -20834,18 +20830,19 @@ package android.net.wifi {
field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
+ field public static final long FLAG_80211mc_RESPONDER = 2L; // 0x2L
+ field public static final long FLAG_PASSPOINT_NETWORK = 1L; // 0x1L
field public java.lang.String SSID;
field public java.lang.String capabilities;
field public int centerFreq0;
field public int centerFreq1;
field public int channelWidth;
+ field public long flags;
field public int frequency;
- field public boolean is80211McRTTResponder;
field public int level;
- field public java.lang.String operatorFriendlyName;
- field public boolean passpointNetwork;
+ field public java.lang.CharSequence operatorFriendlyName;
field public long timestamp;
- field public java.lang.String venueName;
+ field public java.lang.CharSequence venueName;
}
public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -20895,7 +20892,7 @@ package android.net.wifi {
field public java.lang.String preSharedKey;
field public int priority;
field public java.lang.String providerFriendlyName;
- field public java.util.HashSet<java.lang.Long> roamingConsortiumIds;
+ field public java.lang.Long[] roamingConsortiumIds;
field public int status;
field public java.lang.String[] wepKeys;
field public int wepTxKeyIndex;
@@ -20972,7 +20969,7 @@ package android.net.wifi {
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate getClientCertificate();
- method public java.lang.String getDomainSubjectMatch();
+ method public java.lang.String getDomainSuffixMatch();
method public int getEapMethod();
method public java.lang.String getIdentity();
method public java.lang.String getPassword();
@@ -28630,6 +28627,7 @@ package android.provider {
field public static final java.lang.String USB_MASS_STORAGE_ENABLED = "usb_mass_storage_enabled";
field public static final java.lang.String USE_GOOGLE_MAIL = "use_google_mail";
field public static final java.lang.String WAIT_FOR_DEBUGGER = "wait_for_debugger";
+ field public static final java.lang.String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN = "wifi_device_owner_configs_lockdown";
field public static final java.lang.String WIFI_MAX_DHCP_RETRY_COUNT = "wifi_max_dhcp_retry_count";
field public static final java.lang.String WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS = "wifi_mobile_data_transition_wakelock_timeout_ms";
field public static final java.lang.String WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON = "wifi_networks_available_notification_on";
diff --git a/cmds/hid/Android.mk b/cmds/hid/Android.mk
new file mode 100644
index 0000000..ff3691d
--- /dev/null
+++ b/cmds/hid/Android.mk
@@ -0,0 +1,18 @@
+# Copyright 2015 The Android Open Source Project
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_MODULE := hid
+LOCAL_JNI_SHARED_LIBRARIES := libhidcommand_jni
+include $(BUILD_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := hid
+LOCAL_SRC_FILES := hid
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := EXECUTABLES
+include $(BUILD_PREBUILT)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/cmds/hid/MODULE_LICENSE_APACHE2 b/cmds/hid/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/hid/MODULE_LICENSE_APACHE2
diff --git a/cmds/hid/NOTICE b/cmds/hid/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/hid/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/hid/hid b/cmds/hid/hid
new file mode 100755
index 0000000..2359fcd
--- /dev/null
+++ b/cmds/hid/hid
@@ -0,0 +1,8 @@
+#!/system/bin/sh
+#
+# Script to start "hid" on the device, which has a very rudimentary
+# shell.
+#
+base=/system
+export CLASSPATH=$base/framework/hid.jar
+exec app_process $base/bin com.android.commands.hid.Hid "$@"
diff --git a/cmds/hid/jni/Android.mk b/cmds/hid/jni/Android.mk
new file mode 100644
index 0000000..8163a9d
--- /dev/null
+++ b/cmds/hid/jni/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ com_android_commands_hid_Device.cpp
+
+LOCAL_C_INCLUDES := \
+ $(JNI_H_INCLUDE) \
+ frameworks/base/core/jni
+
+LOCAL_SHARED_LIBRARIES := \
+ libandroid_runtime \
+ liblog \
+ libnativehelper \
+ libutils
+
+LOCAL_MODULE := libhidcommand_jni
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_CFLAGS += -Wall
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.cpp b/cmds/hid/jni/com_android_commands_hid_Device.cpp
new file mode 100644
index 0000000..4278e7d
--- /dev/null
+++ b/cmds/hid/jni/com_android_commands_hid_Device.cpp
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "HidCommandDevice"
+
+#include "com_android_commands_hid_Device.h"
+
+#include <linux/uhid.h>
+
+#include <fcntl.h>
+#include <cstdio>
+#include <cstring>
+#include <memory>
+#include <unistd.h>
+
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <android_os_MessageQueue.h>
+#include <core_jni_helpers.h>
+#include <jni.h>
+#include <JNIHelp.h>
+#include <ScopedPrimitiveArray.h>
+#include <ScopedUtfChars.h>
+#include <utils/Log.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace uhid {
+
+static const char* UHID_PATH = "/dev/uhid";
+static const size_t UHID_MAX_NAME_LENGTH = 128;
+
+static struct {
+ jmethodID onDeviceOpen;
+ jmethodID onDeviceError;
+} gDeviceCallbackClassInfo;
+
+static int handleLooperEvents(int fd, int events, void* data) {
+ Device* d = reinterpret_cast<Device*>(data);
+ return d->handleEvents(events);
+}
+
+static void checkAndClearException(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ ALOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+}
+
+DeviceCallback::DeviceCallback(JNIEnv* env, jobject callback) :
+ mCallbackObject(env->NewGlobalRef(callback)) { }
+
+DeviceCallback::~DeviceCallback() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->DeleteGlobalRef(mCallbackObject);
+}
+
+void DeviceCallback::onDeviceError() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceError);
+ checkAndClearException(env, "onDeviceError");
+}
+
+void DeviceCallback::onDeviceOpen() {
+ JNIEnv* env = AndroidRuntime::getJNIEnv();
+ env->CallVoidMethod(mCallbackObject, gDeviceCallbackClassInfo.onDeviceOpen);
+ checkAndClearException(env, "onDeviceOpen");
+}
+
+Device* Device::open(int32_t id, const char* name, int32_t vid, int32_t pid,
+ std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
+ std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) {
+
+ int fd = ::open(UHID_PATH, O_RDWR | O_CLOEXEC);
+ if (fd < 0) {
+ ALOGE("Failed to open uhid: %s", strerror(errno));
+ return nullptr;
+ }
+
+ struct uhid_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_CREATE;
+ strncpy((char*)ev.u.create.name, name, UHID_MAX_NAME_LENGTH);
+ ev.u.create.rd_data = descriptor.get();
+ ev.u.create.rd_size = descriptorSize;
+ ev.u.create.bus = BUS_BLUETOOTH;
+ ev.u.create.vendor = vid;
+ ev.u.create.product = pid;
+ ev.u.create.version = 0;
+ ev.u.create.country = 0;
+
+ errno = 0;
+ ssize_t ret = TEMP_FAILURE_RETRY(::write(fd, &ev, sizeof(ev)));
+ if (ret < 0 || ret != sizeof(ev)) {
+ ::close(fd);
+ ALOGE("Failed to create uhid node: %s", strerror(errno));
+ return nullptr;
+ }
+
+ // Wait for the device to actually be created.
+ ret = TEMP_FAILURE_RETRY(::read(fd, &ev, sizeof(ev)));
+ if (ret < 0 || ev.type != UHID_START) {
+ ::close(fd);
+ ALOGE("uhid node failed to start: %s", strerror(errno));
+ return nullptr;
+ }
+
+ return new Device(id, fd, std::move(callback), looper);
+}
+
+Device::Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback, sp<Looper> looper) :
+ mId(id), mFd(fd), mDeviceCallback(std::move(callback)), mLooper(looper) {
+ looper->addFd(fd, 0, Looper::EVENT_INPUT, handleLooperEvents, reinterpret_cast<void*>(this));
+}
+
+Device::~Device() {
+ mLooper->removeFd(mFd);
+ struct uhid_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_DESTROY;
+ TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
+ ::close(mFd);
+ mFd = -1;
+}
+
+void Device::sendReport(uint8_t* report, size_t reportSize) {
+ struct uhid_event ev;
+ memset(&ev, 0, sizeof(ev));
+ ev.type = UHID_INPUT;
+ ev.u.input.size = reportSize;
+ memcpy(&ev.u.input.data, report, reportSize);
+ ssize_t ret = TEMP_FAILURE_RETRY(::write(mFd, &ev, sizeof(ev)));
+ if (ret < 0 || ret != sizeof(ev)) {
+ ALOGE("Failed to send hid event: %s", strerror(errno));
+ }
+}
+
+int Device::handleEvents(int events) {
+ if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) {
+ ALOGE("uhid node was closed or an error occurred. events=0x%x", events);
+ mDeviceCallback->onDeviceError();
+ return 0;
+ }
+ struct uhid_event ev;
+ ssize_t ret = TEMP_FAILURE_RETRY(::read(mFd, &ev, sizeof(ev)));
+ if (ret < 0) {
+ ALOGE("Failed to read from uhid node: %s", strerror(errno));
+ mDeviceCallback->onDeviceError();
+ return 0;
+ }
+
+ if (ev.type == UHID_OPEN) {
+ mDeviceCallback->onDeviceOpen();
+ }
+
+ return 1;
+}
+
+} // namespace uhid
+
+std::unique_ptr<uint8_t[]> getData(JNIEnv* env, jbyteArray javaArray, size_t& outSize) {
+ ScopedByteArrayRO scopedArray(env, javaArray);
+ outSize = scopedArray.size();
+ std::unique_ptr<uint8_t[]> data(new uint8_t[outSize]);
+ for (size_t i = 0; i < outSize; i++) {
+ data[i] = static_cast<uint8_t>(scopedArray[i]);
+ }
+ return data;
+}
+
+static jlong openDevice(JNIEnv* env, jclass clazz, jstring rawName, jint id, jint vid, jint pid,
+ jbyteArray rawDescriptor, jobject queue, jobject callback) {
+ ScopedUtfChars name(env, rawName);
+ if (name.c_str() == nullptr) {
+ return 0;
+ }
+
+ size_t size;
+ std::unique_ptr<uint8_t[]> desc = getData(env, rawDescriptor, size);
+
+ std::unique_ptr<uhid::DeviceCallback> cb(new uhid::DeviceCallback(env, callback));
+ sp<Looper> looper = android_os_MessageQueue_getMessageQueue(env, queue)->getLooper();
+
+ uhid::Device* d = uhid::Device::open(
+ id, reinterpret_cast<const char*>(name.c_str()), vid, pid,
+ std::move(desc), size, std::move(cb), std::move(looper));
+ return reinterpret_cast<jlong>(d);
+}
+
+static void sendReport(JNIEnv* env, jclass clazz, jlong ptr,jbyteArray rawReport) {
+ size_t size;
+ std::unique_ptr<uint8_t[]> report = getData(env, rawReport, size);
+ uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
+ if (d) {
+ d->sendReport(report.get(), size);
+ }
+}
+
+static void closeDevice(JNIEnv* env, jclass clazz, jlong ptr) {
+ uhid::Device* d = reinterpret_cast<uhid::Device*>(ptr);
+ if (d) {
+ delete d;
+ }
+}
+
+static JNINativeMethod sMethods[] = {
+ { "nativeOpenDevice",
+ "(Ljava/lang/String;III[BLandroid/os/MessageQueue;"
+ "Lcom/android/commands/hid/Device$DeviceCallback;)J",
+ reinterpret_cast<void*>(openDevice) },
+ { "nativeSendReport", "(J[B)V", reinterpret_cast<void*>(sendReport) },
+ { "nativeCloseDevice", "(J)V", reinterpret_cast<void*>(closeDevice) },
+};
+
+int register_com_android_commands_hid_Device(JNIEnv* env) {
+ jclass clazz = FindClassOrDie(env, "com/android/commands/hid/Device$DeviceCallback");
+ uhid::gDeviceCallbackClassInfo.onDeviceOpen =
+ GetMethodIDOrDie(env, clazz, "onDeviceOpen", "()V");
+ uhid::gDeviceCallbackClassInfo.onDeviceError=
+ GetMethodIDOrDie(env, clazz, "onDeviceError", "()V");
+ return jniRegisterNativeMethods(env, "com/android/commands/hid/Device",
+ sMethods, NELEM(sMethods));
+}
+
+} // namespace android
+
+jint JNI_OnLoad(JavaVM* jvm, void*) {
+ JNIEnv *env = NULL;
+ if (jvm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6)) {
+ return JNI_ERR;
+ }
+
+ if (android::register_com_android_commands_hid_Device(env) < 0 ){
+ return JNI_ERR;
+ }
+
+ return JNI_VERSION_1_6;
+}
diff --git a/cmds/hid/jni/com_android_commands_hid_Device.h b/cmds/hid/jni/com_android_commands_hid_Device.h
new file mode 100644
index 0000000..6c5899e
--- /dev/null
+++ b/cmds/hid/jni/com_android_commands_hid_Device.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <memory>
+
+#include <jni.h>
+#include <utils/Looper.h>
+#include <utils/StrongPointer.h>
+
+namespace android {
+namespace uhid {
+
+class DeviceCallback {
+public:
+ DeviceCallback(JNIEnv* env, jobject callback);
+ ~DeviceCallback();
+
+ void onDeviceOpen();
+ void onDeviceError();
+
+private:
+ jobject mCallbackObject;
+};
+
+class Device {
+public:
+ static Device* open(int32_t id, const char* name, int32_t vid, int32_t pid,
+ std::unique_ptr<uint8_t[]> descriptor, size_t descriptorSize,
+ std::unique_ptr<DeviceCallback> callback, sp<Looper> looper);
+
+ Device(int32_t id, int fd, std::unique_ptr<DeviceCallback> callback, sp<Looper> looper);
+ ~Device();
+
+ void sendReport(uint8_t* report, size_t reportSize);
+ void close();
+
+ int handleEvents(int events);
+
+private:
+ int32_t mId;
+ int mFd;
+ std::unique_ptr<DeviceCallback> mDeviceCallback;
+ sp<Looper> mLooper;
+};
+
+
+} // namespace uhid
+} // namespace android
diff --git a/cmds/hid/src/com/android/commands/hid/Device.java b/cmds/hid/src/com/android/commands/hid/Device.java
new file mode 100644
index 0000000..dbe883b
--- /dev/null
+++ b/cmds/hid/src/com/android/commands/hid/Device.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.hid;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.SystemClock;
+import android.util.Log;
+
+import com.android.internal.os.SomeArgs;
+
+public class Device {
+ private static final String TAG = "HidDevice";
+
+ // Minimum amount of time to wait before sending input events to a device. Even though we're
+ // guaranteed that the device has been created and opened by the input system, there's still a
+ // window in which the system hasn't started reading events out of it. If a stream of events
+ // begins in during this window (like a button down event) and *then* we start reading, we're
+ // liable to ignore the whole stream.
+ private static final int MIN_WAIT_FOR_FIRST_EVENT = 150;
+
+ private static final int MSG_OPEN_DEVICE = 1;
+ private static final int MSG_SEND_REPORT = 2;
+ private static final int MSG_CLOSE_DEVICE = 3;
+
+
+ private final int mId;
+ private final HandlerThread mThread;
+ private final DeviceHandler mHandler;
+ private long mEventTime;
+
+ private final Object mCond = new Object();
+
+ static {
+ System.loadLibrary("hidcommand_jni");
+ }
+
+ private static native long nativeOpenDevice(String name, int id, int vid, int pid,
+ byte[] descriptor, MessageQueue queue, DeviceCallback callback);
+ private static native void nativeSendReport(long ptr, byte[] data);
+ private static native void nativeCloseDevice(long ptr);
+
+ public Device(int id, String name, int vid, int pid, byte[] descriptor, byte[] report) {
+ mId = id;
+ mThread = new HandlerThread("HidDeviceHandler");
+ mThread.start();
+ mHandler = new DeviceHandler(mThread.getLooper());
+ SomeArgs args = SomeArgs.obtain();
+ args.argi1 = id;
+ args.argi2 = vid;
+ args.argi3 = pid;
+ if (name != null) {
+ args.arg1 = name;
+ } else {
+ args.arg1 = id + ":" + vid + ":" + pid;
+ }
+ args.arg2 = descriptor;
+ args.arg3 = report;
+ mHandler.obtainMessage(MSG_OPEN_DEVICE, args).sendToTarget();
+ mEventTime = SystemClock.uptimeMillis() + MIN_WAIT_FOR_FIRST_EVENT;
+ }
+
+ public void sendReport(byte[] report) {
+ Message msg = mHandler.obtainMessage(MSG_SEND_REPORT, report);
+ mHandler.sendMessageAtTime(msg, mEventTime);
+ }
+
+ public void addDelay(int delay) {
+ mEventTime += delay;
+ }
+
+ public void close() {
+ Message msg = mHandler.obtainMessage(MSG_CLOSE_DEVICE);
+ msg.setAsynchronous(true);
+ mHandler.sendMessageAtTime(msg, mEventTime + 1);
+ try {
+ synchronized (mCond) {
+ mCond.wait();
+ }
+ } catch (InterruptedException ignore) {}
+ }
+
+ private class DeviceHandler extends Handler {
+ private long mPtr;
+ private int mBarrierToken;
+
+ public DeviceHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_OPEN_DEVICE:
+ SomeArgs args = (SomeArgs) msg.obj;
+ mPtr = nativeOpenDevice((String) args.arg1, args.argi1, args.argi2, args.argi3,
+ (byte[]) args.arg2, getLooper().myQueue(), new DeviceCallback());
+ nativeSendReport(mPtr, (byte[]) args.arg3);
+ pauseEvents();
+ break;
+ case MSG_SEND_REPORT:
+ if (mPtr != 0) {
+ nativeSendReport(mPtr, (byte[]) msg.obj);
+ } else {
+ Log.e(TAG, "Tried to send report to closed device.");
+ }
+ break;
+ case MSG_CLOSE_DEVICE:
+ if (mPtr != 0) {
+ nativeCloseDevice(mPtr);
+ getLooper().quitSafely();
+ mPtr = 0;
+ } else {
+ Log.e(TAG, "Tried to close already closed device.");
+ }
+ synchronized (mCond) {
+ mCond.notify();
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown device message");
+ }
+ }
+
+ public void pauseEvents() {
+ mBarrierToken = getLooper().myQueue().postSyncBarrier();
+ }
+
+ public void resumeEvents() {
+ getLooper().myQueue().removeSyncBarrier(mBarrierToken);
+ mBarrierToken = 0;
+ }
+ }
+
+ private class DeviceCallback {
+ public void onDeviceOpen() {
+ mHandler.resumeEvents();
+ }
+
+ public void onDeviceError() {
+ Message msg = mHandler.obtainMessage(MSG_CLOSE_DEVICE);
+ msg.setAsynchronous(true);
+ msg.sendToTarget();
+ }
+ }
+}
diff --git a/cmds/hid/src/com/android/commands/hid/Event.java b/cmds/hid/src/com/android/commands/hid/Event.java
new file mode 100644
index 0000000..c6a37bd
--- /dev/null
+++ b/cmds/hid/src/com/android/commands/hid/Event.java
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.hid;
+
+import android.util.JsonReader;
+import android.util.JsonToken;
+import android.util.Log;
+
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+public class Event {
+ private static final String TAG = "HidEvent";
+
+ public static final String COMMAND_REGISTER = "register";
+ public static final String COMMAND_DELAY = "delay";
+ public static final String COMMAND_REPORT = "report";
+
+ private int mId;
+ private String mCommand;
+ private String mName;
+ private byte[] mDescriptor;
+ private int mVid;
+ private int mPid;
+ private byte[] mReport;
+ private int mDuration;
+
+ public int getId() {
+ return mId;
+ }
+
+ public String getCommand() {
+ return mCommand;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public byte[] getDescriptor() {
+ return mDescriptor;
+ }
+
+ public int getVendorId() {
+ return mVid;
+ }
+
+ public int getProductId() {
+ return mPid;
+ }
+
+ public byte[] getReport() {
+ return mReport;
+ }
+
+ public int getDuration() {
+ return mDuration;
+ }
+
+ public String toString() {
+ return "Event{id=" + mId
+ + ", command=" + String.valueOf(mCommand)
+ + ", name=" + String.valueOf(mName)
+ + ", descriptor=" + Arrays.toString(mDescriptor)
+ + ", vid=" + mVid
+ + ", pid=" + mPid
+ + ", report=" + Arrays.toString(mReport)
+ + ", duration=" + mDuration
+ + "}";
+ }
+
+ private static class Builder {
+ private Event mEvent;
+
+ public Builder() {
+ mEvent = new Event();
+ }
+
+ public void setId(int id) {
+ mEvent.mId = id;
+ }
+
+ private void setCommand(String command) {
+ mEvent.mCommand = command;
+ }
+
+ public void setName(String name) {
+ mEvent.mName = name;
+ }
+
+ public void setDescriptor(byte[] descriptor) {
+ mEvent.mDescriptor = descriptor;
+ }
+
+ public void setReport(byte[] report) {
+ mEvent.mReport = report;
+ }
+
+ public void setVid(int vid) {
+ mEvent.mVid = vid;
+ }
+
+ public void setPid(int pid) {
+ mEvent.mPid = pid;
+ }
+
+ public void setDuration(int duration) {
+ mEvent.mDuration = duration;
+ }
+
+ public Event build() {
+ if (mEvent.mId == -1) {
+ throw new IllegalStateException("No event id");
+ } else if (mEvent.mCommand == null) {
+ throw new IllegalStateException("Event does not contain a command");
+ }
+ if (COMMAND_REGISTER.equals(mEvent.mCommand)) {
+ if (mEvent.mDescriptor == null) {
+ throw new IllegalStateException("Device registration is missing descriptor");
+ }
+ } else if (COMMAND_DELAY.equals(mEvent.mCommand)) {
+ if (mEvent.mDuration <= 0) {
+ throw new IllegalStateException("Delay has missing or invalid duration");
+ }
+ } else if (COMMAND_REPORT.equals(mEvent.mCommand)) {
+ if (mEvent.mReport == null) {
+ throw new IllegalStateException("Report command is missing report data");
+ }
+ }
+ return mEvent;
+ }
+ }
+
+ public static class Reader {
+ private JsonReader mReader;
+
+ public Reader(InputStreamReader in) {
+ mReader = new JsonReader(in);
+ mReader.setLenient(true);
+ }
+
+ public Event getNextEvent() throws IOException {
+ Event e = null;
+ while (e == null && mReader.peek() != JsonToken.END_DOCUMENT) {
+ Event.Builder eb = new Event.Builder();
+ try {
+ mReader.beginObject();
+ while (mReader.hasNext()) {
+ String name = mReader.nextName();
+ switch (name) {
+ case "id":
+ eb.setId(readInt());
+ break;
+ case "command":
+ eb.setCommand(mReader.nextString());
+ break;
+ case "descriptor":
+ eb.setDescriptor(readData());
+ break;
+ case "name":
+ eb.setName(mReader.nextString());
+ break;
+ case "vid":
+ eb.setVid(readInt());
+ break;
+ case "pid":
+ eb.setPid(readInt());
+ break;
+ case "report":
+ eb.setReport(readData());
+ break;
+ case "duration":
+ eb.setDuration(readInt());
+ break;
+ default:
+ mReader.skipValue();
+ }
+ }
+ mReader.endObject();
+ } catch (IllegalStateException ex) {
+ error("Error reading in object, ignoring.", ex);
+ consumeRemainingElements();
+ mReader.endObject();
+ continue;
+ }
+ e = eb.build();
+ }
+
+ return e;
+ }
+
+ private byte[] readData() throws IOException {
+ ArrayList<Integer> data = new ArrayList<Integer>();
+ try {
+ mReader.beginArray();
+ while (mReader.hasNext()) {
+ data.add(Integer.decode(mReader.nextString()));
+ }
+ mReader.endArray();
+ } catch (IllegalStateException|NumberFormatException e) {
+ consumeRemainingElements();
+ mReader.endArray();
+ throw new IllegalStateException("Encountered malformed data.", e);
+ }
+ byte[] rawData = new byte[data.size()];
+ for (int i = 0; i < data.size(); i++) {
+ int d = data.get(i);
+ if ((d & 0xFF) != d) {
+ throw new IllegalStateException("Invalid data, all values must be byte-sized");
+ }
+ rawData[i] = (byte)d;
+ }
+ return rawData;
+ }
+
+ private int readInt() throws IOException {
+ String val = mReader.nextString();
+ return Integer.decode(val);
+ }
+
+ private void consumeRemainingElements() throws IOException {
+ while (mReader.hasNext()) {
+ mReader.skipValue();
+ }
+ }
+ }
+
+ private static void error(String msg) {
+ error(msg, null);
+ }
+
+ private static void error(String msg, Exception e) {
+ System.out.println(msg);
+ Log.e(TAG, msg);
+ if (e != null) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+}
diff --git a/cmds/hid/src/com/android/commands/hid/Hid.java b/cmds/hid/src/com/android/commands/hid/Hid.java
new file mode 100644
index 0000000..976a782
--- /dev/null
+++ b/cmds/hid/src/com/android/commands/hid/Hid.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.commands.hid;
+
+import android.os.SystemClock;
+import android.util.JsonReader;
+import android.util.JsonToken;
+import android.util.Log;
+import android.util.SparseArray;
+
+import libcore.io.IoUtils;
+
+import java.io.BufferedInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+
+public class Hid {
+ private static final String TAG = "HID";
+
+ private final Event.Reader mReader;
+ private final SparseArray<Device> mDevices;
+
+ private static void usage() {
+ error("Usage: hid [FILE]");
+ }
+
+ public static void main(String[] args) {
+ if (args.length != 1) {
+ usage();
+ System.exit(1);
+ }
+
+ InputStream stream = null;
+ try {
+ if (args[0].equals("-")) {
+ stream = System.in;
+ } else {
+ File f = new File(args[0]);
+ stream = new FileInputStream(f);
+ }
+ (new Hid(stream)).run();
+ } catch (Exception e) {
+ error("HID injection failed.", e);
+ System.exit(1);
+ } finally {
+ IoUtils.closeQuietly(stream);
+ }
+ }
+
+ private Hid(InputStream in) {
+ mDevices = new SparseArray<Device>();
+ try {
+ mReader = new Event.Reader(new InputStreamReader(in, "UTF-8"));
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private void run() {
+ try {
+ Event e = null;
+ while ((e = mReader.getNextEvent()) != null) {
+ process(e);
+ }
+ } catch (IOException ex) {
+ error("Error reading in events.", ex);
+ }
+
+ for (int i = 0; i < mDevices.size(); i++) {
+ mDevices.valueAt(i).close();
+ }
+ }
+
+
+ private void process(Event e) {
+ final int index = mDevices.indexOfKey(e.getId());
+ if (index >= 0) {
+ Device d = mDevices.valueAt(index);
+ if (Event.COMMAND_DELAY.equals(e.getCommand())) {
+ d.addDelay(e.getDuration());
+ } else if (Event.COMMAND_REPORT.equals(e.getCommand())) {
+ d.sendReport(e.getReport());
+ } else {
+ error("Unknown command \"" + e.getCommand() + "\". Ignoring event.");
+ }
+ } else {
+ registerDevice(e);
+ }
+ }
+
+ private void registerDevice(Event e) {
+ if (!Event.COMMAND_REGISTER.equals(e.getCommand())) {
+ throw new IllegalStateException(
+ "Tried to send command \"" + e.getCommand() + "\" to an unregistered device!");
+ }
+ int id = e.getId();
+ Device d = new Device(id, e.getName(), e.getVendorId(), e.getProductId(),
+ e.getDescriptor(), e.getReport());
+ mDevices.append(id, d);
+ }
+
+ private static void error(String msg) {
+ error(msg, null);
+ }
+
+ private static void error(String msg, Exception e) {
+ System.out.println(msg);
+ Log.e(TAG, msg);
+ if (e != null) {
+ Log.e(TAG, Log.getStackTraceString(e));
+ }
+ }
+}
diff --git a/cmds/wm/src/com/android/commands/wm/Wm.java b/cmds/wm/src/com/android/commands/wm/Wm.java
index 64f023f..fb050e5 100644
--- a/cmds/wm/src/com/android/commands/wm/Wm.java
+++ b/cmds/wm/src/com/android/commands/wm/Wm.java
@@ -54,6 +54,7 @@ public class Wm extends BaseCommand {
" wm density [reset|DENSITY]\n" +
" wm overscan [reset|LEFT,TOP,RIGHT,BOTTOM]\n" +
" wm scaling [off|auto]\n" +
+ " wm screen-capture [userId] [true|false]\n" +
"\n" +
"wm size: return or override display size.\n" +
" width and height in pixels unless suffixed with 'dp'.\n" +
@@ -62,7 +63,9 @@ public class Wm extends BaseCommand {
"\n" +
"wm overscan: set overscan area for display.\n" +
"\n" +
- "wm scaling: set display scaling mode.\n"
+ "wm scaling: set display scaling mode.\n" +
+ "\n" +
+ "wm screen-capture: enable/disable screen capture.\n"
);
}
@@ -85,16 +88,39 @@ public class Wm extends BaseCommand {
runDisplayOverscan();
} else if (op.equals("scaling")) {
runDisplayScaling();
+ } else if (op.equals("screen-capture")) {
+ runSetScreenCapture();
} else {
showError("Error: unknown command '" + op + "'");
return;
}
}
+ private void runSetScreenCapture() throws Exception {
+ String userIdStr = nextArg();
+ String enableStr = nextArg();
+ int userId;
+ boolean disable;
+
+ try {
+ userId = Integer.parseInt(userIdStr);
+ } catch (NumberFormatException e) {
+ System.err.println("Error: bad number " + e);
+ return;
+ }
+
+ disable = !Boolean.parseBoolean(enableStr);
+
+ try {
+ mWm.setScreenCaptureDisabled(userId, disable);
+ } catch (RemoteException e) {
+ System.err.println("Error: Can't set screen capture " + e);
+ }
+ }
+
private void runDisplaySize() throws Exception {
String size = nextArg();
int w, h;
- boolean scale = true;
if (size == null) {
Point initialSize = new Point();
Point baseSize = new Point();
@@ -181,7 +207,6 @@ public class Wm extends BaseCommand {
private void runDisplayOverscan() throws Exception {
String overscanStr = nextArgRequired();
Rect rect = new Rect();
- int density;
if ("reset".equals(overscanStr)) {
rect.set(0, 0, 0, 0);
} else {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 1b4ee2e..e8ab109 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -2075,6 +2075,9 @@ public class Activity extends ContextThemeWrapper
"by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
"android:windowActionBar to false in your theme to use a Toolbar instead.");
}
+ // Clear out the MenuInflater to make sure that it is valid for the new Action Bar
+ mMenuInflater = null;
+
ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
mActionBar = tbab;
mWindow.setCallback(tbab.getWrappedWindowCallback());
diff --git a/core/java/android/app/AssistContent.java b/core/java/android/app/AssistContent.java
deleted file mode 100644
index ad2ba39..0000000
--- a/core/java/android/app/AssistContent.java
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app;
-
-import android.content.ClipData;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Holds information about the content an application is viewing, to hand to an
- * assistant at the user's request. This is filled in by
- * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
- * @deprecated use {@link android.app.assist.AssistContent}.
- */
-@Deprecated
-public class AssistContent {
- private boolean mIsAppProvidedIntent = false;
- private Intent mIntent;
- private String mStructuredData;
- private ClipData mClipData;
- private Uri mUri;
- private final Bundle mExtras;
-
- /**
- * @hide
- * Key name this data structure is stored in the Bundle generated by
- * {@link android.app.Activity#onProvideAssistData}.
- */
- public static final String ASSIST_KEY = "android:assist_content";
-
- /**
- * @hide
- * Retrieve the framework-generated AssistContent that is stored within
- * the Bundle filled in by {@link android.app.Activity#onProvideAssistContent}.
- */
- public static android.app.assist.AssistContent getAssistContent(Bundle assistBundle) {
- return assistBundle.getParcelable(ASSIST_KEY);
- }
-
- public AssistContent() {
- mExtras = new Bundle();
- }
-
- /**
- * @hide
- * Called by {@link android.app.ActivityThread} to set the default Intent based on
- * {@link android.app.Activity#getIntent Activity.getIntent}.
- *
- * <p>Automatically populates {@link #mUri} if that Intent is an {@link Intent#ACTION_VIEW}
- * of a web (http or https scheme) URI.</p>
- */
- public void setDefaultIntent(Intent intent) {
- mIntent = intent;
- setWebUri(null);
- if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
- Uri uri = intent.getData();
- if (uri != null) {
- if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) {
- setWebUri(uri);
- }
- }
- }
- }
-
- /**
- * Sets the Intent associated with the content, describing the current top-level context of
- * the activity. If this contains a reference to a piece of data related to the activity,
- * be sure to set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} so the accessibility
- * service can access it.
- */
- public void setIntent(Intent intent) {
- mIsAppProvidedIntent = true;
- mIntent = intent;
- }
-
- /**
- * Returns the current {@link #setIntent} if one is set, else the default Intent obtained from
- * {@link android.app.Activity#getIntent Activity.getIntent}. Can be modified in-place.
- * @hide
- */
- public Intent getIntent() {
- return mIntent;
- }
-
- /**
- * Returns whether or not the current Intent was explicitly provided in
- * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. If not,
- * the Intent was automatically set based on
- * {@link android.app.Activity#getIntent Activity.getIntent}.
- */
- public boolean isAppProvidedIntent() {
- return mIsAppProvidedIntent;
- }
-
- /**
- * Optional additional content items that are involved with
- * the current UI. Access to this content will be granted to the assistant as if you
- * are sending it through an Intent with {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}.
- */
- public void setClipData(ClipData clip) {
- mClipData = clip;
- }
-
- /**
- * Return the current {@link #setClipData}, which you can modify in-place.
- */
- public ClipData getClipData() {
- return mClipData;
- }
-
- /**
- * Sets optional structured data regarding the content being viewed. The provided data
- * must be a string represented with <a href="http://json-ld.org/">JSON-LD</a> using the
- * <a href="http://schema.org/">schema.org</a> vocabulary.
- */
- public void setStructuredData(String structuredData) {
- mStructuredData = structuredData;
- }
-
- /**
- * Returns the current {@link #setStructuredData}.
- */
- public String getStructuredData() {
- return mStructuredData;
- }
-
- /**
- * Set a web URI associated with the current data being shown to the user.
- * This URI could be opened in a web browser, or in the app as an
- * {@link Intent#ACTION_VIEW} Intent, to show the same data that is currently
- * being displayed by it. The URI here should be something that is transportable
- * off the device into other environments to acesss the same data as is currently
- * being shown in the app; if the app does not have such a representation, it should
- * leave the null and only report the local intent and clip data.
- */
- public void setWebUri(Uri uri) {
- mUri = uri;
- }
-
- /**
- * Return the content's web URI as per {@link #setWebUri(android.net.Uri)}, or null if
- * there is none.
- */
- public Uri getWebUri() {
- return mUri;
- }
-
- /**
- * Return Bundle for extra vendor-specific data that can be modified and examined.
- */
- public Bundle getExtras() {
- return mExtras;
- }
-
- /** @hide */
- public AssistContent(Parcel in) {
- if (in.readInt() != 0) {
- mIntent = Intent.CREATOR.createFromParcel(in);
- }
- if (in.readInt() != 0) {
- mClipData = ClipData.CREATOR.createFromParcel(in);
- }
- if (in.readInt() != 0) {
- mUri = Uri.CREATOR.createFromParcel(in);
- }
- if (in.readInt() != 0) {
- mStructuredData = in.readString();
- }
- mIsAppProvidedIntent = in.readInt() == 1;
- mExtras = in.readBundle();
- }
-
- /** @hide */
- public void writeToParcelInternal(Parcel dest, int flags) {
- if (mIntent != null) {
- dest.writeInt(1);
- mIntent.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
- if (mClipData != null) {
- dest.writeInt(1);
- mClipData.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
- if (mUri != null) {
- dest.writeInt(1);
- mUri.writeToParcel(dest, flags);
- } else {
- dest.writeInt(0);
- }
- if (mStructuredData != null) {
- dest.writeInt(1);
- dest.writeString(mStructuredData);
- } else {
- dest.writeInt(0);
- }
- dest.writeInt(mIsAppProvidedIntent ? 1 : 0);
- dest.writeBundle(mExtras);
- }
-}
diff --git a/core/java/android/app/AssistStructure.java b/core/java/android/app/AssistStructure.java
deleted file mode 100644
index 7f6dae5..0000000
--- a/core/java/android/app/AssistStructure.java
+++ /dev/null
@@ -1,1075 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.app;
-
-import android.content.ComponentName;
-import android.graphics.Rect;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.PooledStringReader;
-import android.os.PooledStringWriter;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.view.ViewAssistStructure;
-import android.view.ViewRootImpl;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-
-import java.util.ArrayList;
-
-/**
- * Assist data automatically created by the platform's implementation
- * of {@link android.app.Activity#onProvideAssistData}.
- * @deprecated use {@link android.app.assist.AssistStructure}.
- */
-@Deprecated
-public class AssistStructure {
- static final String TAG = "AssistStructure";
-
- /**
- * @hide
- * Key name this data structure is stored in the Bundle generated by
- * {@link android.app.Activity#onProvideAssistData}.
- */
- public static final String ASSIST_KEY = "android:assist_structure";
-
- /** @hide */
- public boolean mHaveData;
-
- ComponentName mActivityComponent;
-
- final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
-
- final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>();
-
- /** @hide */
- public SendChannel mSendChannel;
- /** @hide */
- public IBinder mReceiveChannel;
-
- Rect mTmpRect = new Rect();
-
- static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
- static final String DESCRIPTOR = "android.app.AssistStructure";
-
- /** @hide */
- public final class SendChannel extends Binder {
- @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- if (code == TRANSACTION_XFER) {
- data.enforceInterface(DESCRIPTOR);
- writeContentToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
- return true;
- } else {
- return super.onTransact(code, data, reply, flags);
- }
- }
- }
-
- final static class ViewNodeText {
- CharSequence mText;
- int mTextSelectionStart;
- int mTextSelectionEnd;
- int mTextColor;
- int mTextBackgroundColor;
- float mTextSize;
- int mTextStyle;
- String mHint;
-
- ViewNodeText() {
- }
-
- ViewNodeText(Parcel in) {
- mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mTextSelectionStart = in.readInt();
- mTextSelectionEnd = in.readInt();
- mTextColor = in.readInt();
- mTextBackgroundColor = in.readInt();
- mTextSize = in.readFloat();
- mTextStyle = in.readInt();
- mHint = in.readString();
- }
-
- void writeToParcel(Parcel out) {
- TextUtils.writeToParcel(mText, out, 0);
- out.writeInt(mTextSelectionStart);
- out.writeInt(mTextSelectionEnd);
- out.writeInt(mTextColor);
- out.writeInt(mTextBackgroundColor);
- out.writeFloat(mTextSize);
- out.writeInt(mTextStyle);
- out.writeString(mHint);
- }
- }
-
- /**
- * Describes a window in the assist data.
- */
- static public class WindowNode {
- final int mX;
- final int mY;
- final int mWidth;
- final int mHeight;
- final CharSequence mTitle;
- final int mDisplayId;
- final ViewNode mRoot;
-
- WindowNode(AssistStructure assist, ViewRootImpl root) {
- View view = root.getView();
- Rect rect = new Rect();
- view.getBoundsOnScreen(rect);
- mX = rect.left - view.getLeft();
- mY = rect.top - view.getTop();
- mWidth = rect.width();
- mHeight = rect.height();
- mTitle = root.getTitle();
- mDisplayId = root.getDisplayId();
- mRoot = new ViewNode();
- ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
- if ((root.getWindowFlags()&WindowManager.LayoutParams.FLAG_SECURE) != 0) {
- // This is a secure window, so it doesn't want a screenshot, and that
- // means we should also not copy out its view hierarchy.
- view.onProvideStructure(builder);
- builder.setAssistBlocked(true);
- return;
- }
- view.dispatchProvideStructure(builder);
- }
-
- WindowNode(Parcel in, PooledStringReader preader) {
- mX = in.readInt();
- mY = in.readInt();
- mWidth = in.readInt();
- mHeight = in.readInt();
- mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- mDisplayId = in.readInt();
- mRoot = new ViewNode(in, preader);
- }
-
- void writeToParcel(Parcel out, PooledStringWriter pwriter) {
- out.writeInt(mX);
- out.writeInt(mY);
- out.writeInt(mWidth);
- out.writeInt(mHeight);
- TextUtils.writeToParcel(mTitle, out, 0);
- out.writeInt(mDisplayId);
- mRoot.writeToParcel(out, pwriter);
- }
-
- /**
- * Returns the left edge of the window, in pixels, relative to the left
- * edge of the screen.
- */
- public int getLeft() {
- return mX;
- }
-
- /**
- * Returns the top edge of the window, in pixels, relative to the top
- * edge of the screen.
- */
- public int getTop() {
- return mY;
- }
-
- /**
- * Returns the total width of the window in pixels.
- */
- public int getWidth() {
- return mWidth;
- }
-
- /**
- * Returns the total height of the window in pixels.
- */
- public int getHeight() {
- return mHeight;
- }
-
- /**
- * Returns the title associated with the window, if it has one.
- */
- public CharSequence getTitle() {
- return mTitle;
- }
-
- /**
- * Returns the ID of the display this window is on, for use with
- * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}.
- */
- public int getDisplayId() {
- return mDisplayId;
- }
-
- /**
- * Returns the {@link ViewNode} containing the root content of the window.
- */
- public ViewNode getRootViewNode() {
- return mRoot;
- }
- }
-
- /**
- * Describes a single view in the assist data.
- */
- static public class ViewNode {
- /**
- * Magic value for text color that has not been defined, which is very unlikely
- * to be confused with a real text color.
- */
- public static final int TEXT_COLOR_UNDEFINED = 1;
-
- public static final int TEXT_STYLE_BOLD = 1<<0;
- public static final int TEXT_STYLE_ITALIC = 1<<1;
- public static final int TEXT_STYLE_UNDERLINE = 1<<2;
- public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
-
- int mId;
- String mIdPackage;
- String mIdType;
- String mIdEntry;
- int mX;
- int mY;
- int mScrollX;
- int mScrollY;
- int mWidth;
- int mHeight;
-
- static final int FLAGS_DISABLED = 0x00000001;
- static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
- static final int FLAGS_FOCUSABLE = 0x00000010;
- static final int FLAGS_FOCUSED = 0x00000020;
- static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x04000000;
- static final int FLAGS_SELECTED = 0x00000040;
- static final int FLAGS_ASSIST_BLOCKED = 0x00000080;
- static final int FLAGS_ACTIVATED = 0x40000000;
- static final int FLAGS_CHECKABLE = 0x00000100;
- static final int FLAGS_CHECKED = 0x00000200;
- static final int FLAGS_CLICKABLE = 0x00004000;
- static final int FLAGS_LONG_CLICKABLE = 0x00200000;
- static final int FLAGS_CONTEXT_CLICKABLE = 0x00400000;
-
- int mFlags;
-
- String mClassName;
- CharSequence mContentDescription;
-
- ViewNodeText mText;
- Bundle mExtras;
-
- ViewNode[] mChildren;
-
- ViewNode() {
- }
-
- ViewNode(Parcel in, PooledStringReader preader) {
- mId = in.readInt();
- if (mId != 0) {
- mIdEntry = preader.readString();
- if (mIdEntry != null) {
- mIdType = preader.readString();
- mIdPackage = preader.readString();
- } else {
- mIdPackage = mIdType = null;
- }
- } else {
- mIdPackage = mIdType = mIdEntry = null;
- }
- mX = in.readInt();
- mY = in.readInt();
- mScrollX = in.readInt();
- mScrollY = in.readInt();
- mWidth = in.readInt();
- mHeight = in.readInt();
- mFlags = in.readInt();
- mClassName = preader.readString();
- mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
- if (in.readInt() != 0) {
- mText = new ViewNodeText(in);
- } else {
- mText = null;
- }
- mExtras = in.readBundle();
- final int NCHILDREN = in.readInt();
- if (NCHILDREN > 0) {
- mChildren = new ViewNode[NCHILDREN];
- for (int i=0; i<NCHILDREN; i++) {
- mChildren[i] = new ViewNode(in, preader);
- }
- } else {
- mChildren = null;
- }
- }
-
- void writeToParcel(Parcel out, PooledStringWriter pwriter) {
- out.writeInt(mId);
- if (mId != 0) {
- pwriter.writeString(mIdEntry);
- if (mIdEntry != null) {
- pwriter.writeString(mIdType);
- pwriter.writeString(mIdPackage);
- }
- }
- out.writeInt(mX);
- out.writeInt(mY);
- out.writeInt(mScrollX);
- out.writeInt(mScrollY);
- out.writeInt(mWidth);
- out.writeInt(mHeight);
- out.writeInt(mFlags);
- pwriter.writeString(mClassName);
- TextUtils.writeToParcel(mContentDescription, out, 0);
- if (mText != null) {
- out.writeInt(1);
- mText.writeToParcel(out);
- } else {
- out.writeInt(0);
- }
- out.writeBundle(mExtras);
- if (mChildren != null) {
- final int NCHILDREN = mChildren.length;
- out.writeInt(NCHILDREN);
- for (int i=0; i<NCHILDREN; i++) {
- mChildren[i].writeToParcel(out, pwriter);
- }
- } else {
- out.writeInt(0);
- }
- }
-
- /**
- * Returns the ID associated with this view, as per {@link View#getId() View.getId()}.
- */
- public int getId() {
- return mId;
- }
-
- /**
- * If {@link #getId()} is a resource identifier, this is the package name of that
- * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
- * for more information.
- */
- public String getIdPackage() {
- return mIdPackage;
- }
-
- /**
- * If {@link #getId()} is a resource identifier, this is the type name of that
- * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
- * for more information.
- */
- public String getIdType() {
- return mIdType;
- }
-
- /**
- * If {@link #getId()} is a resource identifier, this is the entry name of that
- * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
- * for more information.
- */
- public String getIdEntry() {
- return mIdEntry;
- }
-
- /**
- * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
- */
- public int getLeft() {
- return mX;
- }
-
- /**
- * Returns the top edge of this view, in pixels, relative to the top edge of its parent.
- */
- public int getTop() {
- return mY;
- }
-
- /**
- * Returns the current X scroll offset of this view, as per
- * {@link android.view.View#getScrollX() View.getScrollX()}.
- */
- public int getScrollX() {
- return mScrollX;
- }
-
- /**
- * Returns the current Y scroll offset of this view, as per
- * {@link android.view.View#getScrollX() View.getScrollY()}.
- */
- public int getScrollY() {
- return mScrollY;
- }
-
- /**
- * Returns the width of this view, in pixels.
- */
- public int getWidth() {
- return mWidth;
- }
-
- /**
- * Returns the height of this view, in pixels.
- */
- public int getHeight() {
- return mHeight;
- }
-
- /**
- * Returns the visibility mode of this view, as per
- * {@link android.view.View#getVisibility() View.getVisibility()}.
- */
- public int getVisibility() {
- return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
- }
-
- /**
- * Returns true if assist data has been blocked starting at this node in the hierarchy.
- */
- public boolean isAssistBlocked() {
- return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0;
- }
-
- /**
- * Returns true if this node is in an enabled state.
- */
- public boolean isEnabled() {
- return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
- }
-
- /**
- * Returns true if this node is clickable by the user.
- */
- public boolean isClickable() {
- return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
- }
-
- /**
- * Returns true if this node can take input focus.
- */
- public boolean isFocusable() {
- return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
- }
-
- /**
- * Returns true if this node currently had input focus at the time that the
- * structure was collected.
- */
- public boolean isFocused() {
- return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
- }
-
- /**
- * Returns true if this node currently had accessibility focus at the time that the
- * structure was collected.
- */
- public boolean isAccessibilityFocused() {
- return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
- }
-
- /**
- * Returns true if this node represents something that is checkable by the user.
- */
- public boolean isCheckable() {
- return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
- }
-
- /**
- * Returns true if this node is currently in a checked state.
- */
- public boolean isChecked() {
- return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
- }
-
- /**
- * Returns true if this node has currently been selected by the user.
- */
- public boolean isSelected() {
- return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
- }
-
- /**
- * Returns true if this node has currently been activated by the user.
- */
- public boolean isActivated() {
- return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
- }
-
- /**
- * Returns true if this node is something the user can perform a long click/press on.
- */
- public boolean isLongClickable() {
- return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
- }
-
- /**
- * Returns true if this node is something the user can perform a context click on.
- */
- public boolean isContextClickable() {
- return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0;
- }
-
- /**
- * Returns the class name of the node's implementation, indicating its behavior.
- * For example, a button will report "android.widget.Button" meaning it behaves
- * like a {@link android.widget.Button}.
- */
- public String getClassName() {
- return mClassName;
- }
-
- /**
- * Returns any content description associated with the node, which semantically describes
- * its purpose for accessibility and other uses.
- */
- public CharSequence getContentDescription() {
- return mContentDescription;
- }
-
- /**
- * Returns any text associated with the node that is displayed to the user, or null
- * if there is none.
- */
- public CharSequence getText() {
- return mText != null ? mText.mText : null;
- }
-
- /**
- * If {@link #getText()} is non-null, this is where the current selection starts.
- */
- public int getTextSelectionStart() {
- return mText != null ? mText.mTextSelectionStart : -1;
- }
-
- /**
- * If {@link #getText()} is non-null, this is where the current selection starts.
- * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
- * indicating the cursor position.
- */
- public int getTextSelectionEnd() {
- return mText != null ? mText.mTextSelectionEnd : -1;
- }
-
- /**
- * If {@link #getText()} is non-null, this is the main text color associated with it.
- * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned.
- * Note that the text may also contain style spans that modify the color of specific
- * parts of the text.
- */
- public int getTextColor() {
- return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
- }
-
- /**
- * If {@link #getText()} is non-null, this is the main text background color associated
- * with it.
- * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
- * Note that the text may also contain style spans that modify the color of specific
- * parts of the text.
- */
- public int getTextBackgroundColor() {
- return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
- }
-
- /**
- * If {@link #getText()} is non-null, this is the main text size (in pixels) associated
- * with it.
- * Note that the text may also contain style spans that modify the size of specific
- * parts of the text.
- */
- public float getTextSize() {
- return mText != null ? mText.mTextSize : 0;
- }
-
- /**
- * If {@link #getText()} is non-null, this is the main text style associated
- * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD},
- * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or
- * {@link #TEXT_STYLE_UNDERLINE}.
- * Note that the text may also contain style spans that modify the style of specific
- * parts of the text.
- */
- public int getTextStyle() {
- return mText != null ? mText.mTextStyle : 0;
- }
-
- /**
- * Return additional hint text associated with the node; this is typically used with
- * a node that takes user input, describing to the user what the input means.
- */
- public String getHint() {
- return mText != null ? mText.mHint : null;
- }
-
- /**
- * Return a Bundle containing optional vendor-specific extension information.
- */
- public Bundle getExtras() {
- return mExtras;
- }
-
- /**
- * Return the number of children this node has.
- */
- public int getChildCount() {
- return mChildren != null ? mChildren.length : 0;
- }
-
- /**
- * Return a child of this node, given an index value from 0 to
- * {@link #getChildCount()}-1.
- */
- public ViewNode getChildAt(int index) {
- return mChildren[index];
- }
- }
-
- static class ViewNodeBuilder extends ViewAssistStructure {
- final AssistStructure mAssist;
- final ViewNode mNode;
- final boolean mAsync;
-
- ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
- mAssist = assist;
- mNode = node;
- mAsync = async;
- }
-
- @Override
- public void setId(int id, String packageName, String typeName, String entryName) {
- mNode.mId = id;
- mNode.mIdPackage = packageName;
- mNode.mIdType = typeName;
- mNode.mIdEntry = entryName;
- }
-
- @Override
- public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
- mNode.mX = left;
- mNode.mY = top;
- mNode.mScrollX = scrollX;
- mNode.mScrollY = scrollY;
- mNode.mWidth = width;
- mNode.mHeight = height;
- }
-
- @Override
- public void setVisibility(int visibility) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
- }
-
- @Override
- public void setAssistBlocked(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ASSIST_BLOCKED)
- | (state ? 0 : ViewNode.FLAGS_ASSIST_BLOCKED);
- }
-
- @Override
- public void setEnabled(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED)
- | (state ? 0 : ViewNode.FLAGS_DISABLED);
- }
-
- @Override
- public void setClickable(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE)
- | (state ? ViewNode.FLAGS_CLICKABLE : 0);
- }
-
- @Override
- public void setLongClickable(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE)
- | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0);
- }
-
- @Override
- public void setContextClickable(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CONTEXT_CLICKABLE)
- | (state ? ViewNode.FLAGS_CONTEXT_CLICKABLE : 0);
- }
-
- @Override
- public void setFocusable(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE)
- | (state ? ViewNode.FLAGS_FOCUSABLE : 0);
- }
-
- @Override
- public void setFocused(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED)
- | (state ? ViewNode.FLAGS_FOCUSED : 0);
- }
-
- @Override
- public void setAccessibilityFocused(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED)
- | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0);
- }
-
- @Override
- public void setCheckable(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE)
- | (state ? ViewNode.FLAGS_CHECKABLE : 0);
- }
-
- @Override
- public void setChecked(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED)
- | (state ? ViewNode.FLAGS_CHECKED : 0);
- }
-
- @Override
- public void setSelected(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED)
- | (state ? ViewNode.FLAGS_SELECTED : 0);
- }
-
- @Override
- public void setActivated(boolean state) {
- mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED)
- | (state ? ViewNode.FLAGS_ACTIVATED : 0);
- }
-
- @Override
- public void setClassName(String className) {
- mNode.mClassName = className;
- }
-
- @Override
- public void setContentDescription(CharSequence contentDescription) {
- mNode.mContentDescription = contentDescription;
- }
-
- private final ViewNodeText getNodeText() {
- if (mNode.mText != null) {
- return mNode.mText;
- }
- mNode.mText = new ViewNodeText();
- return mNode.mText;
- }
-
- @Override
- public void setText(CharSequence text) {
- ViewNodeText t = getNodeText();
- t.mText = text;
- t.mTextSelectionStart = t.mTextSelectionEnd = -1;
- }
-
- @Override
- public void setText(CharSequence text, int selectionStart, int selectionEnd) {
- ViewNodeText t = getNodeText();
- t.mText = text;
- t.mTextSelectionStart = selectionStart;
- t.mTextSelectionEnd = selectionEnd;
- }
-
- @Override
- public void setTextStyle(float size, int fgColor, int bgColor, int style) {
- ViewNodeText t = getNodeText();
- t.mTextColor = fgColor;
- t.mTextBackgroundColor = bgColor;
- t.mTextSize = size;
- t.mTextStyle = style;
- }
-
- @Override
- public void setHint(CharSequence hint) {
- getNodeText().mHint = hint != null ? hint.toString() : null;
- }
-
- @Override
- public CharSequence getText() {
- return mNode.mText != null ? mNode.mText.mText : null;
- }
-
- @Override
- public int getTextSelectionStart() {
- return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1;
- }
-
- @Override
- public int getTextSelectionEnd() {
- return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1;
- }
-
- @Override
- public CharSequence getHint() {
- return mNode.mText != null ? mNode.mText.mHint : null;
- }
-
- @Override
- public Bundle getExtras() {
- if (mNode.mExtras != null) {
- return mNode.mExtras;
- }
- mNode.mExtras = new Bundle();
- return mNode.mExtras;
- }
-
- @Override
- public boolean hasExtras() {
- return mNode.mExtras != null;
- }
-
- @Override
- public void setChildCount(int num) {
- mNode.mChildren = new ViewNode[num];
- }
-
- @Override
- public int addChildCount(int num) {
- if (mNode.mChildren == null) {
- setChildCount(num);
- return 0;
- }
- final int start = mNode.mChildren.length;
- ViewNode[] newArray = new ViewNode[start + num];
- System.arraycopy(mNode.mChildren, 0, newArray, 0, start);
- mNode.mChildren = newArray;
- return start;
- }
-
- @Override
- public int getChildCount() {
- return mNode.mChildren != null ? mNode.mChildren.length : 0;
- }
-
- @Override
- public ViewAssistStructure newChild(int index) {
- ViewNode node = new ViewNode();
- mNode.mChildren[index] = node;
- return new ViewNodeBuilder(mAssist, node, false);
- }
-
- @Override
- public ViewAssistStructure asyncNewChild(int index) {
- synchronized (mAssist) {
- ViewNode node = new ViewNode();
- mNode.mChildren[index] = node;
- ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
- mAssist.mPendingAsyncChildren.add(builder);
- return builder;
- }
- }
-
- @Override
- public void asyncCommit() {
- synchronized (mAssist) {
- if (!mAsync) {
- throw new IllegalStateException("Child " + this
- + " was not created with ViewAssistStructure.asyncNewChild");
- }
- if (!mAssist.mPendingAsyncChildren.remove(this)) {
- throw new IllegalStateException("Child " + this + " already committed");
- }
- mAssist.notifyAll();
- }
- }
-
- @Override
- public Rect getTempRect() {
- return mAssist.mTmpRect;
- }
- }
-
- /** @hide */
- public AssistStructure(Activity activity) {
- mHaveData = true;
- mActivityComponent = activity.getComponentName();
- ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
- activity.getActivityToken());
- for (int i=0; i<views.size(); i++) {
- ViewRootImpl root = views.get(i);
- mWindowNodes.add(new WindowNode(this, root));
- }
- }
-
- public AssistStructure() {
- mHaveData = true;
- mActivityComponent = null;
- }
-
- /** @hide */
- public AssistStructure(Parcel in) {
- mReceiveChannel = in.readStrongBinder();
- }
-
- /** @hide */
- public void dump() {
- Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
- final int N = getWindowNodeCount();
- for (int i=0; i<N; i++) {
- WindowNode node = getWindowNodeAt(i);
- Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
- + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
- dump(" ", node.getRootViewNode());
- }
- }
-
- void dump(String prefix, ViewNode node) {
- Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
- + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
- int id = node.getId();
- if (id != 0) {
- StringBuilder sb = new StringBuilder();
- sb.append(prefix); sb.append(" ID: #"); sb.append(Integer.toHexString(id));
- String entry = node.getIdEntry();
- if (entry != null) {
- String type = node.getIdType();
- String pkg = node.getIdPackage();
- sb.append(" "); sb.append(pkg); sb.append(":"); sb.append(type);
- sb.append("/"); sb.append(entry);
- }
- Log.i(TAG, sb.toString());
- }
- int scrollX = node.getScrollX();
- int scrollY = node.getScrollY();
- if (scrollX != 0 || scrollY != 0) {
- Log.i(TAG, prefix + " Scroll: " + scrollX + "," + scrollY);
- }
- CharSequence contentDescription = node.getContentDescription();
- if (contentDescription != null) {
- Log.i(TAG, prefix + " Content description: " + contentDescription);
- }
- CharSequence text = node.getText();
- if (text != null) {
- Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-"
- + node.getTextSelectionEnd() + "): " + text);
- Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #"
- + node.getTextStyle());
- Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor())
- + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
- }
- String hint = node.getHint();
- if (hint != null) {
- Log.i(TAG, prefix + " Hint: " + hint);
- }
- Bundle extras = node.getExtras();
- if (extras != null) {
- Log.i(TAG, prefix + " Extras: " + extras);
- }
- final int NCHILDREN = node.getChildCount();
- if (NCHILDREN > 0) {
- Log.i(TAG, prefix + " Children:");
- String cprefix = prefix + " ";
- for (int i=0; i<NCHILDREN; i++) {
- ViewNode cnode = node.getChildAt(i);
- dump(cprefix, cnode);
- }
- }
- }
-
- /**
- * @hide
- * Retrieve the framework-generated AssistStructure that is stored within
- * the Bundle filled in by {@link Activity#onProvideAssistData}.
- */
- public static android.app.assist.AssistStructure getAssistStructure(Bundle assistBundle) {
- return assistBundle.getParcelable(ASSIST_KEY);
- }
-
- /**
- * Return the activity this AssistStructure came from.
- */
- public ComponentName getActivityComponent() {
- ensureData();
- return mActivityComponent;
- }
-
- /**
- * Return the number of window contents that have been collected in this assist data.
- */
- public int getWindowNodeCount() {
- ensureData();
- return mWindowNodes.size();
- }
-
- /**
- * Return one of the windows in the assist data.
- * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1.
- * @hide
- */
- public WindowNode getWindowNodeAt(int index) {
- ensureData();
- return mWindowNodes.get(index);
- }
-
- /** @hide */
- public void ensureData() {
- if (mHaveData) {
- return;
- }
- mHaveData = true;
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInterfaceToken(DESCRIPTOR);
- try {
- mReceiveChannel.transact(TRANSACTION_XFER, data, reply, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failure reading AssistStructure data", e);
- return;
- }
- readContentFromParcel(reply);
- data.recycle();
- reply.recycle();
- }
-
- void writeContentToParcel(Parcel out, int flags) {
- // First make sure all content has been created.
- boolean skipStructure = false;
- synchronized (this) {
- long endTime = SystemClock.uptimeMillis() + 5000;
- long now;
- while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) {
- try {
- wait(endTime-now);
- } catch (InterruptedException e) {
- }
- }
- if (mPendingAsyncChildren.size() > 0) {
- // We waited too long, assume none of the assist structure is valid.
- skipStructure = true;
- }
- }
- int start = out.dataPosition();
- PooledStringWriter pwriter = new PooledStringWriter(out);
- ComponentName.writeToParcel(mActivityComponent, out);
- final int N = skipStructure ? 0 : mWindowNodes.size();
- out.writeInt(N);
- for (int i=0; i<N; i++) {
- mWindowNodes.get(i).writeToParcel(out, pwriter);
- }
- pwriter.finish();
- Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes");
- }
-
- void readContentFromParcel(Parcel in) {
- PooledStringReader preader = new PooledStringReader(in);
- mActivityComponent = ComponentName.readFromParcel(in);
- final int N = in.readInt();
- for (int i=0; i<N; i++) {
- mWindowNodes.add(new WindowNode(in, preader));
- }
- //dump();
- }
-}
diff --git a/core/java/android/app/VoiceInteractor.java b/core/java/android/app/VoiceInteractor.java
index 9cc399d..abb8244 100644
--- a/core/java/android/app/VoiceInteractor.java
+++ b/core/java/android/app/VoiceInteractor.java
@@ -225,6 +225,9 @@ public final class VoiceInteractor {
* Cancel this active request.
*/
public void cancel() {
+ if (mRequestInterface == null) {
+ throw new IllegalStateException("Request " + this + " is no longer active");
+ }
try {
mRequestInterface.cancel();
} catch (RemoteException e) {
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 125708a..4d1cff5 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3972,6 +3972,7 @@ public class DevicePolicyManager {
* <li>{@link Settings.Global#STAY_ON_WHILE_PLUGGED_IN}
* This setting is only available from {@link android.os.Build.VERSION_CODES#MNC} onwards
* and can only be set if {@link #setMaximumTimeToLock} is not used to set a timeout.</li>
+ * <li>{@link Settings.Global#WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN}</li>
* </ul>
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -4349,6 +4350,12 @@ public class DevicePolicyManager {
* group that the runtime permission belongs to. This method can only be called
* by a profile or device owner.
*
+ * <p/>Setting the grant state to {@link #PERMISSION_GRANT_STATE_DEFAULT default} does not
+ * revoke the permission. It retains the previous grant, if any.
+ *
+ * <p/>Permissions can be granted or revoked only for applications built with a
+ * {@code targetSdkVersion} of {@link android.os.Build.VERSION_CODES#MNC} or later.
+ *
* @param admin Which profile or device owner this request is associated with.
* @param packageName The application to grant or revoke a permission to.
* @param permission The permission to grant or revoke.
diff --git a/core/java/android/app/assist/AssistContent.java b/core/java/android/app/assist/AssistContent.java
index c7e7330..07b2d57 100644
--- a/core/java/android/app/assist/AssistContent.java
+++ b/core/java/android/app/assist/AssistContent.java
@@ -1,24 +1,184 @@
package android.app.assist;
+import android.content.ClipData;
import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
/**
- * New home for AssistContent.
+ * Holds information about the content an application is viewing, to hand to an
+ * assistant at the user's request. This is filled in by
+ * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
*/
-public final class AssistContent extends android.app.AssistContent implements Parcelable {
+@Deprecated
+public class AssistContent implements Parcelable {
+ private boolean mIsAppProvidedIntent = false;
+ private Intent mIntent;
+ private String mStructuredData;
+ private ClipData mClipData;
+ private Uri mUri;
+ private final Bundle mExtras;
- /** @hide */
public AssistContent() {
+ mExtras = new Bundle();
}
- public AssistContent(Parcel in) {
- super(in);
+ /**
+ * @hide
+ * Called by {@link android.app.ActivityThread} to set the default Intent based on
+ * {@link android.app.Activity#getIntent Activity.getIntent}.
+ *
+ * <p>Automatically populates {@link #mUri} if that Intent is an {@link Intent#ACTION_VIEW}
+ * of a web (http or https scheme) URI.</p>
+ */
+ public void setDefaultIntent(Intent intent) {
+ mIntent = intent;
+ setWebUri(null);
+ if (intent != null && Intent.ACTION_VIEW.equals(intent.getAction())) {
+ Uri uri = intent.getData();
+ if (uri != null) {
+ if ("http".equals(uri.getScheme()) || "https".equals(uri.getScheme())) {
+ setWebUri(uri);
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the Intent associated with the content, describing the current top-level context of
+ * the activity. If this contains a reference to a piece of data related to the activity,
+ * be sure to set {@link Intent#FLAG_GRANT_READ_URI_PERMISSION} so the accessibility
+ * service can access it.
+ */
+ public void setIntent(Intent intent) {
+ mIsAppProvidedIntent = true;
+ mIntent = intent;
}
+ /**
+ * Returns the current {@link #setIntent} if one is set, else the default Intent obtained from
+ * {@link android.app.Activity#getIntent Activity.getIntent}. Can be modified in-place.
+ */
public Intent getIntent() {
- return super.getIntent();
+ return mIntent;
+ }
+
+ /**
+ * Returns whether or not the current Intent was explicitly provided in
+ * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}. If not,
+ * the Intent was automatically set based on
+ * {@link android.app.Activity#getIntent Activity.getIntent}.
+ */
+ public boolean isAppProvidedIntent() {
+ return mIsAppProvidedIntent;
+ }
+
+ /**
+ * Optional additional content items that are involved with
+ * the current UI. Access to this content will be granted to the assistant as if you
+ * are sending it through an Intent with {@link Intent#FLAG_GRANT_READ_URI_PERMISSION}.
+ */
+ public void setClipData(ClipData clip) {
+ mClipData = clip;
+ }
+
+ /**
+ * Return the current {@link #setClipData}, which you can modify in-place.
+ */
+ public ClipData getClipData() {
+ return mClipData;
+ }
+
+ /**
+ * Sets optional structured data regarding the content being viewed. The provided data
+ * must be a string represented with <a href="http://json-ld.org/">JSON-LD</a> using the
+ * <a href="http://schema.org/">schema.org</a> vocabulary.
+ */
+ public void setStructuredData(String structuredData) {
+ mStructuredData = structuredData;
+ }
+
+ /**
+ * Returns the current {@link #setStructuredData}.
+ */
+ public String getStructuredData() {
+ return mStructuredData;
+ }
+
+ /**
+ * Set a web URI associated with the current data being shown to the user.
+ * This URI could be opened in a web browser, or in the app as an
+ * {@link Intent#ACTION_VIEW} Intent, to show the same data that is currently
+ * being displayed by it. The URI here should be something that is transportable
+ * off the device into other environments to acesss the same data as is currently
+ * being shown in the app; if the app does not have such a representation, it should
+ * leave the null and only report the local intent and clip data.
+ */
+ public void setWebUri(Uri uri) {
+ mUri = uri;
+ }
+
+ /**
+ * Return the content's web URI as per {@link #setWebUri(android.net.Uri)}, or null if
+ * there is none.
+ */
+ public Uri getWebUri() {
+ return mUri;
+ }
+
+ /**
+ * Return Bundle for extra vendor-specific data that can be modified and examined.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ AssistContent(Parcel in) {
+ if (in.readInt() != 0) {
+ mIntent = Intent.CREATOR.createFromParcel(in);
+ }
+ if (in.readInt() != 0) {
+ mClipData = ClipData.CREATOR.createFromParcel(in);
+ }
+ if (in.readInt() != 0) {
+ mUri = Uri.CREATOR.createFromParcel(in);
+ }
+ if (in.readInt() != 0) {
+ mStructuredData = in.readString();
+ }
+ mIsAppProvidedIntent = in.readInt() == 1;
+ mExtras = in.readBundle();
+ }
+
+ void writeToParcelInternal(Parcel dest, int flags) {
+ if (mIntent != null) {
+ dest.writeInt(1);
+ mIntent.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mClipData != null) {
+ dest.writeInt(1);
+ mClipData.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mUri != null) {
+ dest.writeInt(1);
+ mUri.writeToParcel(dest, flags);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mStructuredData != null) {
+ dest.writeInt(1);
+ dest.writeString(mStructuredData);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(mIsAppProvidedIntent ? 1 : 0);
+ dest.writeBundle(mExtras);
}
@Override
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 1677e95..1a04895 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1,28 +1,1038 @@
package android.app.assist;
import android.app.Activity;
+import android.content.ComponentName;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
+import android.os.PooledStringReader;
+import android.os.PooledStringWriter;
+import android.os.RemoteException;
+import android.os.SystemClock;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewAssistStructure;
+import android.view.ViewRootImpl;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+import java.util.ArrayList;
/**
- * New home for AssistStructure.
+ * Assist data automatically created by the platform's implementation
+ * of {@link android.app.Activity#onProvideAssistData}.
*/
-public final class AssistStructure extends android.app.AssistStructure implements Parcelable {
+public class AssistStructure implements Parcelable {
+ static final String TAG = "AssistStructure";
- public AssistStructure() {
+ boolean mHaveData;
+
+ ComponentName mActivityComponent;
+
+ final ArrayList<WindowNode> mWindowNodes = new ArrayList<>();
+
+ final ArrayList<ViewNodeBuilder> mPendingAsyncChildren = new ArrayList<>();
+
+ SendChannel mSendChannel;
+ IBinder mReceiveChannel;
+
+ Rect mTmpRect = new Rect();
+
+ static final int TRANSACTION_XFER = Binder.FIRST_CALL_TRANSACTION+1;
+ static final String DESCRIPTOR = "android.app.AssistStructure";
+
+ final class SendChannel extends Binder {
+ @Override protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ if (code == TRANSACTION_XFER) {
+ data.enforceInterface(DESCRIPTOR);
+ writeContentToParcel(reply, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+ return true;
+ } else {
+ return super.onTransact(code, data, reply, flags);
+ }
+ }
+ }
+
+ final static class ViewNodeText {
+ CharSequence mText;
+ int mTextSelectionStart;
+ int mTextSelectionEnd;
+ int mTextColor;
+ int mTextBackgroundColor;
+ float mTextSize;
+ int mTextStyle;
+ String mHint;
+
+ ViewNodeText() {
+ }
+
+ ViewNodeText(Parcel in) {
+ mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mTextSelectionStart = in.readInt();
+ mTextSelectionEnd = in.readInt();
+ mTextColor = in.readInt();
+ mTextBackgroundColor = in.readInt();
+ mTextSize = in.readFloat();
+ mTextStyle = in.readInt();
+ mHint = in.readString();
+ }
+
+ void writeToParcel(Parcel out) {
+ TextUtils.writeToParcel(mText, out, 0);
+ out.writeInt(mTextSelectionStart);
+ out.writeInt(mTextSelectionEnd);
+ out.writeInt(mTextColor);
+ out.writeInt(mTextBackgroundColor);
+ out.writeFloat(mTextSize);
+ out.writeInt(mTextStyle);
+ out.writeString(mHint);
+ }
+ }
+
+ /**
+ * Describes a window in the assist data.
+ */
+ static public class WindowNode {
+ final int mX;
+ final int mY;
+ final int mWidth;
+ final int mHeight;
+ final CharSequence mTitle;
+ final int mDisplayId;
+ final ViewNode mRoot;
+
+ WindowNode(AssistStructure assist, ViewRootImpl root) {
+ View view = root.getView();
+ Rect rect = new Rect();
+ view.getBoundsOnScreen(rect);
+ mX = rect.left - view.getLeft();
+ mY = rect.top - view.getTop();
+ mWidth = rect.width();
+ mHeight = rect.height();
+ mTitle = root.getTitle();
+ mDisplayId = root.getDisplayId();
+ mRoot = new ViewNode();
+ ViewNodeBuilder builder = new ViewNodeBuilder(assist, mRoot, false);
+ if ((root.getWindowFlags()& WindowManager.LayoutParams.FLAG_SECURE) != 0) {
+ // This is a secure window, so it doesn't want a screenshot, and that
+ // means we should also not copy out its view hierarchy.
+ view.onProvideStructure(builder);
+ builder.setAssistBlocked(true);
+ return;
+ }
+ view.dispatchProvideStructure(builder);
+ }
+
+ WindowNode(Parcel in, PooledStringReader preader) {
+ mX = in.readInt();
+ mY = in.readInt();
+ mWidth = in.readInt();
+ mHeight = in.readInt();
+ mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ mDisplayId = in.readInt();
+ mRoot = new ViewNode(in, preader);
+ }
+
+ void writeToParcel(Parcel out, PooledStringWriter pwriter) {
+ out.writeInt(mX);
+ out.writeInt(mY);
+ out.writeInt(mWidth);
+ out.writeInt(mHeight);
+ TextUtils.writeToParcel(mTitle, out, 0);
+ out.writeInt(mDisplayId);
+ mRoot.writeToParcel(out, pwriter);
+ }
+
+ /**
+ * Returns the left edge of the window, in pixels, relative to the left
+ * edge of the screen.
+ */
+ public int getLeft() {
+ return mX;
+ }
+
+ /**
+ * Returns the top edge of the window, in pixels, relative to the top
+ * edge of the screen.
+ */
+ public int getTop() {
+ return mY;
+ }
+
+ /**
+ * Returns the total width of the window in pixels.
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Returns the total height of the window in pixels.
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Returns the title associated with the window, if it has one.
+ */
+ public CharSequence getTitle() {
+ return mTitle;
+ }
+
+ /**
+ * Returns the ID of the display this window is on, for use with
+ * {@link android.hardware.display.DisplayManager#getDisplay DisplayManager.getDisplay()}.
+ */
+ public int getDisplayId() {
+ return mDisplayId;
+ }
+
+ /**
+ * Returns the {@link ViewNode} containing the root content of the window.
+ */
+ public ViewNode getRootViewNode() {
+ return mRoot;
+ }
+ }
+
+ /**
+ * Describes a single view in the assist data.
+ */
+ static public class ViewNode {
+ /**
+ * Magic value for text color that has not been defined, which is very unlikely
+ * to be confused with a real text color.
+ */
+ public static final int TEXT_COLOR_UNDEFINED = 1;
+
+ public static final int TEXT_STYLE_BOLD = 1<<0;
+ public static final int TEXT_STYLE_ITALIC = 1<<1;
+ public static final int TEXT_STYLE_UNDERLINE = 1<<2;
+ public static final int TEXT_STYLE_STRIKE_THRU = 1<<3;
+
+ int mId;
+ String mIdPackage;
+ String mIdType;
+ String mIdEntry;
+ int mX;
+ int mY;
+ int mScrollX;
+ int mScrollY;
+ int mWidth;
+ int mHeight;
+
+ static final int FLAGS_DISABLED = 0x00000001;
+ static final int FLAGS_VISIBILITY_MASK = View.VISIBLE|View.INVISIBLE|View.GONE;
+ static final int FLAGS_FOCUSABLE = 0x00000010;
+ static final int FLAGS_FOCUSED = 0x00000020;
+ static final int FLAGS_ACCESSIBILITY_FOCUSED = 0x04000000;
+ static final int FLAGS_SELECTED = 0x00000040;
+ static final int FLAGS_ASSIST_BLOCKED = 0x00000080;
+ static final int FLAGS_ACTIVATED = 0x40000000;
+ static final int FLAGS_CHECKABLE = 0x00000100;
+ static final int FLAGS_CHECKED = 0x00000200;
+ static final int FLAGS_CLICKABLE = 0x00004000;
+ static final int FLAGS_LONG_CLICKABLE = 0x00200000;
+ static final int FLAGS_CONTEXT_CLICKABLE = 0x00400000;
+
+ int mFlags;
+
+ String mClassName;
+ CharSequence mContentDescription;
+
+ ViewNodeText mText;
+ Bundle mExtras;
+
+ ViewNode[] mChildren;
+
+ ViewNode() {
+ }
+
+ ViewNode(Parcel in, PooledStringReader preader) {
+ mId = in.readInt();
+ if (mId != 0) {
+ mIdEntry = preader.readString();
+ if (mIdEntry != null) {
+ mIdType = preader.readString();
+ mIdPackage = preader.readString();
+ } else {
+ mIdPackage = mIdType = null;
+ }
+ } else {
+ mIdPackage = mIdType = mIdEntry = null;
+ }
+ mX = in.readInt();
+ mY = in.readInt();
+ mScrollX = in.readInt();
+ mScrollY = in.readInt();
+ mWidth = in.readInt();
+ mHeight = in.readInt();
+ mFlags = in.readInt();
+ mClassName = preader.readString();
+ mContentDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ if (in.readInt() != 0) {
+ mText = new ViewNodeText(in);
+ } else {
+ mText = null;
+ }
+ mExtras = in.readBundle();
+ final int NCHILDREN = in.readInt();
+ if (NCHILDREN > 0) {
+ mChildren = new ViewNode[NCHILDREN];
+ for (int i=0; i<NCHILDREN; i++) {
+ mChildren[i] = new ViewNode(in, preader);
+ }
+ } else {
+ mChildren = null;
+ }
+ }
+
+ void writeToParcel(Parcel out, PooledStringWriter pwriter) {
+ out.writeInt(mId);
+ if (mId != 0) {
+ pwriter.writeString(mIdEntry);
+ if (mIdEntry != null) {
+ pwriter.writeString(mIdType);
+ pwriter.writeString(mIdPackage);
+ }
+ }
+ out.writeInt(mX);
+ out.writeInt(mY);
+ out.writeInt(mScrollX);
+ out.writeInt(mScrollY);
+ out.writeInt(mWidth);
+ out.writeInt(mHeight);
+ out.writeInt(mFlags);
+ pwriter.writeString(mClassName);
+ TextUtils.writeToParcel(mContentDescription, out, 0);
+ if (mText != null) {
+ out.writeInt(1);
+ mText.writeToParcel(out);
+ } else {
+ out.writeInt(0);
+ }
+ out.writeBundle(mExtras);
+ if (mChildren != null) {
+ final int NCHILDREN = mChildren.length;
+ out.writeInt(NCHILDREN);
+ for (int i=0; i<NCHILDREN; i++) {
+ mChildren[i].writeToParcel(out, pwriter);
+ }
+ } else {
+ out.writeInt(0);
+ }
+ }
+
+ /**
+ * Returns the ID associated with this view, as per {@link View#getId() View.getId()}.
+ */
+ public int getId() {
+ return mId;
+ }
+
+ /**
+ * If {@link #getId()} is a resource identifier, this is the package name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
+ public String getIdPackage() {
+ return mIdPackage;
+ }
+
+ /**
+ * If {@link #getId()} is a resource identifier, this is the type name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
+ public String getIdType() {
+ return mIdType;
+ }
+
+ /**
+ * If {@link #getId()} is a resource identifier, this is the entry name of that
+ * identifier. See {@link android.view.ViewStructure#setId ViewStructure.setId}
+ * for more information.
+ */
+ public String getIdEntry() {
+ return mIdEntry;
+ }
+
+ /**
+ * Returns the left edge of this view, in pixels, relative to the left edge of its parent.
+ */
+ public int getLeft() {
+ return mX;
+ }
+
+ /**
+ * Returns the top edge of this view, in pixels, relative to the top edge of its parent.
+ */
+ public int getTop() {
+ return mY;
+ }
+
+ /**
+ * Returns the current X scroll offset of this view, as per
+ * {@link android.view.View#getScrollX() View.getScrollX()}.
+ */
+ public int getScrollX() {
+ return mScrollX;
+ }
+
+ /**
+ * Returns the current Y scroll offset of this view, as per
+ * {@link android.view.View#getScrollX() View.getScrollY()}.
+ */
+ public int getScrollY() {
+ return mScrollY;
+ }
+
+ /**
+ * Returns the width of this view, in pixels.
+ */
+ public int getWidth() {
+ return mWidth;
+ }
+
+ /**
+ * Returns the height of this view, in pixels.
+ */
+ public int getHeight() {
+ return mHeight;
+ }
+
+ /**
+ * Returns the visibility mode of this view, as per
+ * {@link android.view.View#getVisibility() View.getVisibility()}.
+ */
+ public int getVisibility() {
+ return mFlags&ViewNode.FLAGS_VISIBILITY_MASK;
+ }
+
+ /**
+ * Returns true if assist data has been blocked starting at this node in the hierarchy.
+ */
+ public boolean isAssistBlocked() {
+ return (mFlags&ViewNode.FLAGS_ASSIST_BLOCKED) == 0;
+ }
+
+ /**
+ * Returns true if this node is in an enabled state.
+ */
+ public boolean isEnabled() {
+ return (mFlags&ViewNode.FLAGS_DISABLED) == 0;
+ }
+
+ /**
+ * Returns true if this node is clickable by the user.
+ */
+ public boolean isClickable() {
+ return (mFlags&ViewNode.FLAGS_CLICKABLE) != 0;
+ }
+
+ /**
+ * Returns true if this node can take input focus.
+ */
+ public boolean isFocusable() {
+ return (mFlags&ViewNode.FLAGS_FOCUSABLE) != 0;
+ }
+
+ /**
+ * Returns true if this node currently had input focus at the time that the
+ * structure was collected.
+ */
+ public boolean isFocused() {
+ return (mFlags&ViewNode.FLAGS_FOCUSED) != 0;
+ }
+
+ /**
+ * Returns true if this node currently had accessibility focus at the time that the
+ * structure was collected.
+ */
+ public boolean isAccessibilityFocused() {
+ return (mFlags&ViewNode.FLAGS_ACCESSIBILITY_FOCUSED) != 0;
+ }
+
+ /**
+ * Returns true if this node represents something that is checkable by the user.
+ */
+ public boolean isCheckable() {
+ return (mFlags&ViewNode.FLAGS_CHECKABLE) != 0;
+ }
+
+ /**
+ * Returns true if this node is currently in a checked state.
+ */
+ public boolean isChecked() {
+ return (mFlags&ViewNode.FLAGS_CHECKED) != 0;
+ }
+
+ /**
+ * Returns true if this node has currently been selected by the user.
+ */
+ public boolean isSelected() {
+ return (mFlags&ViewNode.FLAGS_SELECTED) != 0;
+ }
+
+ /**
+ * Returns true if this node has currently been activated by the user.
+ */
+ public boolean isActivated() {
+ return (mFlags&ViewNode.FLAGS_ACTIVATED) != 0;
+ }
+
+ /**
+ * Returns true if this node is something the user can perform a long click/press on.
+ */
+ public boolean isLongClickable() {
+ return (mFlags&ViewNode.FLAGS_LONG_CLICKABLE) != 0;
+ }
+
+ /**
+ * Returns true if this node is something the user can perform a context click on.
+ */
+ public boolean isContextClickable() {
+ return (mFlags&ViewNode.FLAGS_CONTEXT_CLICKABLE) != 0;
+ }
+
+ /**
+ * Returns the class name of the node's implementation, indicating its behavior.
+ * For example, a button will report "android.widget.Button" meaning it behaves
+ * like a {@link android.widget.Button}.
+ */
+ public String getClassName() {
+ return mClassName;
+ }
+
+ /**
+ * Returns any content description associated with the node, which semantically describes
+ * its purpose for accessibility and other uses.
+ */
+ public CharSequence getContentDescription() {
+ return mContentDescription;
+ }
+
+ /**
+ * Returns any text associated with the node that is displayed to the user, or null
+ * if there is none.
+ */
+ public CharSequence getText() {
+ return mText != null ? mText.mText : null;
+ }
+
+ /**
+ * If {@link #getText()} is non-null, this is where the current selection starts.
+ */
+ public int getTextSelectionStart() {
+ return mText != null ? mText.mTextSelectionStart : -1;
+ }
+
+ /**
+ * If {@link #getText()} is non-null, this is where the current selection starts.
+ * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
+ * indicating the cursor position.
+ */
+ public int getTextSelectionEnd() {
+ return mText != null ? mText.mTextSelectionEnd : -1;
+ }
+
+ /**
+ * If {@link #getText()} is non-null, this is the main text color associated with it.
+ * If there is no text color, {@link #TEXT_COLOR_UNDEFINED} is returned.
+ * Note that the text may also contain style spans that modify the color of specific
+ * parts of the text.
+ */
+ public int getTextColor() {
+ return mText != null ? mText.mTextColor : TEXT_COLOR_UNDEFINED;
+ }
+
+ /**
+ * If {@link #getText()} is non-null, this is the main text background color associated
+ * with it.
+ * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
+ * Note that the text may also contain style spans that modify the color of specific
+ * parts of the text.
+ */
+ public int getTextBackgroundColor() {
+ return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
+ }
+
+ /**
+ * If {@link #getText()} is non-null, this is the main text size (in pixels) associated
+ * with it.
+ * Note that the text may also contain style spans that modify the size of specific
+ * parts of the text.
+ */
+ public float getTextSize() {
+ return mText != null ? mText.mTextSize : 0;
+ }
+
+ /**
+ * If {@link #getText()} is non-null, this is the main text style associated
+ * with it, containing a bit mask of {@link #TEXT_STYLE_BOLD},
+ * {@link #TEXT_STYLE_BOLD}, {@link #TEXT_STYLE_STRIKE_THRU}, and/or
+ * {@link #TEXT_STYLE_UNDERLINE}.
+ * Note that the text may also contain style spans that modify the style of specific
+ * parts of the text.
+ */
+ public int getTextStyle() {
+ return mText != null ? mText.mTextStyle : 0;
+ }
+
+ /**
+ * Return additional hint text associated with the node; this is typically used with
+ * a node that takes user input, describing to the user what the input means.
+ */
+ public String getHint() {
+ return mText != null ? mText.mHint : null;
+ }
+
+ /**
+ * Return a Bundle containing optional vendor-specific extension information.
+ */
+ public Bundle getExtras() {
+ return mExtras;
+ }
+
+ /**
+ * Return the number of children this node has.
+ */
+ public int getChildCount() {
+ return mChildren != null ? mChildren.length : 0;
+ }
+
+ /**
+ * Return a child of this node, given an index value from 0 to
+ * {@link #getChildCount()}-1.
+ */
+ public ViewNode getChildAt(int index) {
+ return mChildren[index];
+ }
+ }
+
+ static class ViewNodeBuilder extends ViewAssistStructure {
+ final AssistStructure mAssist;
+ final ViewNode mNode;
+ final boolean mAsync;
+
+ ViewNodeBuilder(AssistStructure assist, ViewNode node, boolean async) {
+ mAssist = assist;
+ mNode = node;
+ mAsync = async;
+ }
+
+ @Override
+ public void setId(int id, String packageName, String typeName, String entryName) {
+ mNode.mId = id;
+ mNode.mIdPackage = packageName;
+ mNode.mIdType = typeName;
+ mNode.mIdEntry = entryName;
+ }
+
+ @Override
+ public void setDimens(int left, int top, int scrollX, int scrollY, int width, int height) {
+ mNode.mX = left;
+ mNode.mY = top;
+ mNode.mScrollX = scrollX;
+ mNode.mScrollY = scrollY;
+ mNode.mWidth = width;
+ mNode.mHeight = height;
+ }
+
+ @Override
+ public void setVisibility(int visibility) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_VISIBILITY_MASK) | visibility;
+ }
+
+ @Override
+ public void setAssistBlocked(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ASSIST_BLOCKED)
+ | (state ? 0 : ViewNode.FLAGS_ASSIST_BLOCKED);
+ }
+
+ @Override
+ public void setEnabled(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_DISABLED)
+ | (state ? 0 : ViewNode.FLAGS_DISABLED);
+ }
+
+ @Override
+ public void setClickable(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CLICKABLE)
+ | (state ? ViewNode.FLAGS_CLICKABLE : 0);
+ }
+
+ @Override
+ public void setLongClickable(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_LONG_CLICKABLE)
+ | (state ? ViewNode.FLAGS_LONG_CLICKABLE : 0);
+ }
+
+ @Override
+ public void setContextClickable(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CONTEXT_CLICKABLE)
+ | (state ? ViewNode.FLAGS_CONTEXT_CLICKABLE : 0);
+ }
+
+ @Override
+ public void setFocusable(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSABLE)
+ | (state ? ViewNode.FLAGS_FOCUSABLE : 0);
+ }
+
+ @Override
+ public void setFocused(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_FOCUSED)
+ | (state ? ViewNode.FLAGS_FOCUSED : 0);
+ }
+
+ @Override
+ public void setAccessibilityFocused(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACCESSIBILITY_FOCUSED)
+ | (state ? ViewNode.FLAGS_ACCESSIBILITY_FOCUSED : 0);
+ }
+
+ @Override
+ public void setCheckable(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKABLE)
+ | (state ? ViewNode.FLAGS_CHECKABLE : 0);
+ }
+
+ @Override
+ public void setChecked(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_CHECKED)
+ | (state ? ViewNode.FLAGS_CHECKED : 0);
+ }
+
+ @Override
+ public void setSelected(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_SELECTED)
+ | (state ? ViewNode.FLAGS_SELECTED : 0);
+ }
+
+ @Override
+ public void setActivated(boolean state) {
+ mNode.mFlags = (mNode.mFlags&~ViewNode.FLAGS_ACTIVATED)
+ | (state ? ViewNode.FLAGS_ACTIVATED : 0);
+ }
+
+ @Override
+ public void setClassName(String className) {
+ mNode.mClassName = className;
+ }
+
+ @Override
+ public void setContentDescription(CharSequence contentDescription) {
+ mNode.mContentDescription = contentDescription;
+ }
+
+ private final ViewNodeText getNodeText() {
+ if (mNode.mText != null) {
+ return mNode.mText;
+ }
+ mNode.mText = new ViewNodeText();
+ return mNode.mText;
+ }
+
+ @Override
+ public void setText(CharSequence text) {
+ ViewNodeText t = getNodeText();
+ t.mText = text;
+ t.mTextSelectionStart = t.mTextSelectionEnd = -1;
+ }
+
+ @Override
+ public void setText(CharSequence text, int selectionStart, int selectionEnd) {
+ ViewNodeText t = getNodeText();
+ t.mText = text;
+ t.mTextSelectionStart = selectionStart;
+ t.mTextSelectionEnd = selectionEnd;
+ }
+
+ @Override
+ public void setTextStyle(float size, int fgColor, int bgColor, int style) {
+ ViewNodeText t = getNodeText();
+ t.mTextColor = fgColor;
+ t.mTextBackgroundColor = bgColor;
+ t.mTextSize = size;
+ t.mTextStyle = style;
+ }
+
+ @Override
+ public void setHint(CharSequence hint) {
+ getNodeText().mHint = hint != null ? hint.toString() : null;
+ }
+
+ @Override
+ public CharSequence getText() {
+ return mNode.mText != null ? mNode.mText.mText : null;
+ }
+
+ @Override
+ public int getTextSelectionStart() {
+ return mNode.mText != null ? mNode.mText.mTextSelectionStart : -1;
+ }
+
+ @Override
+ public int getTextSelectionEnd() {
+ return mNode.mText != null ? mNode.mText.mTextSelectionEnd : -1;
+ }
+
+ @Override
+ public CharSequence getHint() {
+ return mNode.mText != null ? mNode.mText.mHint : null;
+ }
+
+ @Override
+ public Bundle getExtras() {
+ if (mNode.mExtras != null) {
+ return mNode.mExtras;
+ }
+ mNode.mExtras = new Bundle();
+ return mNode.mExtras;
+ }
+
+ @Override
+ public boolean hasExtras() {
+ return mNode.mExtras != null;
+ }
+
+ @Override
+ public void setChildCount(int num) {
+ mNode.mChildren = new ViewNode[num];
+ }
+
+ @Override
+ public int addChildCount(int num) {
+ if (mNode.mChildren == null) {
+ setChildCount(num);
+ return 0;
+ }
+ final int start = mNode.mChildren.length;
+ ViewNode[] newArray = new ViewNode[start + num];
+ System.arraycopy(mNode.mChildren, 0, newArray, 0, start);
+ mNode.mChildren = newArray;
+ return start;
+ }
+
+ @Override
+ public int getChildCount() {
+ return mNode.mChildren != null ? mNode.mChildren.length : 0;
+ }
+
+ @Override
+ public ViewAssistStructure newChild(int index) {
+ ViewNode node = new ViewNode();
+ mNode.mChildren[index] = node;
+ return new ViewNodeBuilder(mAssist, node, false);
+ }
+
+ @Override
+ public ViewAssistStructure asyncNewChild(int index) {
+ synchronized (mAssist) {
+ ViewNode node = new ViewNode();
+ mNode.mChildren[index] = node;
+ ViewNodeBuilder builder = new ViewNodeBuilder(mAssist, node, true);
+ mAssist.mPendingAsyncChildren.add(builder);
+ return builder;
+ }
+ }
+
+ @Override
+ public void asyncCommit() {
+ synchronized (mAssist) {
+ if (!mAsync) {
+ throw new IllegalStateException("Child " + this
+ + " was not created with ViewAssistStructure.asyncNewChild");
+ }
+ if (!mAssist.mPendingAsyncChildren.remove(this)) {
+ throw new IllegalStateException("Child " + this + " already committed");
+ }
+ mAssist.notifyAll();
+ }
+ }
+
+ @Override
+ public Rect getTempRect() {
+ return mAssist.mTmpRect;
+ }
}
/** @hide */
public AssistStructure(Activity activity) {
- super(activity);
+ mHaveData = true;
+ mActivityComponent = activity.getComponentName();
+ ArrayList<ViewRootImpl> views = WindowManagerGlobal.getInstance().getRootViews(
+ activity.getActivityToken());
+ for (int i=0; i<views.size(); i++) {
+ ViewRootImpl root = views.get(i);
+ mWindowNodes.add(new WindowNode(this, root));
+ }
+ }
+
+ public AssistStructure() {
+ mHaveData = true;
+ mActivityComponent = null;
}
- AssistStructure(Parcel in) {
- super(in);
+ /** @hide */
+ public AssistStructure(Parcel in) {
+ mReceiveChannel = in.readStrongBinder();
}
+ /** @hide */
+ public void dump() {
+ Log.i(TAG, "Activity: " + mActivityComponent.flattenToShortString());
+ final int N = getWindowNodeCount();
+ for (int i=0; i<N; i++) {
+ WindowNode node = getWindowNodeAt(i);
+ Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
+ + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
+ dump(" ", node.getRootViewNode());
+ }
+ }
+
+ void dump(String prefix, ViewNode node) {
+ Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
+ + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
+ int id = node.getId();
+ if (id != 0) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(prefix); sb.append(" ID: #"); sb.append(Integer.toHexString(id));
+ String entry = node.getIdEntry();
+ if (entry != null) {
+ String type = node.getIdType();
+ String pkg = node.getIdPackage();
+ sb.append(" "); sb.append(pkg); sb.append(":"); sb.append(type);
+ sb.append("/"); sb.append(entry);
+ }
+ Log.i(TAG, sb.toString());
+ }
+ int scrollX = node.getScrollX();
+ int scrollY = node.getScrollY();
+ if (scrollX != 0 || scrollY != 0) {
+ Log.i(TAG, prefix + " Scroll: " + scrollX + "," + scrollY);
+ }
+ CharSequence contentDescription = node.getContentDescription();
+ if (contentDescription != null) {
+ Log.i(TAG, prefix + " Content description: " + contentDescription);
+ }
+ CharSequence text = node.getText();
+ if (text != null) {
+ Log.i(TAG, prefix + " Text (sel " + node.getTextSelectionStart() + "-"
+ + node.getTextSelectionEnd() + "): " + text);
+ Log.i(TAG, prefix + " Text size: " + node.getTextSize() + " , style: #"
+ + node.getTextStyle());
+ Log.i(TAG, prefix + " Text color fg: #" + Integer.toHexString(node.getTextColor())
+ + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
+ }
+ String hint = node.getHint();
+ if (hint != null) {
+ Log.i(TAG, prefix + " Hint: " + hint);
+ }
+ Bundle extras = node.getExtras();
+ if (extras != null) {
+ Log.i(TAG, prefix + " Extras: " + extras);
+ }
+ final int NCHILDREN = node.getChildCount();
+ if (NCHILDREN > 0) {
+ Log.i(TAG, prefix + " Children:");
+ String cprefix = prefix + " ";
+ for (int i=0; i<NCHILDREN; i++) {
+ ViewNode cnode = node.getChildAt(i);
+ dump(cprefix, cnode);
+ }
+ }
+ }
+
+ /**
+ * Return the activity this AssistStructure came from.
+ */
+ public ComponentName getActivityComponent() {
+ ensureData();
+ return mActivityComponent;
+ }
+
+ /**
+ * Return the number of window contents that have been collected in this assist data.
+ */
+ public int getWindowNodeCount() {
+ ensureData();
+ return mWindowNodes.size();
+ }
+
+ /**
+ * Return one of the windows in the assist data.
+ * @param index Which window to retrieve, may be 0 to {@link #getWindowNodeCount()}-1.
+ */
public WindowNode getWindowNodeAt(int index) {
- return super.getWindowNodeAt(index);
+ ensureData();
+ return mWindowNodes.get(index);
+ }
+
+ /** @hide */
+ public void ensureData() {
+ if (mHaveData) {
+ return;
+ }
+ mHaveData = true;
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInterfaceToken(DESCRIPTOR);
+ try {
+ mReceiveChannel.transact(TRANSACTION_XFER, data, reply, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failure reading AssistStructure data", e);
+ return;
+ }
+ readContentFromParcel(reply);
+ data.recycle();
+ reply.recycle();
+ }
+
+ void writeContentToParcel(Parcel out, int flags) {
+ // First make sure all content has been created.
+ boolean skipStructure = false;
+ synchronized (this) {
+ long endTime = SystemClock.uptimeMillis() + 5000;
+ long now;
+ while (mPendingAsyncChildren.size() > 0 && (now=SystemClock.uptimeMillis()) < endTime) {
+ try {
+ wait(endTime-now);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (mPendingAsyncChildren.size() > 0) {
+ // We waited too long, assume none of the assist structure is valid.
+ skipStructure = true;
+ }
+ }
+ int start = out.dataPosition();
+ PooledStringWriter pwriter = new PooledStringWriter(out);
+ ComponentName.writeToParcel(mActivityComponent, out);
+ final int N = skipStructure ? 0 : mWindowNodes.size();
+ out.writeInt(N);
+ for (int i=0; i<N; i++) {
+ mWindowNodes.get(i).writeToParcel(out, pwriter);
+ }
+ pwriter.finish();
+ Log.i(TAG, "Flattened assist data: " + (out.dataPosition() - start) + " bytes");
+ }
+
+ void readContentFromParcel(Parcel in) {
+ PooledStringReader preader = new PooledStringReader(in);
+ mActivityComponent = ComponentName.readFromParcel(in);
+ final int N = in.readInt();
+ for (int i=0; i<N; i++) {
+ mWindowNodes.add(new WindowNode(in, preader));
+ }
+ //dump();
}
public int describeContents() {
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index 8a31390..9113426 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -77,6 +77,12 @@ public abstract class UsageStatsManagerInternal {
public abstract boolean isAppIdle(String packageName, int userId);
/**
+ * @return True if currently app idle parole mode is on. This means all idle apps are allow to
+ * run for a short period of time.
+ */
+ public abstract boolean isAppIdleParoleOn();
+
+ /**
* Sets up a listener for changes to packages being accessed.
* @param listener A listener within the system process.
*/
@@ -90,8 +96,9 @@ public abstract class UsageStatsManagerInternal {
public abstract void removeAppIdleStateChangeListener(
AppIdleStateChangeListener listener);
- public interface AppIdleStateChangeListener {
- void onAppIdleStateChanged(String packageName, int userId, boolean idle);
+ public static abstract class AppIdleStateChangeListener {
+ public abstract void onAppIdleStateChanged(String packageName, int userId, boolean idle);
+ public abstract void onParoleStateChanged(boolean isParoleOn);
}
}
diff --git a/core/java/android/content/AbstractThreadedSyncAdapter.java b/core/java/android/content/AbstractThreadedSyncAdapter.java
index d4dee5b..58bd5cd 100644
--- a/core/java/android/content/AbstractThreadedSyncAdapter.java
+++ b/core/java/android/content/AbstractThreadedSyncAdapter.java
@@ -274,6 +274,10 @@ public abstract class AbstractThreadedSyncAdapter {
} else {
syncResult.databaseError = true;
}
+ } catch (SecurityException e) {
+ AbstractThreadedSyncAdapter.this.onSecurityException(mAccount, mExtras,
+ mAuthority, syncResult);
+ syncResult.databaseError = true;
} finally {
Trace.traceEnd(Trace.TRACE_TAG_SYNC_MANAGER);
@@ -319,6 +323,20 @@ public abstract class AbstractThreadedSyncAdapter {
String authority, ContentProviderClient provider, SyncResult syncResult);
/**
+ * Report that there was a security exception when opening the content provider
+ * prior to calling {@link #onPerformSync}. This will be treated as a sync
+ * database failure.
+ *
+ * @param account the account that attempted to sync
+ * @param extras SyncAdapter-specific parameters
+ * @param authority the authority of the failed sync request
+ * @param syncResult SyncAdapter-specific parameters
+ */
+ public void onSecurityException(Account account, Bundle extras,
+ String authority, SyncResult syncResult) {
+ }
+
+ /**
* Indicates that a sync operation has been canceled. This will be invoked on a separate
* thread than the sync thread and so you must consider the multi-threaded implications
* of the work that you do in this method.
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 2dbcde9..34e4701 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -106,6 +106,8 @@ interface IPackageManager {
void updatePermissionFlags(String permissionName, String packageName, int flagMask,
int flagValues, int userId);
+ void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId);
+
boolean shouldShowRequestPermissionRationale(String permissionName,
String packageName, int userId);
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 27d14b3..a88b71c 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -628,7 +628,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
/**
* <p>List of available high speed video size, fps range and max batch size configurations
* supported by the camera device, in the format of (width, height, fps_min, fps_max, batch_size_max).</p>
- * <p>When CONSTRAINED_HIGH_SPEED_VIDEO is supported in android.control.availableCapabilities,
+ * <p>When CONSTRAINED_HIGH_SPEED_VIDEO is supported in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities},
* this metadata will list the supported high speed video size, fps range and max batch size
* configurations. All the sizes listed in this configuration will be a subset of the sizes
* reported by {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes }
@@ -675,6 +675,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
*
* @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+ * @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
* @hide
*/
public static final Key<android.hardware.camera2.params.HighSpeedVideoConfiguration[]> CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS =
@@ -2679,9 +2680,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <p>Camera devices will come in three flavors: LEGACY, LIMITED and FULL.</p>
* <p>A FULL device will support below capabilities:</p>
* <ul>
- * <li>30fps operation at maximum resolution (== sensor resolution) is preferred, more than
- * 20fps is required, for at least uncompressed YUV
- * output. ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains BURST_CAPTURE)</li>
+ * <li>BURST_CAPTURE capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains BURST_CAPTURE)</li>
* <li>Per frame control ({@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} <code>==</code> PER_FRAME_CONTROL)</li>
* <li>Manual sensor control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains MANUAL_SENSOR)</li>
* <li>Manual post-processing control ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES android.request.availableCapabilities} contains
@@ -2689,7 +2688,7 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* <li>Arbitrary cropping region ({@link CameraCharacteristics#SCALER_CROPPING_TYPE android.scaler.croppingType} <code>==</code> FREEFORM)</li>
* <li>At least 3 processed (but not stalling) format output streams
* ({@link CameraCharacteristics#REQUEST_MAX_NUM_OUTPUT_PROC android.request.maxNumOutputProc} <code>&gt;=</code> 3)</li>
- * <li>The required stream configuration defined in android.scaler.availableStreamConfigurations</li>
+ * <li>The required stream configurations defined in android.scaler.availableStreamConfigurations</li>
* <li>The required exposure time range defined in {@link CameraCharacteristics#SENSOR_INFO_EXPOSURE_TIME_RANGE android.sensor.info.exposureTimeRange}</li>
* <li>The required maxFrameDuration defined in {@link CameraCharacteristics#SENSOR_INFO_MAX_FRAME_DURATION android.sensor.info.maxFrameDuration}</li>
* </ul>
@@ -2709,23 +2708,11 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* post-processing, arbitrary cropping regions, and has relaxed performance constraints.</p>
* <p>Each higher level supports everything the lower level supports
* in this order: FULL <code>&gt;</code> LIMITED <code>&gt;</code> LEGACY.</p>
- * <p>A HIGH_RESOLUTION device is equivalent to a FULL device, except that:</p>
- * <ul>
- * <li>At least one output resolution of 8 megapixels or higher in uncompressed YUV is
- * supported at <code>&gt;=</code> 20 fps.</li>
- * <li>Maximum-size (sensor resolution) uncompressed YUV is supported at <code>&gt;=</code> 10
- * fps.</li>
- * <li>For devices that list the RAW capability and support either RAW10 or RAW12 output,
- * maximum-resolution RAW10 or RAW12 capture will operate at least at the rate of
- * maximum-resolution YUV capture, and at least one supported output resolution of
- * 8 megapixels or higher in RAW10 or RAW12 is supported <code>&gt;=</code> 20 fps.</li>
- * </ul>
* <p><b>Possible values:</b>
* <ul>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED LIMITED}</li>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}</li>
* <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY LEGACY}</li>
- * <li>{@link #INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION HIGH_RESOLUTION}</li>
* </ul></p>
* <p>This key is available on all devices.</p>
*
@@ -2743,7 +2730,6 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_FULL
* @see #INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY
- * @see #INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION
*/
@PublicKey
public static final Key<Integer> INFO_SUPPORTED_HARDWARE_LEVEL =
diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index c656fb8..5a80585 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -531,37 +531,32 @@ public abstract class CameraMetadata<TKey> {
public static final int REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS = 5;
/**
- * <p>The camera device supports capturing maximum-resolution
- * images at &gt;= 20 frames per second, in at least the
- * uncompressed YUV format, when post-processing settings
- * are set to FAST.</p>
- * <p>More specifically, this means that a size matching the
- * camera device's active array size is listed as a
- * supported size for the YUV_420_888 format in
- * {@link CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP android.scaler.streamConfigurationMap}, the minimum frame
- * duration for that format and size is &lt;= 1/20 s, and
- * the {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges} entry
- * lists at least one FPS range where the minimum FPS is</p>
- * <blockquote>
- * <p>= 1 / minimumFrameDuration for the maximum-size
- * YUV_420_888 format.</p>
- * </blockquote>
- * <p>In addition, the {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} field is
- * guaranted to have a value between 0 and 4, inclusive.
- * {@link CameraCharacteristics#CONTROL_AE_LOCK_AVAILABLE android.control.aeLockAvailable} and
- * {@link CameraCharacteristics#CONTROL_AWB_LOCK_AVAILABLE android.control.awbLockAvailable} are also guaranteed
- * to be <code>true</code> so burst capture with these two locks ON
- * yields consistent image output.</p>
- * <p>On a camera device that reports the HIGH_RESOLUTION hardware
- * level, meaning the device supports very large capture sizes,
- * BURST_CAPTURE means that at least 8-megapixel images can be
- * captured at <code>&gt;=</code> 20 fps, and maximum-resolution images can be
- * captured at <code>&gt;=</code> 10 fps.</p>
+ * <p>The camera device supports capturing high-resolution images at &gt;= 20 frames per
+ * second, in at least the uncompressed YUV format, when post-processing settings are set
+ * to FAST. Additionally, maximum-resolution images can be captured at &gt;= 10 frames
+ * per second. Here, 'high resolution' means at least 8 megapixels, or the maximum
+ * resolution of the device, whichever is smaller.</p>
+ * <p>More specifically, this means that a size matching the camera device's active array
+ * size is listed as a supported size for the {@link android.graphics.ImageFormat#YUV_420_888 } format in either {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } or {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes },
+ * with a minimum frame duration for that format and size of either &lt;= 1/20 s, or
+ * &lt;= 1/10 s, respectively; and the {@link CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES android.control.aeAvailableTargetFpsRanges} entry
+ * lists at least one FPS range where the minimum FPS is &gt;= 1 / minimumFrameDuration
+ * for the maximum-size YUV_420_888 format. If that maximum size is listed in {@link android.hardware.camera2.params.StreamConfigurationMap#getHighResolutionOutputSizes },
+ * then the list of resolutions for YUV_420_888 from {@link android.hardware.camera2.params.StreamConfigurationMap#getOutputSizes } contains at
+ * least one resolution &gt;= 8 megapixels, with a minimum frame duration of &lt;= 1/20
+ * s.</p>
+ * <p>If the device supports the {@link android.graphics.ImageFormat#RAW10 }, {@link android.graphics.ImageFormat#RAW12 }, then those can also be captured at the same rate
+ * as the maximum-size YUV_420_888 resolution is.</p>
+ * <p>If the device supports the PRIVATE_REPROCESSING capability, then the same guarantees
+ * as for the YUV_420_888 format also apply to the {@link android.graphics.ImageFormat#PRIVATE } format.</p>
+ * <p>In addition, the {@link CameraCharacteristics#SYNC_MAX_LATENCY android.sync.maxLatency} field is guaranted to have a value between 0
+ * and 4, inclusive. {@link CameraCharacteristics#CONTROL_AE_LOCK_AVAILABLE android.control.aeLockAvailable} and {@link CameraCharacteristics#CONTROL_AWB_LOCK_AVAILABLE android.control.awbLockAvailable}
+ * are also guaranteed to be <code>true</code> so burst capture with these two locks ON yields
+ * consistent image output.</p>
*
* @see CameraCharacteristics#CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES
* @see CameraCharacteristics#CONTROL_AE_LOCK_AVAILABLE
* @see CameraCharacteristics#CONTROL_AWB_LOCK_AVAILABLE
- * @see CameraCharacteristics#SCALER_STREAM_CONFIGURATION_MAP
* @see CameraCharacteristics#SYNC_MAX_LATENCY
* @see CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES
*/
@@ -954,13 +949,6 @@ public abstract class CameraMetadata<TKey> {
*/
public static final int INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY = 2;
- /**
- * <p>This camera device is capable of supporting advanced imaging applications at full rate,
- * and additional high-resolution outputs at lower rates.</p>
- * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
- */
- public static final int INFO_SUPPORTED_HARDWARE_LEVEL_HIGH_RESOLUTION = 3;
-
//
// Enumeration values for CameraCharacteristics#SYNC_MAX_LATENCY
//
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 9fa6687..75289f7 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -398,7 +398,7 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
@Override
public int hashCode() {
- return HashCodeHelpers.hashCode(mSettings, mSurfaceSet, mUserTag);
+ return HashCodeHelpers.hashCodeGeneric(mSettings, mSurfaceSet, mUserTag);
}
public static final Parcelable.Creator<CaptureRequest> CREATOR =
@@ -1759,11 +1759,24 @@ public final class CaptureRequest extends CameraMetadata<CaptureRequest.Key<?>>
* 16:9 aspect ratio, the primary image will be cropped vertically (letterbox) to
* generate the thumbnail image. The thumbnail image will always have a smaller Field
* Of View (FOV) than the primary image when aspect ratios differ.</p>
+ * <p>When an {@link CaptureRequest#JPEG_ORIENTATION android.jpeg.orientation} of non-zero degree is requested,
+ * the camera device will handle thumbnail rotation in one of the following ways:</p>
+ * <ul>
+ * <li>Set the {@link android.media.ExifInterface#TAG_ORIENTATION EXIF orientation flag}
+ * and keep jpeg and thumbnail image data unrotated.</li>
+ * <li>Rotate the jpeg and thumbnail image data and not set
+ * {@link android.media.ExifInterface#TAG_ORIENTATION EXIF orientation flag}. In this
+ * case, LIMITED or FULL hardware level devices will report rotated thumnail size in
+ * capture result, so the width and height will be interchanged if 90 or 270 degree
+ * orientation is requested. LEGACY device will always report unrotated thumbnail
+ * size.</li>
+ * </ul>
* <p><b>Range of valid values:</b><br>
* {@link CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES android.jpeg.availableThumbnailSizes}</p>
* <p>This key is available on all devices.</p>
*
* @see CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES
+ * @see CaptureRequest#JPEG_ORIENTATION
*/
@PublicKey
public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index b1fb615..1d31109 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2314,11 +2314,24 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> {
* 16:9 aspect ratio, the primary image will be cropped vertically (letterbox) to
* generate the thumbnail image. The thumbnail image will always have a smaller Field
* Of View (FOV) than the primary image when aspect ratios differ.</p>
+ * <p>When an {@link CaptureRequest#JPEG_ORIENTATION android.jpeg.orientation} of non-zero degree is requested,
+ * the camera device will handle thumbnail rotation in one of the following ways:</p>
+ * <ul>
+ * <li>Set the {@link android.media.ExifInterface#TAG_ORIENTATION EXIF orientation flag}
+ * and keep jpeg and thumbnail image data unrotated.</li>
+ * <li>Rotate the jpeg and thumbnail image data and not set
+ * {@link android.media.ExifInterface#TAG_ORIENTATION EXIF orientation flag}. In this
+ * case, LIMITED or FULL hardware level devices will report rotated thumnail size in
+ * capture result, so the width and height will be interchanged if 90 or 270 degree
+ * orientation is requested. LEGACY device will always report unrotated thumbnail
+ * size.</li>
+ * </ul>
* <p><b>Range of valid values:</b><br>
* {@link CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES android.jpeg.availableThumbnailSizes}</p>
* <p>This key is available on all devices.</p>
*
* @see CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES
+ * @see CaptureRequest#JPEG_ORIENTATION
*/
@PublicKey
public static final Key<android.util.Size> JPEG_THUMBNAIL_SIZE =
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 10dd8ae..7e50fd9 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -842,11 +842,19 @@ public class CameraMetadataNative implements Parcelable {
CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
ReprocessFormatsMap inputOutputFormatsMap = getBase(
CameraCharacteristics.SCALER_AVAILABLE_INPUT_OUTPUT_FORMATS_MAP);
-
+ int[] capabilities = getBase(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES);
+ boolean listHighResolution = false;
+ for (int capability : capabilities) {
+ if (capability == CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE) {
+ listHighResolution = true;
+ break;
+ }
+ }
return new StreamConfigurationMap(
configurations, minFrameDurations, stallDurations,
depthConfigurations, depthMinFrameDurations, depthStallDurations,
- highSpeedVideoConfigurations, inputOutputFormatsMap);
+ highSpeedVideoConfigurations, inputOutputFormatsMap,
+ listHighResolution);
}
private <T> Integer getMaxRegions(Key<T> key) {
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 2fb3203..e786707 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -605,6 +605,14 @@ public class LegacyCameraDevice implements AutoCloseable {
return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceType(surface));
}
+ /**
+ * Query the surface for its currently configured dataspace
+ */
+ public static int detectSurfaceDataspace(Surface surface) throws BufferQueueAbandonedException {
+ checkNotNull(surface);
+ return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface));
+ }
+
static void configureSurface(Surface surface, int width, int height,
int pixelFormat) throws BufferQueueAbandonedException {
checkNotNull(surface);
@@ -702,6 +710,8 @@ public class LegacyCameraDevice implements AutoCloseable {
private static native int nativeDetectSurfaceType(Surface surface);
+ private static native int nativeDetectSurfaceDataspace(Surface surface);
+
private static native int nativeDetectSurfaceDimens(Surface surface,
/*out*/int[/*2*/] dimens);
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index c6ea488..639ad60 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -20,14 +20,16 @@ import android.graphics.ImageFormat;
import android.graphics.PixelFormat;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.utils.HashCodeHelpers;
+import android.hardware.camera2.utils.SurfaceUtils;
import android.hardware.camera2.legacy.LegacyCameraDevice;
import android.hardware.camera2.legacy.LegacyMetadataMapper;
-import android.hardware.camera2.legacy.LegacyExceptionUtils.BufferQueueAbandonedException;
import android.view.Surface;
import android.util.Range;
import android.util.Size;
+import android.util.SparseIntArray;
import java.util.Arrays;
import java.util.HashMap;
@@ -79,7 +81,8 @@ public final class StreamConfigurationMap {
* @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
* @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if
* camera device does not support high speed video recording
- *
+ * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE
+ * and thus needs a separate list of slow high-resolution output sizes
* @throws NullPointerException if any of the arguments except highSpeedVideoConfigurations
* were {@code null} or any subelements were {@code null}
*
@@ -93,10 +96,12 @@ public final class StreamConfigurationMap {
StreamConfigurationDuration[] depthMinFrameDurations,
StreamConfigurationDuration[] depthStallDurations,
HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
- ReprocessFormatsMap inputOutputFormatsMap) {
+ ReprocessFormatsMap inputOutputFormatsMap,
+ boolean listHighResolution) {
mConfigurations = checkArrayElementsNotNull(configurations, "configurations");
mMinFrameDurations = checkArrayElementsNotNull(minFrameDurations, "minFrameDurations");
mStallDurations = checkArrayElementsNotNull(stallDurations, "stallDurations");
+ mListHighResolution = listHighResolution;
if (depthConfigurations == null) {
mDepthConfigurations = new StreamConfiguration[0];
@@ -120,15 +125,27 @@ public final class StreamConfigurationMap {
// For each format, track how many sizes there are available to configure
for (StreamConfiguration config : configurations) {
- HashMap<Integer, Integer> map = config.isOutput() ? mOutputFormats : mInputFormats;
-
- Integer count = map.get(config.getFormat());
-
- if (count == null) {
- count = 0;
+ int fmt = config.getFormat();
+ SparseIntArray map = null;
+ if (config.isOutput()) {
+ mAllOutputFormats.put(fmt, mAllOutputFormats.get(fmt) + 1);
+ long duration = 0;
+ if (mListHighResolution) {
+ for (StreamConfigurationDuration configurationDuration : mMinFrameDurations) {
+ if (configurationDuration.getFormat() == fmt &&
+ configurationDuration.getWidth() == config.getSize().getWidth() &&
+ configurationDuration.getHeight() == config.getSize().getHeight()) {
+ duration = configurationDuration.getDuration();
+ break;
+ }
+ }
+ }
+ map = duration <= DURATION_20FPS_NS ?
+ mOutputFormats : mHighResOutputFormats;
+ } else {
+ map = mInputFormats;
}
-
- map.put(config.getFormat(), count + 1);
+ map.put(fmt, map.get(fmt) + 1);
}
// For each depth format, track how many sizes there are available to configure
@@ -138,16 +155,11 @@ public final class StreamConfigurationMap {
continue;
}
- Integer count = mDepthOutputFormats.get(config.getFormat());
-
- if (count == null) {
- count = 0;
- }
-
- mDepthOutputFormats.put(config.getFormat(), count + 1);
+ mDepthOutputFormats.put(config.getFormat(),
+ mDepthOutputFormats.get(config.getFormat()) + 1);
}
- if (!mOutputFormats.containsKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED)) {
+ if (mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) {
throw new AssertionError(
"At least one stream configuration for IMPLEMENTATION_DEFINED must exist");
}
@@ -241,7 +253,7 @@ public final class StreamConfigurationMap {
* @return a non-empty array of sizes, or {@code null} if the format was not available.
*/
public Size[] getInputSizes(final int format) {
- return getPublicFormatSizes(format, /*output*/false);
+ return getPublicFormatSizes(format, /*output*/false, /*highRes*/false);
}
/**
@@ -274,9 +286,9 @@ public final class StreamConfigurationMap {
int internalFormat = imageFormatToInternal(format);
int dataspace = imageFormatToDataspace(format);
if (dataspace == HAL_DATASPACE_DEPTH) {
- return mDepthOutputFormats.containsKey(internalFormat);
+ return mDepthOutputFormats.indexOfKey(internalFormat) >= 0;
} else {
- return getFormatsMap(/*output*/true).containsKey(internalFormat);
+ return getFormatsMap(/*output*/true).indexOfKey(internalFormat) >= 0;
}
}
@@ -378,27 +390,24 @@ public final class StreamConfigurationMap {
public boolean isOutputSupportedFor(Surface surface) {
checkNotNull(surface, "surface must not be null");
- Size surfaceSize;
- int surfaceFormat = -1;
- try {
- surfaceSize = LegacyCameraDevice.getSurfaceSize(surface);
- surfaceFormat = LegacyCameraDevice.detectSurfaceType(surface);
- } catch(BufferQueueAbandonedException e) {
- throw new IllegalArgumentException("Abandoned surface", e);
- }
+ Size surfaceSize = SurfaceUtils.getSurfaceSize(surface);
+ int surfaceFormat = SurfaceUtils.getSurfaceFormat(surface);
+ int surfaceDataspace = SurfaceUtils.getSurfaceDataspace(surface);
// See if consumer is flexible.
- boolean isFlexible = LegacyCameraDevice.isFlexibleConsumer(surface);
+ boolean isFlexible = SurfaceUtils.isFlexibleConsumer(surface);
// Override RGB formats to IMPLEMENTATION_DEFINED, b/9487482
if ((surfaceFormat >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 &&
surfaceFormat <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) {
- surfaceFormat = LegacyMetadataMapper.HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
+ surfaceFormat = HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
}
- for (StreamConfiguration config : mConfigurations) {
+ StreamConfiguration[] configs =
+ surfaceDataspace != HAL_DATASPACE_DEPTH ? mConfigurations : mDepthConfigurations;
+ for (StreamConfiguration config : configs) {
if (config.getFormat() == surfaceFormat && config.isOutput()) {
- // Mathing format, either need exact size match, or a flexible consumer
+ // Matching format, either need exact size match, or a flexible consumer
// and a size no bigger than MAX_DIMEN_FOR_ROUNDING
if (config.getSize().equals(surfaceSize)) {
return true;
@@ -414,12 +423,12 @@ public final class StreamConfigurationMap {
/**
* Get a list of sizes compatible with {@code klass} to use as an output.
*
- * <p>Since some of the supported classes may support additional formats beyond
+ * <p>Some of the supported classes may support additional formats beyond
* {@link ImageFormat#PRIVATE}; this function only returns
* sizes for {@link ImageFormat#PRIVATE}. For example, {@link android.media.ImageReader}
* supports {@link ImageFormat#YUV_420_888} and {@link ImageFormat#PRIVATE}, this method will
* only return the sizes for {@link ImageFormat#PRIVATE} for {@link android.media.ImageReader}
- * class .</p>
+ * class.</p>
*
* <p>If a well-defined format such as {@code NV21} is required, use
* {@link #getOutputSizes(int)} instead.</p>
@@ -444,7 +453,7 @@ public final class StreamConfigurationMap {
}
return getInternalFormatSizes(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
- HAL_DATASPACE_UNKNOWN,/*output*/true);
+ HAL_DATASPACE_UNKNOWN,/*output*/true, /*highRes*/false);
}
/**
@@ -453,6 +462,14 @@ public final class StreamConfigurationMap {
* <p>The {@code format} should be a supported format (one of the formats returned by
* {@link #getOutputFormats}).</p>
*
+ * As of API level 23, the {@link #getHighResolutionOutputSizes} method can be used on devices
+ * that support the
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}
+ * capability to get a list of high-resolution output sizes that cannot operate at the preferred
+ * 20fps rate. This means that for some supported formats, this method will return an empty
+ * list, if all the supported resolutions operate at below 20fps. For devices that do not
+ * support the BURST_CAPTURE capability, all output resolutions are listed through this method.
+ *
* @param format an image format from {@link ImageFormat} or {@link PixelFormat}
* @return
* an array of supported sizes,
@@ -463,36 +480,40 @@ public final class StreamConfigurationMap {
* @see #getOutputFormats
*/
public Size[] getOutputSizes(int format) {
- return getPublicFormatSizes(format, /*output*/true);
+ return getPublicFormatSizes(format, /*output*/true, /*highRes*/ false);
}
/**
* Get a list of supported high speed video recording sizes.
- *
- * <p> When HIGH_SPEED_VIDEO is supported in
- * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES available scene modes}, this
- * method will list the supported high speed video size configurations. All the sizes listed
- * will be a subset of the sizes reported by {@link #getOutputSizes} for processed non-stalling
- * formats (typically ImageFormat#YUV_420_888, ImageFormat#NV21, ImageFormat#YV12)</p>
- *
- * <p> To enable high speed video recording, application must set
- * {@link CaptureRequest#CONTROL_SCENE_MODE} to
- * {@link CaptureRequest#CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO} in capture
- * requests and select the video size from this method and
+ * <p>
+ * When {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO} is
+ * supported in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}, this method will
+ * list the supported high speed video size configurations. All the sizes listed will be a
+ * subset of the sizes reported by {@link #getOutputSizes} for processed non-stalling formats
+ * (typically {@link ImageFormat#PRIVATE} {@link ImageFormat#YUV_420_888}, etc.)
+ * </p>
+ * <p>
+ * To enable high speed video recording, application must create a constrained create high speed
+ * capture session via {@link CameraDevice#createConstrainedHighSpeedCaptureSession}, and submit
+ * a CaptureRequest list created by {@link CameraDevice#createConstrainedHighSpeedRequestList}
+ * to this session. The application must select the video size from this method and
* {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} from
- * {@link #getHighSpeedVideoFpsRangesFor} to configure the recording and preview streams and
- * setup the recording requests. For example, if the application intends to do high speed
- * recording, it can select the maximum size reported by this method to configure output
- * streams. Note that for the use case of multiple output streams, application must select one
- * unique size from this method to use. Otherwise a request error might occur. Once the size is
+ * {@link #getHighSpeedVideoFpsRangesFor} to configure the constrained high speed session and
+ * generate the high speed request list. For example, if the application intends to do high
+ * speed recording, it can select the maximum size reported by this method to create high speed
+ * capture session. Note that for the use case of multiple output streams, application must
+ * select one unique size from this method to use (e.g., preview and recording streams must have
+ * the same size). Otherwise, the high speed session creation will fail. Once the size is
* selected, application can get the supported FPS ranges by
* {@link #getHighSpeedVideoFpsRangesFor}, and use these FPS ranges to setup the recording
- * requests.</p>
- *
- * @return
- * an array of supported high speed video recording sizes
+ * request lists via {@link CameraDevice#createConstrainedHighSpeedRequestList}.
+ * </p>
*
+ * @return an array of supported high speed video recording sizes
* @see #getHighSpeedVideoFpsRangesFor(Size)
+ * @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
+ * @see CameraDevice#createConstrainedHighSpeedCaptureSession
+ * @see CameraDevice#createConstrainedHighSpeedRequestList
*/
public Size[] getHighSpeedVideoSizes() {
Set<Size> keySet = mHighSpeedVideoSizeMap.keySet();
@@ -501,26 +522,25 @@ public final class StreamConfigurationMap {
/**
* Get the frame per second ranges (fpsMin, fpsMax) for input high speed video size.
- *
- * <p> See {@link #getHighSpeedVideoSizes} for how to enable high speed recording.</p>
- *
- * <p> For normal video recording use case, where some application will NOT set
- * {@link CaptureRequest#CONTROL_SCENE_MODE} to
- * {@link CaptureRequest#CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO} in capture
- * requests, the {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS ranges} reported in
- * this method must not be used to setup capture requests, or it will cause request error.</p>
+ * <p>
+ * See {@link #getHighSpeedVideoFpsRanges} for how to enable high speed recording.
+ * </p>
+ * <p>
+ * The {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS ranges} reported in this method
+ * must not be used to setup capture requests that are submitted to unconstrained capture
+ * sessions, or it will result in {@link IllegalArgumentException IllegalArgumentExceptions}.
+ * </p>
+ * <p>
+ * See {@link #getHighSpeedVideoFpsRanges} for the characteristics of the returned FPS ranges.
+ * </p>
*
* @param size one of the sizes returned by {@link #getHighSpeedVideoSizes()}
- * @return
- * An array of FPS range to use with
- * {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE TARGET_FPS_RANGE} when using
- * {@link CaptureRequest#CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO} scene
- * mode.
- * The upper bound of returned ranges is guaranteed to be larger or equal to 60.
- *
+ * @return an array of supported high speed video recording FPS ranges The upper bound of
+ * returned ranges is guaranteed to be greater than or equal to 120.
* @throws IllegalArgumentException if input size does not exist in the return value of
- * getHighSpeedVideoSizes
+ * getHighSpeedVideoSizes
* @see #getHighSpeedVideoSizes()
+ * @see #getHighSpeedVideoFpsRanges()
*/
public Range<Integer>[] getHighSpeedVideoFpsRangesFor(Size size) {
Integer fpsRangeCount = mHighSpeedVideoSizeMap.get(size);
@@ -542,34 +562,46 @@ public final class StreamConfigurationMap {
/**
* Get a list of supported high speed video recording FPS ranges.
- *
- * <p> When HIGH_SPEED_VIDEO is supported in
- * {@link CameraCharacteristics#CONTROL_AVAILABLE_SCENE_MODES available scene modes}, this
- * method will list the supported high speed video FPS range configurations. Application can
- * then use {@link #getHighSpeedVideoSizesFor} to query available sizes for one of returned
- * FPS range.</p>
- *
- * <p> To enable high speed video recording, application must set
- * {@link CaptureRequest#CONTROL_SCENE_MODE} to
- * {@link CaptureRequest#CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO} in capture
- * requests and select the video size from {@link #getHighSpeedVideoSizesFor} and
+ * <p>
+ * When {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO} is
+ * supported in {@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}, this method will
+ * list the supported high speed video FPS range configurations. Application can then use
+ * {@link #getHighSpeedVideoSizesFor} to query available sizes for one of returned FPS range.
+ * </p>
+ * <p>
+ * To enable high speed video recording, application must create a constrained create high speed
+ * capture session via {@link CameraDevice#createConstrainedHighSpeedCaptureSession}, and submit
+ * a CaptureRequest list created by {@link CameraDevice#createConstrainedHighSpeedRequestList}
+ * to this session. The application must select the video size from this method and
* {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS range} from
- * this method to configure the recording and preview streams and setup the recording requests.
- * For example, if the application intends to do high speed recording, it can select one FPS
- * range reported by this method, query the video sizes corresponding to this FPS range by
- * {@link #getHighSpeedVideoSizesFor} and select one of reported sizes to configure output
- * streams. Note that for the use case of multiple output streams, application must select one
- * unique size from {@link #getHighSpeedVideoSizesFor}, and use it for all output streams.
- * Otherwise a request error might occur when attempting to enable
- * {@link CaptureRequest#CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO}.
- * Once the stream is configured, application can set the FPS range in the recording requests.
+ * {@link #getHighSpeedVideoFpsRangesFor} to configure the constrained high speed session and
+ * generate the high speed request list. For example, if the application intends to do high
+ * speed recording, it can select one FPS range reported by this method, query the video sizes
+ * corresponding to this FPS range by {@link #getHighSpeedVideoSizesFor} and use one of reported
+ * sizes to create a high speed capture session. Note that for the use case of multiple output
+ * streams, application must select one unique size from this method to use (e.g., preview and
+ * recording streams must have the same size). Otherwise, the high speed session creation will
+ * fail. Once the high speed capture session is created, the application can set the FPS range
+ * in the recording request lists via
+ * {@link CameraDevice#createConstrainedHighSpeedRequestList}.
+ * </p>
+ * <p>
+ * The FPS ranges reported by this method will have below characteristics:
+ * <li>The fpsMin and fpsMax will be a multiple 30fps.</li>
+ * <li>The fpsMin will be no less than 30fps, the fpsMax will be no less than 120fps.</li>
+ * <li>At least one range will be a fixed FPS range where fpsMin == fpsMax.</li>
+ * <li>For each fixed FPS range, there will be one corresponding variable FPS range [30,
+ * fps_max]. These kinds of FPS ranges are suitable for preview-only use cases where the
+ * application doesn't want the camera device always produce higher frame rate than the display
+ * refresh rate.</li>
* </p>
*
- * @return
- * an array of supported high speed video recording FPS ranges
- * The upper bound of returned ranges is guaranteed to be larger or equal to 60.
- *
+ * @return an array of supported high speed video recording FPS ranges The upper bound of
+ * returned ranges is guaranteed to be larger or equal to 120.
* @see #getHighSpeedVideoSizesFor
+ * @see CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_CONSTRAINED_HIGH_SPEED_VIDEO
+ * @see CameraDevice#createConstrainedHighSpeedCaptureSession
+ * @see CameraDevice#createConstrainedHighSpeedRequestList
*/
@SuppressWarnings("unchecked")
public Range<Integer>[] getHighSpeedVideoFpsRanges() {
@@ -578,21 +610,13 @@ public final class StreamConfigurationMap {
}
/**
- * Get the supported video sizes for input FPS range.
+ * Get the supported video sizes for an input high speed FPS range.
*
- * <p> See {@link #getHighSpeedVideoFpsRanges} for how to enable high speed recording.</p>
- *
- * <p> For normal video recording use case, where the application will NOT set
- * {@link CaptureRequest#CONTROL_SCENE_MODE} to
- * {@link CaptureRequest#CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO} in capture
- * requests, the {@link CaptureRequest#CONTROL_AE_TARGET_FPS_RANGE FPS ranges} reported in
- * this method must not be used to setup capture requests, or it will cause request error.</p>
+ * <p> See {@link #getHighSpeedVideoSizes} for how to enable high speed recording.</p>
*
* @param fpsRange one of the FPS range returned by {@link #getHighSpeedVideoFpsRanges()}
- * @return
- * An array of video sizes to configure output stream when using
- * {@link CaptureRequest#CONTROL_SCENE_MODE_HIGH_SPEED_VIDEO HIGH_SPEED_VIDEO} scene
- * mode.
+ * @return An array of video sizes to create high speed capture sessions for high speed streaming
+ * use cases.
*
* @throws IllegalArgumentException if input FPS range does not exist in the return value of
* getHighSpeedVideoFpsRanges
@@ -616,6 +640,32 @@ public final class StreamConfigurationMap {
}
/**
+ * Get a list of supported high resolution sizes, which cannot operate at full BURST_CAPTURE
+ * rate.
+ *
+ * <p>This includes all output sizes that cannot meet the 20 fps frame rate requirements for the
+ * {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE BURST_CAPTURE}
+ * capability. This does not include the stall duration, so for example, a JPEG or RAW16 output
+ * resolution with a large stall duration but a minimum frame duration that's above 20 fps will
+ * still be listed in the regular {@link #getOutputSizes} list. All the sizes on this list are
+ * still guaranteed to operate at a rate of at least 10 fps, not including stall duration.</p>
+ *
+ * <p>For a device that does not support the BURST_CAPTURE capability, this list will be
+ * {@code null}, since resolutions in the {@link #getOutputSizes} list are already not
+ * guaranteed to meet &gt;= 20 fps rate requirements. For a device that does support the
+ * BURST_CAPTURE capability, this list may be empty, if all supported resolutions meet the 20
+ * fps requirement.</p>
+ *
+ * @return an array of supported slower high-resolution sizes, or {@code null} if the
+ * BURST_CAPTURE capability is not supported
+ */
+ public Size[] getHighResolutionOutputSizes(int format) {
+ if (!mListHighResolution) return null;
+
+ return getPublicFormatSizes(format, /*output*/true, /*highRes*/ true);
+ }
+
+ /**
* Get the minimum {@link CaptureRequest#SENSOR_FRAME_DURATION frame duration}
* for the format/size combination (in nanoseconds).
*
@@ -867,6 +917,7 @@ public final class StreamConfigurationMap {
return Arrays.equals(mConfigurations, other.mConfigurations) &&
Arrays.equals(mMinFrameDurations, other.mMinFrameDurations) &&
Arrays.equals(mStallDurations, other.mStallDurations) &&
+ Arrays.equals(mDepthConfigurations, other.mDepthConfigurations) &&
Arrays.equals(mHighSpeedVideoConfigurations,
other.mHighSpeedVideoConfigurations);
}
@@ -879,18 +930,31 @@ public final class StreamConfigurationMap {
@Override
public int hashCode() {
// XX: do we care about order?
- return HashCodeHelpers.hashCode(
+ return HashCodeHelpers.hashCodeGeneric(
mConfigurations, mMinFrameDurations,
- mStallDurations, mHighSpeedVideoConfigurations);
+ mStallDurations,
+ mDepthConfigurations, mHighSpeedVideoConfigurations);
}
// Check that the argument is supported by #getOutputFormats or #getInputFormats
private int checkArgumentFormatSupported(int format, boolean output) {
checkArgumentFormat(format);
- int[] formats = output ? getOutputFormats() : getInputFormats();
- for (int i = 0; i < formats.length; ++i) {
- if (format == formats[i]) {
+ int internalFormat = imageFormatToInternal(format);
+ int internalDataspace = imageFormatToDataspace(format);
+
+ if (output) {
+ if (internalDataspace == HAL_DATASPACE_DEPTH) {
+ if (mDepthOutputFormats.indexOfKey(internalFormat) >= 0) {
+ return format;
+ }
+ } else {
+ if (mAllOutputFormats.indexOfKey(internalFormat) >= 0) {
+ return format;
+ }
+ }
+ } else {
+ if (mInputFormats.indexOfKey(internalFormat) >= 0) {
return format;
}
}
@@ -1175,7 +1239,7 @@ public final class StreamConfigurationMap {
return formats;
}
- private Size[] getPublicFormatSizes(int format, boolean output) {
+ private Size[] getPublicFormatSizes(int format, boolean output, boolean highRes) {
try {
checkArgumentFormatSupported(format, output);
} catch (IllegalArgumentException e) {
@@ -1185,36 +1249,57 @@ public final class StreamConfigurationMap {
int internalFormat = imageFormatToInternal(format);
int dataspace = imageFormatToDataspace(format);
- return getInternalFormatSizes(internalFormat, dataspace, output);
+ return getInternalFormatSizes(internalFormat, dataspace, output, highRes);
}
- private Size[] getInternalFormatSizes(int format, int dataspace, boolean output) {
-
- HashMap<Integer, Integer> formatsMap =
- (dataspace == HAL_DATASPACE_DEPTH) ? mDepthOutputFormats : getFormatsMap(output);
-
- Integer sizesCount = formatsMap.get(format);
- if (sizesCount == null) {
+ private Size[] getInternalFormatSizes(int format, int dataspace,
+ boolean output, boolean highRes) {
+ SparseIntArray formatsMap =
+ !output ? mInputFormats :
+ dataspace == HAL_DATASPACE_DEPTH ? mDepthOutputFormats :
+ highRes ? mHighResOutputFormats :
+ mOutputFormats;
+
+ int sizesCount = formatsMap.get(format);
+ if ( ((!output || dataspace == HAL_DATASPACE_DEPTH) && sizesCount == 0) ||
+ (output && dataspace != HAL_DATASPACE_DEPTH && mAllOutputFormats.get(format) == 0)) {
+ // Only throw if this is really not supported at all
throw new IllegalArgumentException("format not available");
}
- int len = sizesCount;
- Size[] sizes = new Size[len];
+ Size[] sizes = new Size[sizesCount];
int sizeIndex = 0;
StreamConfiguration[] configurations =
(dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
-
for (StreamConfiguration config : configurations) {
- if (config.getFormat() == format && config.isOutput() == output) {
+ int fmt = config.getFormat();
+ if (fmt == format && config.isOutput() == output) {
+ if (output) {
+ // Filter slow high-res output formats; include for
+ // highRes, remove for !highRes
+ long duration = 0;
+ for (int i = 0; i < mMinFrameDurations.length; i++) {
+ StreamConfigurationDuration d = mMinFrameDurations[i];
+ if (d.getFormat() == fmt &&
+ d.getWidth() == config.getSize().getWidth() &&
+ d.getHeight() == config.getSize().getHeight()) {
+ duration = d.getDuration();
+ break;
+ }
+ }
+ if (highRes != (duration > DURATION_20FPS_NS)) {
+ continue;
+ }
+ }
sizes[sizeIndex++] = config.getSize();
}
}
- if (sizeIndex != len) {
+ if (sizeIndex != sizesCount) {
throw new AssertionError(
- "Too few sizes (expected " + len + ", actual " + sizeIndex + ")");
+ "Too few sizes (expected " + sizesCount + ", actual " + sizeIndex + ")");
}
return sizes;
@@ -1226,14 +1311,16 @@ public final class StreamConfigurationMap {
int i = 0;
- for (int format : getFormatsMap(output).keySet()) {
+ SparseIntArray map = getFormatsMap(output);
+ for (int j = 0; j < map.size(); j++) {
+ int format = map.keyAt(j);
if (format != HAL_PIXEL_FORMAT_RAW_OPAQUE) {
formats[i++] = imageFormatToPublic(format);
}
}
if (output) {
- for (int format : mDepthOutputFormats.keySet()) {
- formats[i++] = depthFormatToPublic(format);
+ for (int j = 0; j < mDepthOutputFormats.size(); j++) {
+ formats[i++] = depthFormatToPublic(mDepthOutputFormats.keyAt(j));
}
}
if (formats.length != i) {
@@ -1244,14 +1331,14 @@ public final class StreamConfigurationMap {
}
/** Get the format -> size count map for either output or input formats */
- private HashMap<Integer, Integer> getFormatsMap(boolean output) {
- return output ? mOutputFormats : mInputFormats;
+ private SparseIntArray getFormatsMap(boolean output) {
+ return output ? mAllOutputFormats : mInputFormats;
}
private long getInternalFormatDuration(int format, int dataspace, Size size, int duration) {
// assume format is already checked, since its internal
- if (!arrayContains(getInternalFormatSizes(format, dataspace, /*output*/true), size)) {
+ if (!isSupportedInternalConfiguration(format, dataspace, size)) {
throw new IllegalArgumentException("size was not supported");
}
@@ -1289,10 +1376,9 @@ public final class StreamConfigurationMap {
/** Count the number of publicly-visible output formats */
private int getPublicFormatCount(boolean output) {
- HashMap<Integer, Integer> formatsMap = getFormatsMap(output);
-
+ SparseIntArray formatsMap = getFormatsMap(output);
int size = formatsMap.size();
- if (formatsMap.containsKey(HAL_PIXEL_FORMAT_RAW_OPAQUE)) {
+ if (formatsMap.indexOfKey(HAL_PIXEL_FORMAT_RAW_OPAQUE) >= 0) {
size -= 1;
}
if (output) {
@@ -1316,6 +1402,21 @@ public final class StreamConfigurationMap {
return false;
}
+ private boolean isSupportedInternalConfiguration(int format, int dataspace,
+ Size size) {
+ StreamConfiguration[] configurations =
+ (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations : mConfigurations;
+
+ for (int i = 0; i < configurations.length; i++) {
+ if (configurations[i].getFormat() == format &&
+ configurations[i].getSize().equals(size)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
/**
* Return this {@link StreamConfigurationMap} as a string representation.
*
@@ -1351,6 +1452,8 @@ public final class StreamConfigurationMap {
StringBuilder sb = new StringBuilder("StreamConfiguration(");
appendOutputsString(sb);
sb.append(", ");
+ appendHighResOutputsString(sb);
+ sb.append(", ");
appendInputsString(sb);
sb.append(", ");
appendValidOutputFormatsForInputString(sb);
@@ -1381,6 +1484,27 @@ public final class StreamConfigurationMap {
sb.append(")");
}
+ private void appendHighResOutputsString(StringBuilder sb) {
+ sb.append("HighResolutionOutputs(");
+ int[] formats = getOutputFormats();
+ for (int format : formats) {
+ Size[] sizes = getHighResolutionOutputSizes(format);
+ if (sizes == null) continue;
+ for (Size size : sizes) {
+ long minFrameDuration = getOutputMinFrameDuration(format, size);
+ long stallDuration = getOutputStallDuration(format, size);
+ sb.append(String.format("[w:%d, h:%d, format:%s(%d), min_duration:%d, " +
+ "stall:%d], ", size.getWidth(), size.getHeight(), formatToString(format),
+ format, minFrameDuration, stallDuration));
+ }
+ }
+ // Remove the pending ", "
+ if (sb.charAt(sb.length() - 1) == ' ') {
+ sb.delete(sb.length() - 2, sb.length());
+ }
+ sb.append(")");
+ }
+
private void appendInputsString(StringBuilder sb) {
sb.append("Inputs(");
int[] formats = getInputFormats();
@@ -1479,15 +1603,21 @@ public final class StreamConfigurationMap {
}
// from system/core/include/system/graphics.h
+ private static final int HAL_PIXEL_FORMAT_RAW16 = 0x20;
private static final int HAL_PIXEL_FORMAT_BLOB = 0x21;
private static final int HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED = 0x22;
+ private static final int HAL_PIXEL_FORMAT_YCbCr_420_888 = 0x23;
private static final int HAL_PIXEL_FORMAT_RAW_OPAQUE = 0x24;
+ private static final int HAL_PIXEL_FORMAT_RAW10 = 0x25;
+ private static final int HAL_PIXEL_FORMAT_RAW12 = 0x26;
private static final int HAL_PIXEL_FORMAT_Y16 = 0x20363159;
+
private static final int HAL_DATASPACE_UNKNOWN = 0x0;
private static final int HAL_DATASPACE_JFIF = 0x101;
private static final int HAL_DATASPACE_DEPTH = 0x1000;
+ private static final long DURATION_20FPS_NS = 50000000L;
/**
* @see #getDurations(int, int)
*/
@@ -1505,15 +1635,20 @@ public final class StreamConfigurationMap {
private final HighSpeedVideoConfiguration[] mHighSpeedVideoConfigurations;
private final ReprocessFormatsMap mInputOutputFormatsMap;
- /** ImageFormat -> num output sizes mapping */
- private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mOutputFormats =
- new HashMap<Integer, Integer>();
- /** ImageFormat -> num input sizes mapping */
- private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mInputFormats =
- new HashMap<Integer, Integer>();
- /** ImageFormat -> num depth output sizes mapping */
- private final HashMap</*ImageFormat*/Integer, /*Count*/Integer> mDepthOutputFormats =
- new HashMap<Integer, Integer>();
+ private final boolean mListHighResolution;
+
+ /** internal format -> num output sizes mapping, not including slow high-res sizes, for
+ * non-depth dataspaces */
+ private final SparseIntArray mOutputFormats = new SparseIntArray();
+ /** internal format -> num output sizes mapping for slow high-res sizes, for non-depth
+ * dataspaces */
+ private final SparseIntArray mHighResOutputFormats = new SparseIntArray();
+ /** internal format -> num output sizes mapping for all non-depth dataspaces */
+ private final SparseIntArray mAllOutputFormats = new SparseIntArray();
+ /** internal format -> num input sizes mapping, for input reprocessing formats */
+ private final SparseIntArray mInputFormats = new SparseIntArray();
+ /** internal format -> num depth output sizes mapping, for HAL_DATASPACE_DEPTH */
+ private final SparseIntArray mDepthOutputFormats = new SparseIntArray();
/** High speed video Size -> FPS range count mapping*/
private final HashMap</*HighSpeedVideoSize*/Size, /*Count*/Integer> mHighSpeedVideoSizeMap =
new HashMap<Size, Integer>();
@@ -1522,4 +1657,3 @@ public final class StreamConfigurationMap {
mHighSpeedVideoFpsRangeMap = new HashMap<Range<Integer>, Integer>();
}
-
diff --git a/core/java/android/hardware/camera2/params/TonemapCurve.java b/core/java/android/hardware/camera2/params/TonemapCurve.java
index 398a7e9..2d7bbaa 100644
--- a/core/java/android/hardware/camera2/params/TonemapCurve.java
+++ b/core/java/android/hardware/camera2/params/TonemapCurve.java
@@ -277,7 +277,7 @@ public final class TonemapCurve {
return mHashCode;
}
- mHashCode = HashCodeHelpers.hashCode(mRed, mGreen, mBlue);
+ mHashCode = HashCodeHelpers.hashCodeGeneric(mRed, mGreen, mBlue);
mHashCalculated = true;
return mHashCode;
diff --git a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
index 7b4aa09..731da8b 100644
--- a/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
+++ b/core/java/android/hardware/camera2/utils/HashCodeHelpers.java
@@ -30,7 +30,7 @@ public final class HashCodeHelpers {
*
* @return the numeric hash code
*/
- public static int hashCode(int[] array) {
+ public static int hashCode(int... array) {
if (array == null) {
return 0;
}
@@ -60,7 +60,7 @@ public final class HashCodeHelpers {
*
* @return the numeric hash code
*/
- public static int hashCode(float[] array) {
+ public static int hashCode(float... array) {
if (array == null) {
return 0;
}
@@ -83,7 +83,7 @@ public final class HashCodeHelpers {
*
* @return the numeric hash code
*/
- public static <T> int hashCode(T[] array) {
+ public static <T> int hashCodeGeneric(T... array) {
if (array == null) {
return 0;
}
@@ -97,56 +97,4 @@ public final class HashCodeHelpers {
return h;
}
- public static <T> int hashCode(T a) {
- return (a == null) ? 0 : a.hashCode();
- }
-
- public static <T> int hashCode(T a, T b) {
- int h = hashCode(a);
-
- int x = (b == null) ? 0 : b.hashCode();
- h = ((h << 5) - h) ^ x; // (h * 31) XOR x
-
- return h;
- }
-
- public static <T> int hashCode(T a, T b, T c) {
- int h = hashCode(a, b);
-
- int x = (c == null) ? 0 : c.hashCode();
- h = ((h << 5) - h) ^ x; // (h * 31) XOR x
-
- return h;
- }
-
- public static <T> int hashCode(T a, T b, T c, T d) {
- int h = hashCode(a, b, c);
-
- int x = (d == null) ? 0 : d.hashCode();
- h = ((h << 5) - h) ^ x; // (h * 31) XOR x
-
- return h;
- }
-
- public static int hashCode(int x) {
- return hashCode(new int[] { x } );
- }
-
- public static int hashCode(int x, int y) {
- return hashCode(new int[] { x, y } );
- }
-
- public static int hashCode(int x, int y, int z) {
- return hashCode(new int[] { x, y, z } );
- }
-
- public static int hashCode(int x, int y, int z, int w) {
- return hashCode(new int[] { x, y, z, w } );
- }
-
- public static int hashCode(int x, int y, int z, int w, int t) {
- return hashCode(new int[] { x, y, z, w, t } );
- }
-
-
}
diff --git a/core/java/android/hardware/camera2/utils/SurfaceUtils.java b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
index 40005a5..064b21a 100644
--- a/core/java/android/hardware/camera2/utils/SurfaceUtils.java
+++ b/core/java/android/hardware/camera2/utils/SurfaceUtils.java
@@ -79,4 +79,30 @@ public class SurfaceUtils {
throw new IllegalArgumentException("Surface was abandoned", e);
}
}
+
+ /**
+ * Get the Surface dataspace.
+ *
+ * @param surface The surface to be queried for dataspace.
+ * @return dataspace of the surface.
+ *
+ * @throws IllegalArgumentException if the surface is already abandoned.
+ */
+ public static int getSurfaceDataspace(Surface surface) {
+ try {
+ return LegacyCameraDevice.detectSurfaceDataspace(surface);
+ } catch (BufferQueueAbandonedException e) {
+ throw new IllegalArgumentException("Surface was abandoned", e);
+ }
+ }
+
+ /**
+ * Return true is the consumer is one of the consumers that can accept
+ * producer overrides of the default dimensions and format.
+ *
+ */
+ public static boolean isFlexibleConsumer(Surface output) {
+ return LegacyCameraDevice.isFlexibleConsumer(output);
+ }
+
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index b9f7365..80476ea 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2110,6 +2110,8 @@ public class ConnectivityManager {
* can automatically log in to a captive portal without user intervention.
*
* @param network The {@link Network} of the network that is being evaluated.
+ *
+ * @hide
*/
public void onPreCheck(Network network) {}
@@ -2379,6 +2381,14 @@ public class ConnectivityManager {
* Status of the request can be followed by listening to the various
* callbacks described in {@link NetworkCallback}. The {@link Network}
* can be used to direct traffic to the network.
+ * <p>It is presently unsupported to request a network with mutable
+ * {@link NetworkCapabilities} such as
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+ * as these {@code NetworkCapabilities} represent states that a particular
+ * network may never attain, and whether a network will attain these states
+ * is unknown prior to bringing up the network so the framework does not
+ * know how to go about satisfing a request with these capabilities.
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
*
@@ -2386,6 +2396,8 @@ public class ConnectivityManager {
* @param networkCallback The {@link NetworkCallback} to be utilized for this
* request. Note the callback must not be shared - they
* uniquely specify this request.
+ * @throws IllegalArgumentException if {@code request} specifies any mutable
+ * {@code NetworkCapabilities}.
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
sendRequestForNetwork(request.networkCapabilities, networkCallback, 0,
@@ -2467,12 +2479,22 @@ public class ConnectivityManager {
* <p>
* The request may be released normally by calling
* {@link #releaseNetworkRequest(android.app.PendingIntent)}.
+ * <p>It is presently unsupported to request a network with either
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+ * as these {@code NetworkCapabilities} represent states that a particular
+ * network may never attain, and whether a network will attain these states
+ * is unknown prior to bringing up the network so the framework does not
+ * know how to go about satisfing a request with these capabilities.
* <p>This method requires the caller to hold the permission
* {@link android.Manifest.permission#CHANGE_NETWORK_STATE}.
* @param request {@link NetworkRequest} describing this request.
* @param operation Action to perform when the network is available (corresponds
* to the {@link NetworkCallback#onAvailable} call. Typically
* comes from {@link PendingIntent#getBroadcast}. Cannot be null.
+ * @throws IllegalArgumentException if {@code request} contains either
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}.
*/
public void requestNetwork(NetworkRequest request, PendingIntent operation) {
checkPendingIntent(operation);
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index cf747cf..658051c 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -173,12 +173,17 @@ public final class NetworkCapabilities implements Parcelable {
* Indicates that connectivity on this network was successfully validated. For example, for a
* network with NET_CAPABILITY_INTERNET, it means that Internet connectivity was successfully
* detected.
- * @hide
*/
public static final int NET_CAPABILITY_VALIDATED = 16;
+ /**
+ * Indicates that this network was found to have a captive portal in place last time it was
+ * probed.
+ */
+ public static final int NET_CAPABILITY_CAPTIVE_PORTAL = 17;
+
private static final int MIN_NET_CAPABILITY = NET_CAPABILITY_MMS;
- private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_VALIDATED;
+ private static final int MAX_NET_CAPABILITY = NET_CAPABILITY_CAPTIVE_PORTAL;
/**
* Adds the given capability to this {@code NetworkCapability} instance.
diff --git a/core/java/android/os/Debug.java b/core/java/android/os/Debug.java
index 87e8c5e..97b85e2 100644
--- a/core/java/android/os/Debug.java
+++ b/core/java/android/os/Debug.java
@@ -1469,13 +1469,30 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
* </tr>
* <tr>
* <td>art.gc.gc-count-rate-histogram</td>
- * <td>The histogram of the number of garbage collection runs per 10 seconds.</td>
+ * <td>Every 10 seconds, the gc-count-rate is computed as the number of garbage
+ * collection runs that have occurred over the last 10
+ * seconds. art.gc.gc-count-rate-histogram is a histogram of the gc-count-rate
+ * samples taken since the process began. The histogram can be used to identify
+ * instances of high rates of garbage collection runs. For example, a histogram
+ * of "0:34503,1:45350,2:11281,3:8088,4:43,5:8" shows that most of the time
+ * there are between 0 and 2 garbage collection runs every 10 seconds, but there
+ * were 8 distinct 10-second intervals in which 5 garbage collection runs
+ * occurred.</td>
* <td>{@code 0:34503,1:45350,2:11281,3:8088,4:43,5:8}</td>
* <td>23</td>
* </tr>
* <tr>
* <td>art.gc.blocking-gc-count-rate-histogram</td>
- * <td>The histogram of the number of garbage collection runs per 10 seconds.</td>
+ * <td>Every 10 seconds, the blocking-gc-count-rate is computed as the number of
+ * blocking garbage collection runs that have occurred over the last 10
+ * seconds. art.gc.blocking-gc-count-rate-histogram is a histogram of the
+ * blocking-gc-count-rate samples taken since the process began. The histogram
+ * can be used to identify instances of high rates of blocking garbage
+ * collection runs. For example, a histogram of "0:99269,1:1,2:1" shows that
+ * most of the time there are zero blocking garbage collection runs every 10
+ * seconds, but there was one 10-second interval in which one blocking garbage
+ * collection run occurred, and there was one interval in which two blocking
+ * garbage collection runs occurred.</td>
* <td>{@code 0:99269,1:1,2:1}</td>
* <td>23</td>
* </tr>
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 1cc2d33..f10b982 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1919,9 +1919,9 @@ public final class StrictMode {
for (int i = 0; i < numViolations; ++i) {
if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call. i=" + i);
ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
- if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 10000) {
+ if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 30000) {
String front = info.crashInfo.stackTrace.substring(256);
- // 10000 characters is way too large for this to be any sane kind of
+ // 30000 characters is way too large for this to be any sane kind of
// strict mode collection of stacks. We've had a problem where we leave
// strict mode violations associated with the thread, and it keeps tacking
// more and more stacks on to the violations. Looks like we're in this casse,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 56cd1a7..9b5fbfa 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6685,6 +6685,17 @@ public final class Settings {
"wifi_mobile_data_transition_wakelock_timeout_ms";
/**
+ * This setting controls whether WiFi configurations created by a Device Owner app
+ * should be locked down (that is, be editable or removable only by the Device Owner App,
+ * not even by Settings app).
+ * This setting takes integer values. Non-zero values mean DO created configurations
+ * are locked down. Value of zero means they are not. Default value in the absence of
+ * actual value to this setting is 0.
+ */
+ public static final String WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN =
+ "wifi_device_owner_configs_lockdown";
+
+ /**
* The operational wifi frequency band
* Set to one of {@link WifiManager#WIFI_FREQUENCY_BAND_AUTO},
* {@link WifiManager#WIFI_FREQUENCY_BAND_5GHZ} or
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 39dd29b..f9e216a 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1146,20 +1146,7 @@ public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCall
mContentFrame.requestApplyInsets();
}
- /** @hide */
- public void onHandleAssist(Bundle assistBundle) {
- }
-
public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
- if (data != null) {
- Bundle assistContext = data.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
- if (assistContext != null) {
- assistContext.putParcelable(AssistStructure.ASSIST_KEY, structure);
- assistContext.putParcelable(AssistContent.ASSIST_KEY, content);
- data.putBundle(Intent.EXTRA_ASSIST_CONTEXT, assistContext);
- }
- }
- onHandleAssist(data);
}
public void onHandleScreenshot(Bitmap screenshot) {
diff --git a/core/java/android/text/format/Formatter.java b/core/java/android/text/format/Formatter.java
index 13a959e..47d5c79 100644
--- a/core/java/android/text/format/Formatter.java
+++ b/core/java/android/text/format/Formatter.java
@@ -16,6 +16,7 @@
package android.text.format;
+import android.annotation.Nullable;
import android.content.Context;
import android.content.res.Resources;
import android.net.NetworkUtils;
@@ -52,7 +53,10 @@ public final class Formatter {
* @param sizeBytes size value to be formatted, in bytes
* @return formatted string with the number
*/
- public static String formatFileSize(Context context, long sizeBytes) {
+ public static String formatFileSize(@Nullable Context context, long sizeBytes) {
+ if (context == null) {
+ return "";
+ }
final BytesResult res = formatBytes(context.getResources(), sizeBytes, 0);
return context.getString(com.android.internal.R.string.fileSizeSuffix,
res.value, res.units);
@@ -62,7 +66,10 @@ public final class Formatter {
* Like {@link #formatFileSize}, but trying to generate shorter numbers
* (showing fewer digits of precision).
*/
- public static String formatShortFileSize(Context context, long sizeBytes) {
+ public static String formatShortFileSize(@Nullable Context context, long sizeBytes) {
+ if (context == null) {
+ return "";
+ }
final BytesResult res = formatBytes(context.getResources(), sizeBytes, FLAG_SHORTER);
return context.getString(com.android.internal.R.string.fileSizeSuffix,
res.value, res.units);
diff --git a/core/java/android/transition/Visibility.java b/core/java/android/transition/Visibility.java
index 8b74a1e..585fc4e 100644
--- a/core/java/android/transition/Visibility.java
+++ b/core/java/android/transition/Visibility.java
@@ -504,13 +504,20 @@ public abstract class Visibility extends Transition {
private final boolean mIsForcedVisibility;
private final View mView;
private final int mFinalVisibility;
+ private final ViewGroup mParent;
+ private boolean mEnded;
boolean mCanceled = false;
public DisappearListener(View view, int finalVisibility, boolean isForcedVisibility) {
this.mView = view;
this.mIsForcedVisibility = isForcedVisibility;
this.mFinalVisibility = finalVisibility;
+ this.mParent = (ViewGroup) view.getParent();
+ if (!isForcedVisibility && mParent != null) {
+ // Prevent a layout from including mView in its calculation.
+ mParent.suppressLayout(true);
+ }
}
@Override
@@ -552,13 +559,39 @@ public abstract class Visibility extends Transition {
hideViewWhenNotCanceled();
}
+ @Override
+ public void onTransitionPause(Transition transition) {
+ if (mParent != null && !mIsForcedVisibility) {
+ mParent.suppressLayout(false);
+ }
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ if (mParent != null && !mIsForcedVisibility) {
+ mParent.suppressLayout(true);
+ }
+ }
+
private void hideViewWhenNotCanceled() {
- if (!mCanceled) {
- if (mIsForcedVisibility) {
- mView.setTransitionAlpha(0);
- } else {
- mView.setVisibility(mFinalVisibility);
+ if (!mEnded) {
+ if (!mCanceled) {
+ if (mIsForcedVisibility) {
+ mView.setTransitionAlpha(0);
+ } else {
+ // Recreate the parent's display list in case it includes mView.
+ mView.setTransitionVisibility(mFinalVisibility);
+ if (mParent != null) {
+ mParent.invalidate();
+ }
+ }
+ }
+ if (!mIsForcedVisibility && mParent != null) {
+ // Layout is allowed now that the View is in its final state
+ mParent.suppressLayout(false);
}
+ // Do this only once
+ mEnded = true;
}
}
}
diff --git a/core/java/android/util/Range.java b/core/java/android/util/Range.java
index 211d01a..5524506 100644
--- a/core/java/android/util/Range.java
+++ b/core/java/android/util/Range.java
@@ -350,7 +350,7 @@ public final class Range<T extends Comparable<? super T>> {
*/
@Override
public int hashCode() {
- return HashCodeHelpers.hashCode(mLower, mUpper);
+ return HashCodeHelpers.hashCodeGeneric(mLower, mUpper);
}
private final T mLower;
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index 4394cd8..6026d04 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -1399,6 +1399,7 @@ public final class MotionEvent extends InputEvent implements Parcelable {
private static native int nativeGetButtonState(long nativePtr);
private static native void nativeSetButtonState(long nativePtr, int buttonState);
private static native int nativeGetActionButton(long nativePtr);
+ private static native void nativeSetActionButton(long nativePtr, int actionButton);
private static native void nativeOffsetLocation(long nativePtr, float deltaX, float deltaY);
private static native float nativeGetXOffset(long nativePtr);
private static native float nativeGetYOffset(long nativePtr);
@@ -2284,6 +2285,16 @@ public final class MotionEvent extends InputEvent implements Parcelable {
}
/**
+ * Sets the action button for the event.
+ *
+ * @see #getActionButton()
+ * @hide
+ */
+ public final void setActionButton(int button) {
+ nativeSetActionButton(mNativePtr, button);
+ }
+
+ /**
* Returns the original raw X coordinate of this event. For touch
* events on the screen, this is the original location of the event
* on the screen, before it had been adjusted for the containing window
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 4074529..5970c3f 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -453,6 +453,19 @@ public class SurfaceControl {
}
}
+ /**
+ * Sets the security of the surface. Setting the flag is equivalent to creating the
+ * Surface with the {@link #SECURE} flag.
+ */
+ public void setSecure(boolean isSecure) {
+ checkNotReleased();
+ if (isSecure) {
+ nativeSetFlags(mNativeObject, SECURE, SECURE);
+ } else {
+ nativeSetFlags(mNativeObject, 0, SECURE);
+ }
+ }
+
/*
* set display parameters.
* needs to be inside open/closeTransaction block
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index fd3ee4f..92dae2e 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6032,7 +6032,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
public AccessibilityNodeInfo createAccessibilityNodeInfoInternal() {
AccessibilityNodeProvider provider = getAccessibilityNodeProvider();
if (provider != null) {
- return provider.createAccessibilityNodeInfo(View.NO_ID);
+ return provider.createAccessibilityNodeInfo(AccessibilityNodeProvider.HOST_VIEW_ID);
} else {
AccessibilityNodeInfo info = AccessibilityNodeInfo.obtain(this);
onInitializeAccessibilityNodeInfo(info);
@@ -6326,6 +6326,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+ if (mAttachInfo == null) {
+ return;
+ }
+
Rect bounds = mAttachInfo.mTmpInvalRect;
getDrawingRect(bounds);
@@ -8774,7 +8778,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public void notifyViewAccessibilityStateChangedIfNeeded(int changeType) {
- if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+ if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
return;
}
if (mSendViewStateChangedAccessibilityEvent == null) {
@@ -8796,7 +8800,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
* @hide
*/
public void notifySubtreeAccessibilityStateChangedIfNeeded() {
- if (!AccessibilityManager.getInstance(mContext).isEnabled()) {
+ if (!AccessibilityManager.getInstance(mContext).isEnabled() || mAttachInfo == null) {
return;
}
if ((mPrivateFlags2 & PFLAG2_SUBTREE_ACCESSIBILITY_STATE_CHANGED) == 0) {
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index d06cd83..3572f1e 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -150,7 +150,7 @@ public abstract class ViewStructure {
* @param size The size, in pixels, of the text.
* @param fgColor The foreground color, packed as 0xAARRGGBB.
* @param bgColor The background color, packed as 0xAARRGGBB.
- * @param style Style flags, as defined by {@link android.app.AssistStructure.ViewNode}.
+ * @param style Style flags, as defined by {@link android.app.assist.AssistStructure.ViewNode}.
*/
public abstract void setTextStyle(float size, int fgColor, int bgColor, int style);
diff --git a/core/java/android/view/accessibility/AccessibilityEvent.java b/core/java/android/view/accessibility/AccessibilityEvent.java
index ab793e0..87706ef 100644
--- a/core/java/android/view/accessibility/AccessibilityEvent.java
+++ b/core/java/android/view/accessibility/AccessibilityEvent.java
@@ -1115,7 +1115,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
record.mParcelableData = parcel.readParcelable(null);
parcel.readList(record.mText, null);
record.mSourceWindowId = parcel.readInt();
- record.mSourceNodeId = parcel.readLong();
+ record.mSourceNode = parcel.readParcelable(null);
record.mSealed = (parcel.readInt() == 1);
}
@@ -1167,7 +1167,10 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
parcel.writeParcelable(record.mParcelableData, flags);
parcel.writeList(record.mText);
parcel.writeInt(record.mSourceWindowId);
- parcel.writeLong(record.mSourceNodeId);
+ // create copy of the node here because the node would be recycled just after it is written
+ // to parcel
+ parcel.writeParcelable(record.mSourceNode != null ?
+ AccessibilityNodeInfo.obtain(record.mSourceNode) : null, flags);
parcel.writeInt(record.mSealed ? 1 : 0);
}
@@ -1191,7 +1194,9 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
builder.append("\n");
builder.append("; ContentChangeTypes: ").append(mContentChangeTypes);
builder.append("; sourceWindowId: ").append(mSourceWindowId);
- builder.append("; mSourceNodeId: ").append(mSourceNodeId);
+ if (mSourceNode != null) {
+ builder.append("; mSourceNodeId: ").append(mSourceNode.getSourceNodeId());
+ }
for (int i = 0; i < getRecordCount(); i++) {
final AccessibilityRecord record = getRecord(i);
builder.append(" Record ");
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 36de8f3..86ed499 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -2821,7 +2821,7 @@ public class AccessibilityNodeInfo implements Parcelable {
* @param parcel A parcel containing the state of a {@link AccessibilityNodeInfo}.
*/
private void initFromParcel(Parcel parcel) {
- mSealed = (parcel.readInt() == 1);
+ final boolean sealed = (parcel.readInt() == 1);
mSourceNodeId = parcel.readLong();
mWindowId = parcel.readInt();
mParentNodeId = parcel.readLong();
@@ -2911,6 +2911,8 @@ public class AccessibilityNodeInfo implements Parcelable {
parcel.readInt() == 1,
parcel.readInt() == 1);
}
+
+ mSealed = sealed;
}
/**
diff --git a/core/java/android/view/accessibility/AccessibilityRecord.java b/core/java/android/view/accessibility/AccessibilityRecord.java
index cc6a71d..f99690a 100644
--- a/core/java/android/view/accessibility/AccessibilityRecord.java
+++ b/core/java/android/view/accessibility/AccessibilityRecord.java
@@ -90,7 +90,7 @@ public class AccessibilityRecord {
int mAddedCount= UNDEFINED;
int mRemovedCount = UNDEFINED;
- long mSourceNodeId = AccessibilityNodeInfo.makeNodeId(UNDEFINED, UNDEFINED);
+ AccessibilityNodeInfo mSourceNode;
int mSourceWindowId = UNDEFINED;
CharSequence mClassName;
@@ -135,16 +135,24 @@ public class AccessibilityRecord {
*/
public void setSource(View root, int virtualDescendantId) {
enforceNotSealed();
- final boolean important;
- if (virtualDescendantId == UNDEFINED) {
- important = (root != null) ? root.isImportantForAccessibility() : true;
- } else {
- important = true;
+ boolean important = true;
+ mSourceWindowId = UNDEFINED;
+ clearSourceNode();
+ if (root != null) {
+ if (virtualDescendantId == UNDEFINED ||
+ virtualDescendantId == AccessibilityNodeInfo.UNDEFINED_ITEM_ID) {
+ important = root.isImportantForAccessibility();
+ mSourceNode = root.createAccessibilityNodeInfo();
+ } else {
+ AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
+ if (provider != null) {
+ mSourceNode = provider.createAccessibilityNodeInfo(virtualDescendantId);
+ }
+ }
+
+ mSourceWindowId = root.getAccessibilityWindowId();
}
setBooleanProperty(PROPERTY_IMPORTANT_FOR_ACCESSIBILITY, important);
- mSourceWindowId = (root != null) ? root.getAccessibilityWindowId() : UNDEFINED;
- final int rootViewId = (root != null) ? root.getAccessibilityViewId() : UNDEFINED;
- mSourceNodeId = AccessibilityNodeInfo.makeNodeId(rootViewId, virtualDescendantId);
}
/**
@@ -158,13 +166,11 @@ public class AccessibilityRecord {
*/
public AccessibilityNodeInfo getSource() {
enforceSealed();
- if (mConnectionId == UNDEFINED || mSourceWindowId == UNDEFINED
- || AccessibilityNodeInfo.getAccessibilityViewId(mSourceNodeId) == UNDEFINED) {
- return null;
+ if (mSourceNode != null) {
+ return AccessibilityNodeInfo.obtain(mSourceNode);
}
- AccessibilityInteractionClient client = AccessibilityInteractionClient.getInstance();
- return client.findAccessibilityNodeInfoByAccessibilityId(mConnectionId, mSourceWindowId,
- mSourceNodeId, false, GET_SOURCE_PREFETCH_FLAGS);
+
+ return null;
}
/**
@@ -619,7 +625,7 @@ public class AccessibilityRecord {
* @hide
*/
public long getSourceNodeId() {
- return mSourceNodeId;
+ return mSourceNode != null ? mSourceNode.getSourceNodeId() : UNDEFINED;
}
/**
@@ -633,6 +639,9 @@ public class AccessibilityRecord {
public void setConnectionId(int connectionId) {
enforceNotSealed();
mConnectionId = connectionId;
+ if (mSourceNode != null) {
+ mSourceNode.setConnectionId(mConnectionId);
+ }
}
/**
@@ -644,6 +653,9 @@ public class AccessibilityRecord {
*/
public void setSealed(boolean sealed) {
mSealed = sealed;
+ if (mSourceNode != null) {
+ mSourceNode.setSealed(sealed);
+ }
}
/**
@@ -782,7 +794,9 @@ public class AccessibilityRecord {
mParcelableData = record.mParcelableData;
mText.addAll(record.mText);
mSourceWindowId = record.mSourceWindowId;
- mSourceNodeId = record.mSourceNodeId;
+ if (record.mSourceNode != null) {
+ mSourceNode = AccessibilityNodeInfo.obtain(record.mSourceNode);
+ }
mConnectionId = record.mConnectionId;
}
@@ -807,11 +821,18 @@ public class AccessibilityRecord {
mBeforeText = null;
mParcelableData = null;
mText.clear();
- mSourceNodeId = AccessibilityNodeInfo.makeNodeId(UNDEFINED, UNDEFINED);
+ clearSourceNode();
mSourceWindowId = UNDEFINED;
mConnectionId = UNDEFINED;
}
+ private void clearSourceNode() {
+ if (mSourceNode != null) {
+ mSourceNode.recycle();
+ mSourceNode = null;
+ }
+ }
+
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f733eab..e84ba99 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -25,7 +25,7 @@ import android.annotation.StringRes;
import android.annotation.StyleRes;
import android.annotation.XmlRes;
import android.app.Activity;
-import android.app.AssistStructure;
+import android.app.assist.AssistStructure;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
@@ -9443,10 +9443,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
public void onRtlPropertiesChanged(int layoutDirection) {
super.onRtlPropertiesChanged(layoutDirection);
- mTextDir = getTextDirectionHeuristic();
-
- if (mLayout != null) {
- checkForRelayout();
+ final TextDirectionHeuristic newTextDir = getTextDirectionHeuristic();
+ if (mTextDir != newTextDir) {
+ mTextDir = newTextDir;
+ if (mLayout != null) {
+ checkForRelayout();
+ }
}
}
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 678e92b..1b55557 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -100,6 +100,10 @@ public class ChooserActivity extends ResolverActivity {
mChooserListAdapter.addServiceResults(sri.originalTarget, sri.resultTargets);
unbindService(sri.connection);
mServiceConnections.remove(sri.connection);
+ if (mServiceConnections.isEmpty()) {
+ mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
+ sendVoiceChoicesIfNeeded();
+ }
break;
case CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT:
@@ -107,6 +111,7 @@ public class ChooserActivity extends ResolverActivity {
Log.d(TAG, "CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT; unbinding services");
}
unbindRemainingServices();
+ sendVoiceChoicesIfNeeded();
break;
default:
@@ -384,6 +389,8 @@ public class ChooserActivity extends ResolverActivity {
+ WATCHDOG_TIMEOUT_MILLIS + "ms");
mChooserHandler.sendEmptyMessageDelayed(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT,
WATCHDOG_TIMEOUT_MILLIS);
+ } else {
+ sendVoiceChoicesIfNeeded();
}
}
@@ -418,6 +425,10 @@ public class ChooserActivity extends ResolverActivity {
mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
}
+ void onSetupVoiceInteraction() {
+ // Do nothing. We'll send the voice stuff ourselves.
+ }
+
void onRefinementResult(TargetInfo selectedTarget, Intent matchingIntent) {
if (mRefinementResultReceiver != null) {
mRefinementResultReceiver.destroy();
@@ -956,6 +967,10 @@ public class ChooserActivity extends ResolverActivity {
if (DEBUG) Log.d(TAG, "onServiceDisconnected: " + name);
unbindService(this);
mServiceConnections.remove(this);
+ if (mServiceConnections.isEmpty()) {
+ mChooserHandler.removeMessages(CHOOSER_TARGET_SERVICE_WATCHDOG_TIMEOUT);
+ sendVoiceChoicesIfNeeded();
+ }
}
@Override
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index e14f058..fe3ab9e 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -16,10 +16,17 @@
package com.android.internal.app;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityThread;
+import android.app.VoiceInteractor;
+import android.app.VoiceInteractor.PickOptionRequest;
+import android.app.VoiceInteractor.PickOptionRequest.Option;
+import android.app.VoiceInteractor.Prompt;
+import android.app.VoiceInteractor.Request;
import android.os.AsyncTask;
import android.provider.Settings;
+import android.service.chooser.ChooserTarget;
import android.text.TextUtils;
import android.util.Slog;
import android.widget.AbsListView;
@@ -96,6 +103,7 @@ public class ResolverActivity extends Activity {
private int mProfileSwitchMessageId = -1;
private final ArrayList<Intent> mIntents = new ArrayList<>();
private ResolverComparator mResolverComparator;
+ private PickTargetOptionRequest mPickOptionRequest;
private boolean mRegistered;
private final PackageMonitor mPackageMonitor = new PackageMonitor() {
@@ -242,6 +250,9 @@ public class ResolverActivity extends Activity {
finish();
}
});
+ if (isVoiceInteraction()) {
+ rdl.setCollapsed(false);
+ }
}
if (title == null) {
@@ -313,6 +324,39 @@ public class ResolverActivity extends Activity {
});
bindProfileView();
}
+
+ if (isVoiceInteraction()) {
+ onSetupVoiceInteraction();
+ }
+ }
+
+ /**
+ * Perform any initialization needed for voice interaction.
+ */
+ void onSetupVoiceInteraction() {
+ // Do it right now. Subclasses may delay this and send it later.
+ sendVoiceChoicesIfNeeded();
+ }
+
+ void sendVoiceChoicesIfNeeded() {
+ if (!isVoiceInteraction()) {
+ // Clearly not needed.
+ return;
+ }
+
+
+ final Option[] options = new Option[mAdapter.getCount()];
+ for (int i = 0, N = options.length; i < N; i++) {
+ options[i] = optionForChooserTarget(mAdapter.getItem(i), i);
+ }
+
+ mPickOptionRequest = new PickTargetOptionRequest(
+ new Prompt(getTitle()), options, null);
+ getVoiceInteractor().submitRequest(mPickOptionRequest);
+ }
+
+ Option optionForChooserTarget(TargetInfo target, int index) {
+ return new Option(target.getDisplayLabel(), index);
}
protected final void setAdditionalTargets(Intent[] intents) {
@@ -473,6 +517,14 @@ public class ResolverActivity extends Activity {
}
@Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (!isChangingConfigurations() && mPickOptionRequest != null) {
+ mPickOptionRequest.cancel();
+ }
+ }
+
+ @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
if (mAlwaysUseOption) {
@@ -510,16 +562,12 @@ public class ResolverActivity extends Activity {
try {
ApplicationInfo appInfo = getPackageManager().getApplicationInfo(
resolveInfo.activityInfo.packageName, 0 /* default flags */);
- return versionNumberAtLeastL(appInfo.targetSdkVersion);
+ return appInfo.targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP;
} catch (NameNotFoundException e) {
return false;
}
}
- private boolean versionNumberAtLeastL(int versionNumber) {
- return versionNumber >= Build.VERSION_CODES.LOLLIPOP;
- }
-
private void setAlwaysButtonEnabled(boolean hasValidSelection, int checkedPos,
boolean filtered) {
boolean enabled = false;
@@ -1644,4 +1692,39 @@ public class ResolverActivity extends Activity {
&& match <= IntentFilter.MATCH_CATEGORY_PATH;
}
+ static class PickTargetOptionRequest extends PickOptionRequest {
+ public PickTargetOptionRequest(@Nullable Prompt prompt, Option[] options,
+ @Nullable Bundle extras) {
+ super(prompt, options, extras);
+ }
+
+ @Override
+ public void onCancel() {
+ super.onCancel();
+ final ResolverActivity ra = (ResolverActivity) getActivity();
+ if (ra != null) {
+ ra.mPickOptionRequest = null;
+ ra.finish();
+ }
+ }
+
+ @Override
+ public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
+ super.onPickOptionResult(finished, selections, result);
+ if (selections.length != 1) {
+ // TODO In a better world we would filter the UI presented here and let the
+ // user refine. Maybe later.
+ return;
+ }
+
+ final ResolverActivity ra = (ResolverActivity) getActivity();
+ if (ra != null) {
+ final TargetInfo ti = ra.mAdapter.getItem(selections[0].getIndex());
+ if (ra.onTargetSelected(ti, false)) {
+ ra.mPickOptionRequest = null;
+ ra.finish();
+ }
+ }
+ }
+ }
}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index e4ccb4b..b78eca7 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -37,6 +37,9 @@ public class MetricsLogger implements MetricsConstants {
public static final int ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215;
public static final int ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216;
public static final int ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217;
+ public static final int ACTION_BRIGHTNESS = 218;
+ public static final int ACTION_BRIGHTNESS_AUTO = 219;
+ public static final int BRIGHTNESS_DIALOG = 220;
// Temporary constants go here, to await migration to MetricsConstants.
public static void visible(Context context, int category) throws IllegalArgumentException {
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index 663c838..aea1585 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -19,6 +19,7 @@ package com.android.internal.statusbar;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
+import com.android.internal.statusbar.NotificationVisibility;
import android.service.notification.StatusBarNotification;
/** @hide */
@@ -53,8 +54,8 @@ interface IStatusBarService
int uid, int initialPid, String message, int userId);
void onClearAllNotifications(int userId);
void onNotificationClear(String pkg, String tag, int id, int userId);
- void onNotificationVisibilityChanged(
- in String[] newlyVisibleKeys, in String[] noLongerVisibleKeys);
+ void onNotificationVisibilityChanged( in NotificationVisibility[] newlyVisibleKeys,
+ in NotificationVisibility[] noLongerVisibleKeys);
void onNotificationExpansionChanged(in String key, in boolean userAction, in boolean expanded);
void setSystemUiVisibility(int vis, int mask, String cause);
void setWindowState(int window, int state);
diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.aidl b/core/java/com/android/internal/statusbar/NotificationVisibility.aidl
new file mode 100644
index 0000000..c067551
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/NotificationVisibility.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+parcelable NotificationVisibility;
+
diff --git a/core/java/com/android/internal/statusbar/NotificationVisibility.java b/core/java/com/android/internal/statusbar/NotificationVisibility.java
new file mode 100644
index 0000000..2139ad0
--- /dev/null
+++ b/core/java/com/android/internal/statusbar/NotificationVisibility.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.statusbar;
+
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+import java.util.ArrayDeque;
+import java.util.Collection;
+
+public class NotificationVisibility implements Parcelable {
+ private static final String TAG = "NoViz";
+ private static final int MAX_POOL_SIZE = 25;
+ private static ArrayDeque<NotificationVisibility> sPool = new ArrayDeque<>(MAX_POOL_SIZE);
+ private static int sNexrId = 0;
+
+ public String key;
+ public int rank;
+ public boolean visible = true;
+ /*package*/ int id;
+
+ private NotificationVisibility() {
+ id = sNexrId++;
+ }
+
+ private NotificationVisibility(String key, int rank, boolean visibile) {
+ this();
+ this.key = key;
+ this.rank = rank;
+ this.visible = visibile;
+ }
+
+ @Override
+ public String toString() {
+ return "NotificationVisibility(id=" + id
+ + "key=" + key
+ + " rank=" + rank
+ + (visible?" visible":"")
+ + " )";
+ }
+
+ @Override
+ public NotificationVisibility clone() {
+ return obtain(this.key, this.rank, this.visible);
+ }
+
+ @Override
+ public int hashCode() {
+ // allow lookups by key, which _should_ never be null.
+ return key == null ? 0 : key.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object that) {
+ // allow lookups by key, which _should_ never be null.
+ if (that instanceof NotificationVisibility) {
+ NotificationVisibility thatViz = (NotificationVisibility) that;
+ return (key == null && thatViz.key == null) || key.equals(thatViz.key);
+ }
+ return false;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(this.key);
+ out.writeInt(this.rank);
+ out.writeInt(this.visible ? 1 : 0);
+ }
+
+ private void readFromParcel(Parcel in) {
+ this.key = in.readString();
+ this.rank = in.readInt();
+ this.visible = in.readInt() != 0;
+ }
+
+ /**
+ * Return a new NotificationVisibility instance from the global pool. Allows us to
+ * avoid allocating new objects in many cases.
+ */
+ public static NotificationVisibility obtain(String key, int rank, boolean visible) {
+ NotificationVisibility vo = obtain();
+ vo.key = key;
+ vo.rank = rank;
+ vo.visible = visible;
+ return vo;
+ }
+
+ private static NotificationVisibility obtain(Parcel in) {
+ NotificationVisibility vo = obtain();
+ vo.readFromParcel(in);
+ return vo;
+ }
+
+ private static NotificationVisibility obtain() {
+ synchronized (sPool) {
+ if (!sPool.isEmpty()) {
+ return sPool.poll();
+ }
+ }
+ return new NotificationVisibility();
+ }
+
+ /**
+ * Return a NotificationVisibility instance to the global pool.
+ * <p>
+ * You MUST NOT touch the NotificationVisibility after calling this function because it has
+ * effectively been freed.
+ * </p>
+ */
+ public void recycle() {
+ if (key == null) {
+ // do nothing on multiple recycles
+ return;
+ }
+ key = null;
+ if (sPool.size() < MAX_POOL_SIZE) {
+ synchronized (sPool) {
+ sPool.offer(this);
+ }
+ }
+ }
+
+ /**
+ * Parcelable.Creator that instantiates NotificationVisibility objects
+ */
+ public static final Parcelable.Creator<NotificationVisibility> CREATOR
+ = new Parcelable.Creator<NotificationVisibility>()
+ {
+ public NotificationVisibility createFromParcel(Parcel parcel)
+ {
+ return obtain(parcel);
+ }
+
+ public NotificationVisibility[] newArray(int size)
+ {
+ return new NotificationVisibility[size];
+ }
+ };
+}
+
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 585cbc9..1071e12 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -144,6 +144,14 @@ public class ResolverDrawerLayout extends ViewGroup {
return mCollapseOffset > 0;
}
+ public void setCollapsed(boolean collapsed) {
+ if (!isLaidOut()) {
+ mOpenOnLayout = collapsed;
+ } else {
+ smoothScrollTo(collapsed ? mCollapsibleHeight : 0, 0);
+ }
+ }
+
private boolean isMoving() {
return mIsDragging || !mScroller.isFinished();
}
@@ -575,7 +583,13 @@ public class ResolverDrawerLayout extends ViewGroup {
@Override
public boolean onNestedFling(View target, float velocityX, float velocityY, boolean consumed) {
if (!consumed && Math.abs(velocityY) > mMinFlingVelocity) {
- smoothScrollTo(velocityY > 0 ? 0 : mCollapsibleHeight, velocityY);
+ if (mOnDismissedListener != null
+ && velocityY < 0 && mCollapseOffset > mCollapsibleHeight) {
+ smoothScrollTo(mCollapsibleHeight + mUncollapsibleHeight, velocityY);
+ mDismissOnScrollerFinished = true;
+ } else {
+ smoothScrollTo(velocityY > 0 ? 0 : mCollapsibleHeight, velocityY);
+ }
return true;
}
return false;
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index f5f8b1f..c9d609c 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -257,6 +257,8 @@ private:
case SENSOR_TYPE_MAGNETIC_FIELD:
case SENSOR_TYPE_ACCELEROMETER:
case SENSOR_TYPE_GYROSCOPE:
+ case SENSOR_TYPE_GRAVITY:
+ case SENSOR_TYPE_LINEAR_ACCELERATION:
status = buffer[i].vector.status;
break;
case SENSOR_TYPE_HEART_RATE:
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 5bef653..63915ed 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -436,6 +436,23 @@ static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz
return fmt;
}
+static jint LegacyCameraDevice_nativeDetectSurfaceDataspace(JNIEnv* env, jobject thiz, jobject surface) {
+ ALOGV("nativeDetectSurfaceDataspace");
+ sp<ANativeWindow> anw;
+ if ((anw = getNativeWindow(env, surface)) == NULL) {
+ ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+ return BAD_VALUE;
+ }
+ int32_t fmt = 0;
+ status_t err = anw->query(anw.get(), NATIVE_WINDOW_DEFAULT_DATASPACE, &fmt);
+ if(err != NO_ERROR) {
+ ALOGE("%s: Error while querying surface dataspace %s (%d).", __FUNCTION__, strerror(-err),
+ err);
+ return err;
+ }
+ return fmt;
+}
+
static jint LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz,
jobject surface, jintArray dimens) {
ALOGV("nativeGetSurfaceDimens");
@@ -717,6 +734,9 @@ static JNINativeMethod gCameraDeviceMethods[] = {
{ "nativeDetectSurfaceType",
"(Landroid/view/Surface;)I",
(void *)LegacyCameraDevice_nativeDetectSurfaceType },
+ { "nativeDetectSurfaceDataspace",
+ "(Landroid/view/Surface;)I",
+ (void *)LegacyCameraDevice_nativeDetectSurfaceDataspace },
{ "nativeDetectSurfaceDimens",
"(Landroid/view/Surface;[I)I",
(void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 91a3c7e..0e2ec6b 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -77,7 +77,7 @@ NativeDisplayEventReceiver::NativeDisplayEventReceiver(JNIEnv* env,
jobject receiverWeak, const sp<MessageQueue>& messageQueue) :
mReceiverWeakGlobal(env->NewGlobalRef(receiverWeak)),
mMessageQueue(messageQueue), mWaitingForVsync(false) {
- ALOGV("receiver %p ~ Initializing input event receiver.", this);
+ ALOGV("receiver %p ~ Initializing display event receiver.", this);
}
NativeDisplayEventReceiver::~NativeDisplayEventReceiver() {
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index eb28c4d..98c17c0 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -462,6 +462,12 @@ static int android_view_MotionEvent_nativeGetActionButton(JNIEnv* env, jclass cl
return event->getActionButton();
}
+static void android_view_MotionEvent_nativeSetActionButton(JNIEnv* env, jclass clazz,
+ jlong nativePtr, jint button) {
+ MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
+ event->setActionButton(button);
+}
+
static jboolean android_view_MotionEvent_nativeIsTouchEvent(JNIEnv* env, jclass clazz,
jlong nativePtr) {
MotionEvent* event = reinterpret_cast<MotionEvent*>(nativePtr);
@@ -779,6 +785,9 @@ static JNINativeMethod gMotionEventMethods[] = {
{ "nativeGetActionButton",
"(J)I",
(void*)android_view_MotionEvent_nativeGetActionButton},
+ { "nativeSetActionButton",
+ "(JI)V",
+ (void*)android_view_MotionEvent_nativeSetActionButton},
{ "nativeIsTouchEvent",
"(J)Z",
(void*)android_view_MotionEvent_nativeIsTouchEvent },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b1b772a..f9b41a9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2457,6 +2457,7 @@
<intent-filter>
<action android:name="android.intent.action.CHOOSER" />
<category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.VOICE" />
</intent-filter>
</activity>
<activity android:name="com.android.internal.app.IntentForwarderActivity"
diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml
index 18c83b4..9548e51 100644
--- a/core/res/res/xml/sms_short_codes.xml
+++ b/core/res/res/xml/sms_short_codes.xml
@@ -93,11 +93,11 @@
<!-- France: 5 digits, free: 3xxxx, premium [4-8]xxxx, plus EU:
http://clients.txtnation.com/entries/161972-france-premium-sms-short-code-requirements -->
- <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}" />
+ <shortcode country="fr" premium="[4-8]\\d{4}" free="3\\d{4}|116\\d{3}|21101" />
<!-- United Kingdom (Great Britain): 4-6 digits, common codes [5-8]xxxx, plus EU:
http://www.short-codes.com/media/Co-regulatoryCodeofPracticeforcommonshortcodes170206.pdf -->
- <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}" />
+ <shortcode country="gb" pattern="\\d{4,6}" premium="[5-8]\\d{4}" free="116\\d{3}|887" />
<!-- Georgia: 4 digits, known premium codes listed -->
<shortcode country="ge" pattern="\\d{4}" premium="801[234]|888[239]" />
@@ -184,6 +184,6 @@
<shortcode country="ua" pattern="\\d{4}" premium="444[3-9]|70[579]4|7540" />
<!-- USA: 5-6 digits (premium codes from https://www.premiumsmsrefunds.com/ShortCodes.htm) -->
- <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" free="87902" />
+ <shortcode country="us" pattern="\\d{5,6}" premium="20433|21(?:344|472)|22715|23(?:333|847)|24(?:15|28)0|25209|27(?:449|606|663)|28498|305(?:00|83)|32(?:340|941)|33(?:166|786|849)|34746|35(?:182|564)|37975|38(?:135|146|254)|41(?:366|463)|42335|43(?:355|500)|44(?:578|711|811)|45814|46(?:157|173|327)|46666|47553|48(?:221|277|669)|50(?:844|920)|51(?:062|368)|52944|54(?:723|892)|55928|56483|57370|59(?:182|187|252|342)|60339|61(?:266|982)|62478|64(?:219|898)|65(?:108|500)|69(?:208|388)|70877|71851|72(?:078|087|465)|73(?:288|588|882|909|997)|74(?:034|332|815)|76426|79213|81946|83177|84(?:103|685)|85797|86(?:234|236|666)|89616|90(?:715|842|938)|91(?:362|958)|94719|95297|96(?:040|666|835|969)|97(?:142|294|688)|99(?:689|796|807)" free="122|87902" />
</shortcodes>
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
index 250bad7..515be1d 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
@@ -113,7 +113,7 @@ public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
return result;
} else {
throw new InvalidKeySpecException(
- "Obtaining RSAPublicKeySpec not supported for " + key.getAlgorithm() + " "
+ "Obtaining ECPublicKeySpec not supported for " + key.getAlgorithm() + " "
+ ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public")
+ " key");
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
index 532b330..ff265cf 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -511,15 +511,23 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
return generateSelfSignedCertificateWithFakeSignature(publicKey);
} else {
// Key can be used to sign a certificate
- return generateSelfSignedCertificateWithValidSignature(
- privateKey, publicKey, signatureAlgorithm);
+ try {
+ return generateSelfSignedCertificateWithValidSignature(
+ privateKey, publicKey, signatureAlgorithm);
+ } catch (Exception e) {
+ // Failed to generate the self-signed certificate with valid signature. Fall back
+ // to generating a self-signed certificate with a fake signature. This is done for
+ // all exception types because we prefer key pair generation to succeed and end up
+ // producing a self-signed certificate with an invalid signature to key pair
+ // generation failing.
+ return generateSelfSignedCertificateWithFakeSignature(publicKey);
+ }
}
}
@SuppressWarnings("deprecation")
private X509Certificate generateSelfSignedCertificateWithValidSignature(
- PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm)
- throws Exception {
+ PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
certGen.setPublicKey(publicKey);
certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 3d23399..919dd48 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -71,6 +71,8 @@ import javax.security.auth.x500.X500Principal;
* <li>{@link KeyProperties#PURPOSE_SIGN},</li>
* <li>operation without requiring the user to be authenticated (see
* {@link Builder#setUserAuthenticationRequired(boolean)}),</li>
+ * <li>signing/origination at this moment in time (see {@link Builder#setKeyValidityStart(Date)}
+ * and {@link Builder#setKeyValidityForOriginationEnd(Date)}),</li>
* <li>suitable digest or {@link KeyProperties#DIGEST_NONE},</li>
* <li>(RSA keys only) padding scheme {@link KeyProperties#SIGNATURE_PADDING_RSA_PKCS1} or
* {@link KeyProperties#ENCRYPTION_PADDING_NONE}.</li>
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index d9b40ae..00add29 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -14,15 +14,13 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
-#define ATRACE_TAG ATRACE_TAG_VIEW
-
#include "LayerCache.h"
#include "LayerRenderer.h"
#include "Matrix.h"
#include "Properties.h"
#include "Rect.h"
#include "renderstate/RenderState.h"
+#include "utils/GLUtils.h"
#include "utils/TraceUtils.h"
#include <ui/Rect.h>
@@ -238,8 +236,9 @@ Layer* LayerRenderer::createRenderLayer(RenderState& renderState, uint32_t width
layer->allocateTexture();
// This should only happen if we run out of memory
- if (glGetError() != GL_NO_ERROR) {
- ALOGE("Could not allocate texture for layer (fbo=%d %dx%d)", fbo, width, height);
+ if (CC_UNLIKELY(GLUtils::dumpGLErrors())) {
+ LOG_ALWAYS_FATAL("Could not allocate texture for layer (fbo=%d %dx%d)",
+ fbo, width, height);
renderState.bindFramebuffer(previousFbo);
layer->decStrong(nullptr);
return nullptr;
diff --git a/libs/hwui/utils/GLUtils.cpp b/libs/hwui/utils/GLUtils.cpp
index 9b298ca..55104de 100644
--- a/libs/hwui/utils/GLUtils.cpp
+++ b/libs/hwui/utils/GLUtils.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#define LOG_TAG "OpenGLRenderer"
-
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
@@ -26,9 +24,11 @@
namespace android {
namespace uirenderer {
-void GLUtils::dumpGLErrors() {
+bool GLUtils::dumpGLErrors() {
+ bool errorObserved = false;
GLenum status = GL_NO_ERROR;
while ((status = glGetError()) != GL_NO_ERROR) {
+ errorObserved = true;
switch (status) {
case GL_INVALID_ENUM:
ALOGE("GL error: GL_INVALID_ENUM");
@@ -46,6 +46,7 @@ void GLUtils::dumpGLErrors() {
ALOGE("GL error: 0x%x", status);
}
}
+ return errorObserved;
}
}; // namespace uirenderer
diff --git a/libs/hwui/utils/GLUtils.h b/libs/hwui/utils/GLUtils.h
index 890e374..7020461 100644
--- a/libs/hwui/utils/GLUtils.h
+++ b/libs/hwui/utils/GLUtils.h
@@ -20,12 +20,11 @@ namespace android {
namespace uirenderer {
class GLUtils {
-private:
public:
/**
- * Print out any GL errors with ALOGE
+ * Print out any GL errors with ALOGE, returns true if any errors were found.
*/
- static void dumpGLErrors();
+ static bool dumpGLErrors();
}; // class GLUtils
diff --git a/media/java/android/media/CamcorderProfile.java b/media/java/android/media/CamcorderProfile.java
index 9609c35..d303a2e 100644
--- a/media/java/android/media/CamcorderProfile.java
+++ b/media/java/android/media/CamcorderProfile.java
@@ -150,6 +150,25 @@ public class CamcorderProfile
/**
* High speed ( >= 100fps) quality level corresponding to the lowest available resolution.
+ * <p>
+ * For all the high speed profiles defined below ((from {@link #QUALITY_HIGH_SPEED_LOW} to
+ * {@link #QUALITY_HIGH_SPEED_2160P}), they are similar as normal recording profiles, with just
+ * higher output frame rate and bit rate. Therefore, setting these profiles with
+ * {@link MediaRecorder#setProfile} without specifying any other encoding parameters will
+ * produce high speed videos rather than slow motion videos that have different capture and
+ * output (playback) frame rates. To record slow motion videos, the application must set video
+ * output (playback) frame rate and bit rate appropriately via
+ * {@link MediaRecorder#setVideoFrameRate} and {@link MediaRecorder#setVideoEncodingBitRate}
+ * based on the slow motion factor. If the application intends to do the video recording with
+ * {@link MediaCodec} encoder, it must set each individual field of {@link MediaFormat}
+ * similarly according to this CamcorderProfile.
+ * </p>
+ *
+ * @see #videoBitRate
+ * @see #videoFrameRate
+ * @see MediaRecorder
+ * @see MediaCodec
+ * @see MediaFormat
*/
public static final int QUALITY_HIGH_SPEED_LOW = 2000;
@@ -212,11 +231,56 @@ public class CamcorderProfile
/**
* The target video output bit rate in bits per second
+ * <p>
+ * This is the target recorded video output bit rate if the application configures the video
+ * recording via {@link MediaRecorder#setProfile} without specifying any other
+ * {@link MediaRecorder} encoding parameters. For example, for high speed quality profiles (from
+ * {@link #QUALITY_HIGH_SPEED_LOW} to {@link #QUALITY_HIGH_SPEED_2160P}), this is the bit rate
+ * where the video is recorded with. If the application intends to record slow motion videos
+ * with the high speed quality profiles, it must set a different video bit rate that is
+ * corresponding to the desired recording output bit rate (i.e., the encoded video bit rate
+ * during normal playback) via {@link MediaRecorder#setVideoEncodingBitRate}. For example, if
+ * {@link #QUALITY_HIGH_SPEED_720P} advertises 240fps {@link #videoFrameRate} and 64Mbps
+ * {@link #videoBitRate} in the high speed CamcorderProfile, and the application intends to
+ * record 1/8 factor slow motion recording videos, the application must set 30fps via
+ * {@link MediaRecorder#setVideoFrameRate} and 8Mbps ( {@link #videoBitRate} * slow motion
+ * factor) via {@link MediaRecorder#setVideoEncodingBitRate}. Failing to do so will result in
+ * videos with unexpected frame rate and bit rate, or {@link MediaRecorder} error if the output
+ * bit rate exceeds the encoder limit. If the application intends to do the video recording with
+ * {@link MediaCodec} encoder, it must set each individual field of {@link MediaFormat}
+ * similarly according to this CamcorderProfile.
+ * </p>
+ *
+ * @see #videoFrameRate
+ * @see MediaRecorder
+ * @see MediaCodec
+ * @see MediaFormat
*/
public int videoBitRate;
/**
- * The target video frame rate in frames per second
+ * The target video frame rate in frames per second.
+ * <p>
+ * This is the target recorded video output frame rate per second if the application configures
+ * the video recording via {@link MediaRecorder#setProfile} without specifying any other
+ * {@link MediaRecorder} encoding parameters. For example, for high speed quality profiles (from
+ * {@link #QUALITY_HIGH_SPEED_LOW} to {@link #QUALITY_HIGH_SPEED_2160P}), this is the frame rate
+ * where the video is recorded and played back with. If the application intends to create slow
+ * motion use case with the high speed quality profiles, it must set a different video frame
+ * rate that is corresponding to the desired output (playback) frame rate via
+ * {@link MediaRecorder#setVideoFrameRate}. For example, if {@link #QUALITY_HIGH_SPEED_720P}
+ * advertises 240fps {@link #videoFrameRate} in the CamcorderProfile, and the application
+ * intends to create 1/8 factor slow motion recording videos, the application must set 30fps via
+ * {@link MediaRecorder#setVideoFrameRate}. Failing to do so will result in high speed videos
+ * with normal speed playback frame rate (240fps for above example). If the application intends
+ * to do the video recording with {@link MediaCodec} encoder, it must set each individual field
+ * of {@link MediaFormat} similarly according to this CamcorderProfile.
+ * </p>
+ *
+ * @see #videoBitRate
+ * @see MediaRecorder
+ * @see MediaCodec
+ * @see MediaFormat
*/
public int videoFrameRate;
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index da5f33e..7cd086e 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -710,7 +710,7 @@ public final class TvContract {
public static final String COLUMN_LOCKED = "locked";
/**
- * The app badge icon of the app link template for this channel.
+ * The URI for the app badge icon of the app link template for this channel.
*
* <p>This small icon is overlaid at the bottom of the poster art specified by
* {@link #COLUMN_APP_LINK_POSTER_ART_URI}. The data in the column must be a URI in one of
@@ -736,9 +736,10 @@ public final class TvContract {
public static final String COLUMN_APP_LINK_ICON_URI = "app_link_icon_uri";
/**
- * The poster art used as the background of the app link template for this channel.
+ * The URI for the poster art used as the background of the app link template for this
+ * channel.
*
- * <p>The data in the column must be a URL or a URI in one of the following formats:
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
*
* <ul>
* <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
@@ -1100,6 +1101,15 @@ public final class TvContract {
/**
* The URI for the poster art of this TV program.
*
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
* <p>Can be empty.
*
* <p>Type: TEXT
@@ -1109,6 +1119,19 @@ public final class TvContract {
/**
* The URI for the thumbnail of this TV program.
*
+ * <p>The system can generate a thumbnail from the poster art if this column is not
+ * specified. Thus it is not necessary for TV input services to include a thumbnail if it is
+ * just a scaled image of the poster art.
+ *
+ * <p>The data in the column must be a URL, or a URI in one of the following formats:
+ *
+ * <ul>
+ * <li>content ({@link android.content.ContentResolver#SCHEME_CONTENT})</li>
+ * <li>android.resource ({@link android.content.ContentResolver#SCHEME_ANDROID_RESOURCE})
+ * </li>
+ * <li>file ({@link android.content.ContentResolver#SCHEME_FILE})</li>
+ * </ul>
+ *
* <p>Can be empty.
*
* <p>Type: TEXT
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index f4e4ea1..ef08e19 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -346,7 +346,7 @@ public class WifiTracker {
accessPoint.update(mLastInfo, mLastNetworkInfo);
}
- if (result.passpointNetwork) {
+ if (result.isPasspointNetwork()) {
WifiConfiguration config = mWifiManager.getMatchingWifiConfig(result);
if (config != null) {
accessPoint.update(config);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index aff6ad8..44b9d8b 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -904,16 +904,16 @@ public class SettingsProvider extends ContentProvider {
private boolean mutateSystemSetting(String name, String value, int runAsUserId,
int operation) {
- // Make sure the caller can change the settings.
- enforceWritePermission(Manifest.permission.WRITE_SETTINGS);
+ // Check for permissions first.
+ hasPermissionsToMutateSystemSettings();
// Verify whether this operation is allowed for the calling package.
if (!isAppOpWriteSettingsAllowedForCallingPackage()) {
return false;
}
- // Enforce what the calling package can mutate in the system settings.
- enforceRestrictedSystemSettingsMutationForCallingPackageLocked(operation, name);
+ // Enforce what the calling package can mutate the system settings.
+ enforceRestrictedSystemSettingsMutationForCallingPackage(operation, name);
// Resolve the userId on whose behalf the call is made.
final int callingUserId = resolveCallingUserIdEnforcingPermissionsLocked(runAsUserId);
@@ -954,6 +954,28 @@ public class SettingsProvider extends ContentProvider {
}
}
+ private boolean hasPermissionsToMutateSystemSettings() {
+ // Write secure settings is a more protected permission. If caller has it we are good.
+ if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+
+ // The write settings permission gates mutation of system settings.
+ if (getContext().checkCallingOrSelfPermission(Manifest.permission.WRITE_SETTINGS)
+ == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+
+ // Excpet we let system apps change system settings without the permission.
+ PackageInfo packageInfo = getCallingPackageInfoOrThrow();
+ if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ return true;
+ }
+
+ return false;
+ }
+
private void validateSystemSettingValue(String name, String value) {
Settings.System.Validator validator = Settings.System.VALIDATORS.get(name);
if (validator != null && !validator.validate(value)) {
@@ -1000,7 +1022,7 @@ public class SettingsProvider extends ContentProvider {
return userId;
}
- private void enforceRestrictedSystemSettingsMutationForCallingPackageLocked(int operation,
+ private void enforceRestrictedSystemSettingsMutationForCallingPackage(int operation,
String name) {
// System/root/shell can mutate whatever secure settings they want.
final int callingUid = Binder.getCallingUid();
diff --git a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
index 674356b..7838119 100644
--- a/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
+++ b/packages/SystemUI/src/com/android/systemui/assist/AssistManager.java
@@ -311,4 +311,12 @@ public class AssistManager {
public void showDisclosure() {
mAssistDisclosure.postShow();
}
+
+ public void onUserSwitched(int newUserId) {
+ updateAssistInfo();
+ }
+
+ public void prepareBeforeInvocation() {
+ updateAssistInfo();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
index d6a16fa..77c27fa 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessController.java
@@ -30,6 +30,8 @@ import android.os.UserHandle;
import android.provider.Settings;
import android.widget.ImageView;
+import com.android.internal.logging.MetricsLogger;
+
import java.util.ArrayList;
public class BrightnessController implements ToggleSlider.Listener {
@@ -195,12 +197,16 @@ public class BrightnessController implements ToggleSlider.Listener {
}
@Override
- public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value) {
+ public void onChanged(ToggleSlider view, boolean tracking, boolean automatic, int value,
+ boolean stopTracking) {
updateIcon(mAutomatic);
if (mExternalChange) return;
if (!mAutomatic) {
final int val = value + mMinimumBacklight;
+ if (stopTracking) {
+ MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS, val);
+ }
setBrightness(val);
if (!tracking) {
AsyncTask.execute(new Runnable() {
@@ -213,6 +219,9 @@ public class BrightnessController implements ToggleSlider.Listener {
}
} else {
final float adj = value / (BRIGHTNESS_ADJ_RESOLUTION / 2f) - 1;
+ if (stopTracking) {
+ MetricsLogger.action(mContext, MetricsLogger.ACTION_BRIGHTNESS_AUTO, value);
+ }
setBrightnessAdj(adj);
if (!tracking) {
AsyncTask.execute(new Runnable() {
diff --git a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
index 74267a5..cef4d34 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/BrightnessDialog.java
@@ -24,6 +24,7 @@ import android.view.Window;
import android.view.WindowManager;
import android.widget.ImageView;
+import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
/** A dialog that provides controls for adjusting the screen brightness. */
@@ -52,11 +53,13 @@ public class BrightnessDialog extends Activity {
protected void onStart() {
super.onStart();
mBrightnessController.registerCallbacks();
+ MetricsLogger.visible(this, MetricsLogger.BRIGHTNESS_DIALOG);
}
@Override
protected void onStop() {
super.onStop();
+ MetricsLogger.hidden(this, MetricsLogger.BRIGHTNESS_DIALOG);
mBrightnessController.unregisterCallbacks();
}
diff --git a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
index cdb8e69..d247711 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
+++ b/packages/SystemUI/src/com/android/systemui/settings/ToggleSlider.java
@@ -35,7 +35,8 @@ import com.android.systemui.statusbar.policy.BrightnessMirrorController;
public class ToggleSlider extends RelativeLayout {
public interface Listener {
public void onInit(ToggleSlider v);
- public void onChanged(ToggleSlider v, boolean tracking, boolean checked, int value);
+ public void onChanged(ToggleSlider v, boolean tracking, boolean checked, int value,
+ boolean stopTracking);
}
private Listener mListener;
@@ -143,7 +144,7 @@ public class ToggleSlider extends RelativeLayout {
if (mListener != null) {
mListener.onChanged(
- ToggleSlider.this, mTracking, checked, mSlider.getProgress());
+ ToggleSlider.this, mTracking, checked, mSlider.getProgress(), false);
}
if (mMirror != null) {
@@ -157,7 +158,7 @@ public class ToggleSlider extends RelativeLayout {
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (mListener != null) {
mListener.onChanged(
- ToggleSlider.this, mTracking, mToggle.isChecked(), progress);
+ ToggleSlider.this, mTracking, mToggle.isChecked(), progress, false);
}
}
@@ -166,8 +167,8 @@ public class ToggleSlider extends RelativeLayout {
mTracking = true;
if (mListener != null) {
- mListener.onChanged(
- ToggleSlider.this, mTracking, mToggle.isChecked(), mSlider.getProgress());
+ mListener.onChanged(ToggleSlider.this, mTracking, mToggle.isChecked(),
+ mSlider.getProgress(), false);
}
mToggle.setChecked(false);
@@ -183,8 +184,8 @@ public class ToggleSlider extends RelativeLayout {
mTracking = false;
if (mListener != null) {
- mListener.onChanged(
- ToggleSlider.this, mTracking, mToggle.isChecked(), mSlider.getProgress());
+ mListener.onChanged(ToggleSlider.this, mTracking, mToggle.isChecked(),
+ mSlider.getProgress(), true);
}
if (mMirrorController != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 295fdc8..9d6204c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1613,17 +1613,11 @@ public abstract class BaseStatusBar extends SystemUI implements
/**
* The LEDs are turned off when the notification panel is shown, even just a little bit.
- * This was added last-minute and is inconsistent with the way the rest of the notifications
- * are handled, because the notification isn't really cancelled. The lights are just
- * turned off. If any other notifications happen, the lights will turn back on. Steve says
- * this is what he wants. (see bug 1131461)
*/
protected void handleVisibleToUserChanged(boolean visibleToUser) {
try {
if (visibleToUser) {
- // Only stop blinking, vibrating, ringing when the user went into the shade
- // manually (SHADE or SHADE_LOCKED).
- boolean clearNotificationEffects =
+ boolean clearNotificationEffects = mShowLockscreenNotifications ||
(mState == StatusBarState.SHADE || mState == StatusBarState.SHADE_LOCKED);
mBarService.onPanelRevealed(clearNotificationEffects);
} else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 16df64c..9e6dd7e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -96,6 +96,7 @@ import android.widget.ImageView;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.keyguard.KeyguardHostView.OnDismissAction;
import com.android.keyguard.ViewMediatorCallback;
@@ -457,7 +458,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private int mDisabledUnmodified2;
/** Keys of notifications currently visible to the user. */
- private final ArraySet<String> mCurrentlyVisibleNotifications = new ArraySet<String>();
+ private final ArraySet<NotificationVisibility> mCurrentlyVisibleNotifications =
+ new ArraySet<>();
private long mLastVisibilityReportUptimeMs;
private final ShadeUpdates mShadeUpdates = new ShadeUpdates();
@@ -471,9 +473,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private int mLastLoggedStateFingerprint;
private static final int VISIBLE_LOCATIONS = StackViewState.LOCATION_FIRST_CARD
- | StackViewState.LOCATION_TOP_STACK_PEEKING
- | StackViewState.LOCATION_MAIN_AREA
- | StackViewState.LOCATION_BOTTOM_STACK_PEEKING;
+ | StackViewState.LOCATION_MAIN_AREA;
private final OnChildLocationsChangedListener mNotificationLocationsChangedListener =
new OnChildLocationsChangedListener() {
@@ -498,12 +498,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Tracks notifications currently visible in mNotificationStackScroller and
// emits visibility events via NoMan on changes.
private final Runnable mVisibilityReporter = new Runnable() {
- private final ArrayList<String> mTmpNewlyVisibleNotifications = new ArrayList<String>();
- private final ArrayList<String> mTmpCurrentlyVisibleNotifications = new ArrayList<String>();
+ private final ArraySet<NotificationVisibility> mTmpNewlyVisibleNotifications =
+ new ArraySet<>();
+ private final ArraySet<NotificationVisibility> mTmpCurrentlyVisibleNotifications =
+ new ArraySet<>();
+ private final ArraySet<NotificationVisibility> mTmpNoLongerVisibleNotifications =
+ new ArraySet<>();
@Override
public void run() {
mLastVisibilityReportUptimeMs = SystemClock.uptimeMillis();
+ final String mediaKey = getCurrentMediaNotificationKey();
// 1. Loop over mNotificationData entries:
// A. Keep list of visible notifications.
@@ -518,31 +523,45 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
for (int i = 0; i < N; i++) {
Entry entry = activeNotifications.get(i);
String key = entry.notification.getKey();
- boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(key);
- boolean currentlyVisible =
+ boolean isVisible =
(mStackScroller.getChildLocation(entry.row) & VISIBLE_LOCATIONS) != 0;
- if (currentlyVisible) {
+ NotificationVisibility visObj = NotificationVisibility.obtain(key, i, isVisible);
+ boolean previouslyVisible = mCurrentlyVisibleNotifications.contains(visObj);
+ if (isVisible) {
// Build new set of visible notifications.
- mTmpCurrentlyVisibleNotifications.add(key);
- }
- if (!previouslyVisible && currentlyVisible) {
- mTmpNewlyVisibleNotifications.add(key);
+ mTmpCurrentlyVisibleNotifications.add(visObj);
+ if (!previouslyVisible) {
+ mTmpNewlyVisibleNotifications.add(visObj);
+ }
+ } else {
+ // release object
+ visObj.recycle();
}
}
- ArraySet<String> noLongerVisibleNotifications = mCurrentlyVisibleNotifications;
- noLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
+ mTmpNoLongerVisibleNotifications.addAll(mCurrentlyVisibleNotifications);
+ mTmpNoLongerVisibleNotifications.removeAll(mTmpCurrentlyVisibleNotifications);
logNotificationVisibilityChanges(
- mTmpNewlyVisibleNotifications, noLongerVisibleNotifications);
+ mTmpNewlyVisibleNotifications, mTmpNoLongerVisibleNotifications);
- mCurrentlyVisibleNotifications.clear();
+ recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
mCurrentlyVisibleNotifications.addAll(mTmpCurrentlyVisibleNotifications);
- mTmpNewlyVisibleNotifications.clear();
+ recycleAllVisibilityObjects(mTmpNoLongerVisibleNotifications);
mTmpCurrentlyVisibleNotifications.clear();
+ mTmpNewlyVisibleNotifications.clear();
+ mTmpNoLongerVisibleNotifications.clear();
}
};
+ private void recycleAllVisibilityObjects(ArraySet<NotificationVisibility> array) {
+ final int N = array.size();
+ for (int i = 0 ; i < N; i++) {
+ array.valueAt(i).recycle();
+ }
+ array.clear();
+ }
+
private final View.OnClickListener mOverflowClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -1028,6 +1047,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private int mShowSearchHoldoff = 0;
private Runnable mInvokeAssist = new Runnable() {
public void run() {
+ mAssistManager.prepareBeforeInvocation();
invokeAssistGesture(true /* vibrate */);
awakenDreams();
if (mNavigationBarView != null) {
@@ -2917,6 +2937,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
updateNotifications();
resetUserSetupObserver();
setControllerUsers();
+ mAssistManager.onUserSwitched(newUserId);
}
private void setControllerUsers() {
@@ -2987,9 +3008,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
// Report all notifications as invisible and turn down the
// reporter.
if (!mCurrentlyVisibleNotifications.isEmpty()) {
- logNotificationVisibilityChanges(
- Collections.<String>emptyList(), mCurrentlyVisibleNotifications);
- mCurrentlyVisibleNotifications.clear();
+ logNotificationVisibilityChanges(Collections.<NotificationVisibility>emptyList(),
+ mCurrentlyVisibleNotifications);
+ recycleAllVisibilityObjects(mCurrentlyVisibleNotifications);
}
mHandler.removeCallbacks(mVisibilityReporter);
mStackScroller.setChildLocationsChangedListener(null);
@@ -3007,18 +3028,27 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
private void logNotificationVisibilityChanges(
- Collection<String> newlyVisible, Collection<String> noLongerVisible) {
+ Collection<NotificationVisibility> newlyVisible,
+ Collection<NotificationVisibility> noLongerVisible) {
if (newlyVisible.isEmpty() && noLongerVisible.isEmpty()) {
return;
}
- String[] newlyVisibleAr = newlyVisible.toArray(new String[newlyVisible.size()]);
- String[] noLongerVisibleAr = noLongerVisible.toArray(new String[noLongerVisible.size()]);
+ NotificationVisibility[] newlyVisibleAr =
+ newlyVisible.toArray(new NotificationVisibility[newlyVisible.size()]);
+ NotificationVisibility[] noLongerVisibleAr =
+ noLongerVisible.toArray(new NotificationVisibility[noLongerVisible.size()]);
try {
mBarService.onNotificationVisibilityChanged(newlyVisibleAr, noLongerVisibleAr);
} catch (RemoteException e) {
// Ignore.
}
- setNotificationsShown(newlyVisibleAr);
+
+ final int N = newlyVisible.size();
+ String[] newlyVisibleKeyAr = new String[N];
+ for (int i = 0; i < N; i++) {
+ newlyVisibleKeyAr[i] = newlyVisibleAr[i].key;
+ }
+ setNotificationsShown(newlyVisibleKeyAr);
}
// State logging
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index 2b76c31..a5b244e 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -150,13 +150,23 @@ public class QsTuner extends Fragment implements Callback {
}
public void onStartDrag() {
- mDropTarget.setVisibility(View.VISIBLE);
- mAddTarget.setVisibility(View.GONE);
+ mDropTarget.post(new Runnable() {
+ @Override
+ public void run() {
+ mDropTarget.setVisibility(View.VISIBLE);
+ mAddTarget.setVisibility(View.GONE);
+ }
+ });
}
public void stopDrag() {
- mDropTarget.setVisibility(View.GONE);
- mAddTarget.setVisibility(View.VISIBLE);
+ mDropTarget.post(new Runnable() {
+ @Override
+ public void run() {
+ mDropTarget.setVisibility(View.GONE);
+ mAddTarget.setVisibility(View.VISIBLE);
+ }
+ });
}
@Override
@@ -230,9 +240,16 @@ public class QsTuner extends Fragment implements Callback {
public void showAddDialog() {
List<String> tiles = mTileSpecs;
+ int numBroadcast = 0;
+ for (int i = 0; i < tiles.size(); i++) {
+ if (tiles.get(i).startsWith(IntentTile.PREFIX)) {
+ numBroadcast++;
+ }
+ }
String[] defaults =
getContext().getString(R.string.quick_settings_tiles_default).split(",");
- final String[] available = new String[defaults.length + 1 - tiles.size()];
+ final String[] available = new String[defaults.length + 1
+ - (tiles.size() - numBroadcast)];
final String[] availableTiles = new String[available.length];
int index = 0;
for (int i = 0; i < defaults.length; i++) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 25d4d5e..d9e5b75 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -23,6 +23,7 @@ import static android.net.ConnectivityManager.TYPE_NONE;
import static android.net.ConnectivityManager.TYPE_VPN;
import static android.net.ConnectivityManager.getNetworkTypeName;
import static android.net.ConnectivityManager.isNetworkTypeValid;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
@@ -1869,7 +1870,14 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (nai == null) {
loge("EVENT_NETWORK_CAPABILITIES_CHANGED from unknown NetworkAgent");
} else {
- updateCapabilities(nai, (NetworkCapabilities)msg.obj);
+ final NetworkCapabilities networkCapabilities =
+ (NetworkCapabilities)msg.obj;
+ if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL) ||
+ networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
+ Slog.wtf(TAG, "BUG: " + nai + " has stateful capability.");
+ }
+ updateCapabilities(nai, networkCapabilities,
+ NascentState.NOT_JUST_VALIDATED);
}
break;
}
@@ -1956,20 +1964,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (isLiveNetworkAgent(nai, "EVENT_NETWORK_TESTED")) {
final boolean valid =
(msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
- final boolean validationChanged = (valid != nai.lastValidated);
- nai.lastValidated = valid;
- if (valid) {
- if (DBG) log("Validated " + nai.name());
- nai.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
- if (!nai.everValidated) {
- nai.everValidated = true;
- rematchNetworkAndRequests(nai, NascentState.JUST_VALIDATED,
- ReapUnvalidatedNetworks.REAP);
- // If score has changed, rebroadcast to NetworkFactories. b/17726566
- sendUpdatedScoreToFactories(nai);
- }
- } else {
- nai.networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
+ if (DBG) log(nai.name() + " validation " + (valid ? " passed" : "failed"));
+ if (valid != nai.lastValidated) {
+ final int oldScore = nai.getCurrentScore();
+ final NascentState nascent = (valid && !nai.everValidated) ?
+ NascentState.JUST_VALIDATED : NascentState.NOT_JUST_VALIDATED;
+ nai.lastValidated = valid;
+ nai.everValidated |= valid;
+ updateCapabilities(nai, nai.networkCapabilities, nascent);
+ // If score has changed, rebroadcast to NetworkFactories. b/17726566
+ if (oldScore != nai.getCurrentScore()) sendUpdatedScoreToFactories(nai);
}
updateInetCondition(nai);
// Let the NetworkAgent know the state of its network
@@ -1977,10 +1981,6 @@ public class ConnectivityService extends IConnectivityManager.Stub
android.net.NetworkAgent.CMD_REPORT_NETWORK_STATUS,
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
0, null);
-
- if (validationChanged) {
- notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_CAP_CHANGED);
- }
}
break;
}
@@ -1993,18 +1993,25 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: {
final int netId = msg.arg2;
- if (msg.arg1 == 0) {
+ final boolean visible = (msg.arg1 != 0);
+ final NetworkAgentInfo nai;
+ synchronized (mNetworkForNetId) {
+ nai = mNetworkForNetId.get(netId);
+ }
+ // If captive portal status has changed, update capabilities.
+ if (nai != null && (visible != nai.lastCaptivePortalDetected)) {
+ nai.lastCaptivePortalDetected = visible;
+ nai.everCaptivePortalDetected |= visible;
+ updateCapabilities(nai, nai.networkCapabilities,
+ NascentState.NOT_JUST_VALIDATED);
+ }
+ if (!visible) {
setProvNotificationVisibleIntent(false, netId, null, 0, null, null);
} else {
- final NetworkAgentInfo nai;
- synchronized (mNetworkForNetId) {
- nai = mNetworkForNetId.get(netId);
- }
if (nai == null) {
loge("EVENT_PROVISIONING_NOTIFICATION from unknown NetworkMonitor");
break;
}
- nai.captivePortalDetected = true;
setProvNotificationVisibleIntent(true, netId, NotificationType.SIGN_IN,
nai.networkInfo.getType(),nai.networkInfo.getExtraInfo(),
(PendingIntent)msg.obj);
@@ -2390,7 +2397,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
if (accept != nai.networkMisc.acceptUnvalidated) {
int oldScore = nai.getCurrentScore();
nai.networkMisc.acceptUnvalidated = accept;
- rematchAllNetworksAndRequests(nai, oldScore);
+ rematchAllNetworksAndRequests(nai, oldScore, NascentState.NOT_JUST_VALIDATED);
sendUpdatedScoreToFactories(nai);
}
@@ -2426,7 +2433,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Only prompt if the network is unvalidated and was explicitly selected by the user, and if
// we haven't already been told to switch to it regardless of whether it validated or not.
// Also don't prompt on captive portals because we're already prompting the user to sign in.
- if (nai == null || nai.everValidated || nai.captivePortalDetected ||
+ if (nai == null || nai.everValidated || nai.everCaptivePortalDetected ||
!nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
return;
}
@@ -3571,12 +3578,24 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
+ private void ensureImmutableCapabilities(NetworkCapabilities networkCapabilities) {
+ if (networkCapabilities.hasCapability(NET_CAPABILITY_VALIDATED)) {
+ throw new IllegalArgumentException(
+ "Cannot request network with NET_CAPABILITY_VALIDATED");
+ }
+ if (networkCapabilities.hasCapability(NET_CAPABILITY_CAPTIVE_PORTAL)) {
+ throw new IllegalArgumentException(
+ "Cannot request network with NET_CAPABILITY_CAPTIVE_PORTAL");
+ }
+ }
+
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
networkCapabilities = new NetworkCapabilities(networkCapabilities);
enforceNetworkRequestPermissions(networkCapabilities);
enforceMeteredApnPolicy(networkCapabilities);
+ ensureImmutableCapabilities(networkCapabilities);
if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
throw new IllegalArgumentException("Bad timeout specified");
@@ -3645,6 +3664,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
networkCapabilities = new NetworkCapabilities(networkCapabilities);
enforceNetworkRequestPermissions(networkCapabilities);
enforceMeteredApnPolicy(networkCapabilities);
+ ensureImmutableCapabilities(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId());
@@ -4046,18 +4066,35 @@ public class ConnectivityService extends IConnectivityManager.Stub
mNumDnsEntries = last;
}
+ /**
+ * Update the NetworkCapabilities for {@code networkAgent} to {@code networkCapabilities}
+ * augmented with any stateful capabilities implied from {@code networkAgent}
+ * (e.g., validated status and captive portal status).
+ *
+ * @param networkAgent the network having its capabilities updated.
+ * @param networkCapabilities the new network capabilities.
+ * @param nascent indicates whether {@code networkAgent} was validated
+ * (i.e. had everValidated set for the first time) immediately prior to this call.
+ */
private void updateCapabilities(NetworkAgentInfo networkAgent,
- NetworkCapabilities networkCapabilities) {
+ NetworkCapabilities networkCapabilities, NascentState nascent) {
+ // Don't modify caller's NetworkCapabilities.
+ networkCapabilities = new NetworkCapabilities(networkCapabilities);
+ if (networkAgent.lastValidated) {
+ networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
+ } else {
+ networkCapabilities.removeCapability(NET_CAPABILITY_VALIDATED);
+ }
+ if (networkAgent.lastCaptivePortalDetected) {
+ networkCapabilities.addCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
+ } else {
+ networkCapabilities.removeCapability(NET_CAPABILITY_CAPTIVE_PORTAL);
+ }
if (!Objects.equals(networkAgent.networkCapabilities, networkCapabilities)) {
synchronized (networkAgent) {
networkAgent.networkCapabilities = networkCapabilities;
}
- if (networkAgent.lastValidated) {
- networkAgent.networkCapabilities.addCapability(NET_CAPABILITY_VALIDATED);
- // There's no need to remove the capability if we think the network is unvalidated,
- // because NetworkAgents don't set the validated capability.
- }
- rematchAllNetworksAndRequests(networkAgent, networkAgent.getCurrentScore());
+ rematchAllNetworksAndRequests(networkAgent, networkAgent.getCurrentScore(), nascent);
notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_CAP_CHANGED);
}
}
@@ -4401,15 +4438,21 @@ public class ConnectivityService extends IConnectivityManager.Stub
}
}
- // Attempt to rematch all Networks with NetworkRequests. This may result in Networks
- // being disconnected.
- // If only one Network's score or capabilities have been modified since the last time
- // this function was called, pass this Network in via the "changed" arugment, otherwise
- // pass null.
- // If only one Network has been changed but its NetworkCapabilities have not changed,
- // pass in the Network's score (from getCurrentScore()) prior to the change via
- // "oldScore", otherwise pass changed.getCurrentScore() or 0 if "changed" is null.
- private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore) {
+ /**
+ * Attempt to rematch all Networks with NetworkRequests. This may result in Networks
+ * being disconnected.
+ * @param changed If only one Network's score or capabilities have been modified since the last
+ * time this function was called, pass this Network in this argument, otherwise pass
+ * null.
+ * @param oldScore If only one Network has been changed but its NetworkCapabilities have not
+ * changed, pass in the Network's score (from getCurrentScore()) prior to the change via
+ * this argument, otherwise pass {@code changed.getCurrentScore()} or 0 if
+ * {@code changed} is {@code null}. This is because NetworkCapabilities influence a
+ * network's score.
+ * @param nascent indicates if {@code changed} has just been validated.
+ */
+ private void rematchAllNetworksAndRequests(NetworkAgentInfo changed, int oldScore,
+ NascentState nascent) {
// TODO: This may get slow. The "changed" parameter is provided for future optimization
// to avoid the slowness. It is not simply enough to process just "changed", for
// example in the case where "changed"'s score decreases and another network should begin
@@ -4418,9 +4461,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
// Optimization: Only reprocess "changed" if its score improved. This is safe because it
// can only add more NetworkRequests satisfied by "changed", and this is exactly what
// rematchNetworkAndRequests() handles.
- if (changed != null && oldScore < changed.getCurrentScore()) {
- rematchNetworkAndRequests(changed, NascentState.NOT_JUST_VALIDATED,
- ReapUnvalidatedNetworks.REAP);
+ if (changed != null &&
+ (oldScore < changed.getCurrentScore() || nascent == NascentState.JUST_VALIDATED)) {
+ rematchNetworkAndRequests(changed, nascent, ReapUnvalidatedNetworks.REAP);
} else {
for (Iterator i = mNetworkAgentInfos.values().iterator(); i.hasNext(); ) {
rematchNetworkAndRequests((NetworkAgentInfo)i.next(),
@@ -4547,7 +4590,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
final int oldScore = nai.getCurrentScore();
nai.setCurrentScore(score);
- rematchAllNetworksAndRequests(nai, oldScore);
+ rematchAllNetworksAndRequests(nai, oldScore, NascentState.NOT_JUST_VALIDATED);
sendUpdatedScoreToFactories(nai);
}
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 49d4c22..43b640b 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -74,7 +74,7 @@ option java_package com.android.server
# when a notification has been canceled
27530 notification_canceled (key|3),(reason|1),(lifespan|1),(freshness|1),(exposure|1)
# replaces 27510 with a row per notification
-27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1)
+27531 notification_visibility (key|3),(visibile|1),(lifespan|1),(freshness|1),(exposure|1),(rank|1)
# a notification emited noise, vibration, or light
27532 notification_alert (key|3),(buzz|1),(beep|1),(blink|1)
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index baa55e7..7afb192 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -214,9 +214,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
*/
@GuardedBy("mQuotaLock")
private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
-
- private boolean mStandbyChainEnabled = false;
- private boolean mDozableChainEnabled = false;
+ /** Set of states for the child firewall chains. True if the chain is active. */
+ @GuardedBy("mQuotaLock")
+ final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
private Object mIdleTimerLock = new Object();
/** Set of interfaces with active idle timers. */
@@ -307,9 +307,6 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
public void systemReady() {
- // init firewall states
- mDozableChainEnabled = false;
- mStandbyChainEnabled = true;
prepareNativeDaemon();
if (DBG) Slog.d(TAG, "Prepared");
}
@@ -611,7 +608,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
uidFirewallRules.valueAt(i));
}
}
- if (mStandbyChainEnabled) {
+ if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)) {
setFirewallChainEnabled(FIREWALL_CHAIN_STANDBY, true);
}
@@ -625,7 +622,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
uidFirewallRules.valueAt(i));
}
}
- if (mDozableChainEnabled) {
+ if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
}
}
@@ -2013,24 +2010,31 @@ public class NetworkManagementService extends INetworkManagementService.Stub
@Override
public void setFirewallChainEnabled(int chain, boolean enable) {
enforceSystemUid();
- final String operation = enable ? "enable_chain" : "disable_chain";
- try {
- String chainName;
- switch(chain) {
- case FIREWALL_CHAIN_STANDBY:
- chainName = FIREWALL_CHAIN_NAME_STANDBY;
- mStandbyChainEnabled = enable;
- break;
- case FIREWALL_CHAIN_DOZABLE:
- chainName = FIREWALL_CHAIN_NAME_DOZABLE;
- mDozableChainEnabled = enable;
- break;
- default:
- throw new IllegalArgumentException("Bad child chain: " + chain);
+ synchronized (mQuotaLock) {
+ if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
+ mFirewallChainStates.get(chain) == enable) {
+ // All is the same, nothing to do.
+ return;
+ }
+ mFirewallChainStates.put(chain, enable);
+
+ final String operation = enable ? "enable_chain" : "disable_chain";
+ try {
+ String chainName;
+ switch(chain) {
+ case FIREWALL_CHAIN_STANDBY:
+ chainName = FIREWALL_CHAIN_NAME_STANDBY;
+ break;
+ case FIREWALL_CHAIN_DOZABLE:
+ chainName = FIREWALL_CHAIN_NAME_DOZABLE;
+ break;
+ default:
+ throw new IllegalArgumentException("Bad child chain: " + chain);
+ }
+ mConnector.execute("firewall", operation, chainName);
+ } catch (NativeDaemonConnectorException e) {
+ throw e.rethrowAsParcelableException();
}
- mConnector.execute("firewall", operation, chainName);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
}
}
@@ -2048,27 +2052,29 @@ public class NetworkManagementService extends INetworkManagementService.Stub
@Override
public void setFirewallUidRules(int chain, int[] uids, int[] rules) {
enforceSystemUid();
- SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
- SparseIntArray newRules = new SparseIntArray();
- // apply new set of rules
- for (int index = uids.length - 1; index >= 0; --index) {
- int uid = uids[index];
- int rule = rules[index];
- setFirewallUidRule(chain, uid, rule);
- newRules.put(uid, rule);
- }
- // collect the rules to remove.
- SparseIntArray rulesToRemove = new SparseIntArray();
- for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
- int uid = uidFirewallRules.keyAt(index);
- if (newRules.indexOfKey(uid) < 0) {
- rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
+ synchronized (mQuotaLock) {
+ SparseIntArray uidFirewallRules = getUidFirewallRules(chain);
+ SparseIntArray newRules = new SparseIntArray();
+ // apply new set of rules
+ for (int index = uids.length - 1; index >= 0; --index) {
+ int uid = uids[index];
+ int rule = rules[index];
+ setFirewallUidRule(chain, uid, rule);
+ newRules.put(uid, rule);
+ }
+ // collect the rules to remove.
+ SparseIntArray rulesToRemove = new SparseIntArray();
+ for (int index = uidFirewallRules.size() - 1; index >= 0; --index) {
+ int uid = uidFirewallRules.keyAt(index);
+ if (newRules.indexOfKey(uid) < 0) {
+ rulesToRemove.put(uid, FIREWALL_RULE_DEFAULT);
+ }
+ }
+ // remove dead rules
+ for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
+ int uid = rulesToRemove.keyAt(index);
+ setFirewallUidRuleInternal(chain, uid, FIREWALL_RULE_DEFAULT);
}
- }
- // remove dead rules
- for (int index = rulesToRemove.size() - 1; index >= 0; --index) {
- int uid = rulesToRemove.keyAt(index);
- setFirewallUidRuleInternal(chain, uid, FIREWALL_RULE_DEFAULT);
}
}
@@ -2094,34 +2100,43 @@ public class NetworkManagementService extends INetworkManagementService.Stub
}
try {
- String ruleName;
- if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
- if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
- ruleName = "allow";
- } else {
- ruleName = "deny";
- }
- } else { // Blacklist mode
- if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
- ruleName = "deny";
- } else {
- ruleName = "allow";
- }
- }
+ String ruleName = getFirewallRuleName(chain, rule);
+ String oldRuleName = getFirewallRuleName(chain, oldUidFirewallRule);
if (rule == NetworkPolicyManager.FIREWALL_RULE_DEFAULT) {
uidFirewallRules.delete(uid);
} else {
uidFirewallRules.put(uid, rule);
}
- mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
- ruleName);
+
+ if (!ruleName.equals(oldRuleName)) {
+ mConnector.execute("firewall", "set_uid_rule", getFirewallChainName(chain), uid,
+ ruleName);
+ }
} catch (NativeDaemonConnectorException e) {
throw e.rethrowAsParcelableException();
}
}
}
+ private @NonNull String getFirewallRuleName(int chain, int rule) {
+ String ruleName;
+ if (getFirewallType(chain) == FIREWALL_TYPE_WHITELIST) {
+ if (rule == NetworkPolicyManager.FIREWALL_RULE_ALLOW) {
+ ruleName = "allow";
+ } else {
+ ruleName = "deny";
+ }
+ } else { // Blacklist mode
+ if (rule == NetworkPolicyManager.FIREWALL_RULE_DENY) {
+ ruleName = "deny";
+ } else {
+ ruleName = "allow";
+ }
+ }
+ return ruleName;
+ }
+
private @NonNull SparseIntArray getUidFirewallRules(int chain) {
switch (chain) {
case FIREWALL_CHAIN_STANDBY:
@@ -2272,7 +2287,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
pw.println("]");
}
- pw.println("UID firewall standby chain enabled: " + mStandbyChainEnabled);
+ pw.println("UID firewall standby chain enabled: " +
+ mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
synchronized (mUidFirewallStandbyRules) {
pw.print("UID firewall standby rule: [");
final int size = mUidFirewallStandbyRules.size();
@@ -2285,7 +2301,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
pw.println("]");
}
- pw.println("UID firewall dozable chain enabled: " + mDozableChainEnabled);
+ pw.println("UID firewall dozable chain enabled: " +
+ mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
synchronized (mUidFirewallDozableRules) {
pw.print("UID firewall dozable rule: [");
final int size = mUidFirewallDozableRules.size();
diff --git a/services/core/java/com/android/server/camera/CameraService.java b/services/core/java/com/android/server/camera/CameraService.java
index 9347c24..0be24f4 100644
--- a/services/core/java/com/android/server/camera/CameraService.java
+++ b/services/core/java/com/android/server/camera/CameraService.java
@@ -16,7 +16,10 @@
package com.android.server.camera;
import android.app.ActivityManager;
+import android.content.BroadcastReceiver;
import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
import android.content.pm.UserInfo;
import android.hardware.ICameraService;
import android.hardware.ICameraServiceProxy;
@@ -67,6 +70,32 @@ public class CameraService extends SystemService implements Handler.Callback {
private final Object mLock = new Object();
private Set<Integer> mEnabledCameraUsers;
+ private int mLastUser;
+
+ private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ final String action = intent.getAction();
+ if (action == null) return;
+
+ switch (action) {
+ case Intent.ACTION_USER_ADDED:
+ case Intent.ACTION_USER_REMOVED:
+ case Intent.ACTION_USER_INFO_CHANGED:
+ case Intent.ACTION_MANAGED_PROFILE_ADDED:
+ case Intent.ACTION_MANAGED_PROFILE_REMOVED:
+ synchronized(mLock) {
+ // Return immediately if we haven't seen any users start yet
+ if (mEnabledCameraUsers == null) return;
+ switchUserLocked(mLastUser);
+ }
+ break;
+ default:
+ break; // do nothing
+ }
+
+ }
+ };
private final ICameraServiceProxy.Stub mCameraServiceProxy = new ICameraServiceProxy.Stub() {
@Override
@@ -103,6 +132,15 @@ public class CameraService extends SystemService implements Handler.Callback {
// Should never see this unless someone messes up the SystemServer service boot order.
throw new IllegalStateException("UserManagerService must start before CameraService!");
}
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(Intent.ACTION_USER_ADDED);
+ filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_USER_INFO_CHANGED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
+ filter.addAction(Intent.ACTION_MANAGED_PROFILE_REMOVED);
+ mContext.registerReceiver(mIntentReceiver, filter);
+
publishBinderService(CAMERA_SERVICE_PROXY_BINDER_NAME, mCameraServiceProxy);
}
@@ -125,6 +163,7 @@ public class CameraService extends SystemService implements Handler.Callback {
private void switchUserLocked(int userHandle) {
Set<Integer> currentUserHandles = getEnabledUserHandles(userHandle);
+ mLastUser = userHandle;
if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
// Some user handles have been added or removed, update mediaserver.
mEnabledCameraUsers = currentUserHandles;
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 3bf1183..51c6628 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -45,6 +45,7 @@ public class NetworkAgentInfo {
// This Network object is always valid.
public final Network network;
public LinkProperties linkProperties;
+ // This should only be modified via ConnectivityService.updateCapabilities().
public NetworkCapabilities networkCapabilities;
public final NetworkMonitor networkMonitor;
public final NetworkMisc networkMisc;
@@ -66,7 +67,10 @@ public class NetworkAgentInfo {
// Whether a captive portal was ever detected on this network.
// This is a sticky bit; once set it is never cleared.
- public boolean captivePortalDetected;
+ public boolean everCaptivePortalDetected;
+
+ // Whether a captive portal was found during the last network validation attempt.
+ public boolean lastCaptivePortalDetected;
// This represents the last score received from the NetworkAgent.
private int currentScore;
@@ -174,7 +178,8 @@ public class NetworkAgentInfo {
"created{" + created + "} " +
"explicitlySelected{" + networkMisc.explicitlySelected + "} " +
"acceptUnvalidated{" + networkMisc.acceptUnvalidated + "} " +
- "captivePortalDetected{" + captivePortalDetected + "} " +
+ "everCaptivePortalDetected{" + everCaptivePortalDetected + "} " +
+ "lastCaptivePortalDetected{" + lastCaptivePortalDetected + "} " +
"}";
}
diff --git a/services/core/java/com/android/server/content/AppIdleMonitor.java b/services/core/java/com/android/server/content/AppIdleMonitor.java
index 9598de8..fe5c2da 100644
--- a/services/core/java/com/android/server/content/AppIdleMonitor.java
+++ b/services/core/java/com/android/server/content/AppIdleMonitor.java
@@ -18,11 +18,6 @@ package com.android.server.content;
import android.app.usage.UsageStatsManagerInternal;
import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
import android.os.UserHandle;
import com.android.server.LocalServices;
@@ -31,53 +26,32 @@ import com.android.server.LocalServices;
* Helper to listen for app idle and charging status changes and restart backed off
* sync operations.
*/
-class AppIdleMonitor implements AppIdleStateChangeListener {
+class AppIdleMonitor extends AppIdleStateChangeListener {
private final SyncManager mSyncManager;
private final UsageStatsManagerInternal mUsageStats;
- final BatteryManager mBatteryManager;
- /** Is the device currently plugged into power. */
- private boolean mPluggedIn;
+ private boolean mAppIdleParoleOn;
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- onPluggedIn(mBatteryManager.isCharging());
- }
- };
-
- AppIdleMonitor(SyncManager syncManager, Context context) {
+ AppIdleMonitor(SyncManager syncManager) {
mSyncManager = syncManager;
mUsageStats = LocalServices.getService(UsageStatsManagerInternal.class);
- mUsageStats.addAppIdleStateChangeListener(this);
- mBatteryManager = context.getSystemService(BatteryManager.class);
- mPluggedIn = isPowered();
- registerReceivers(context);
- }
-
- private void registerReceivers(Context context) {
- // Monitor battery charging state
- IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING);
- filter.addAction(BatteryManager.ACTION_DISCHARGING);
- context.registerReceiver(mReceiver, filter);
- }
+ mAppIdleParoleOn = mUsageStats.isAppIdleParoleOn();
- private boolean isPowered() {
- return mBatteryManager.isCharging();
+ mUsageStats.addAppIdleStateChangeListener(this);
}
- void onPluggedIn(boolean pluggedIn) {
- if (mPluggedIn == pluggedIn) {
+ void setAppIdleParoleOn(boolean appIdleParoleOn) {
+ if (mAppIdleParoleOn == appIdleParoleOn) {
return;
}
- mPluggedIn = pluggedIn;
- if (mPluggedIn) {
+ mAppIdleParoleOn = appIdleParoleOn;
+ if (mAppIdleParoleOn) {
mSyncManager.onAppNotIdle(null, UserHandle.USER_ALL);
}
}
boolean isAppIdle(String packageName, int userId) {
- return !mPluggedIn && mUsageStats.isAppIdle(packageName, userId);
+ return !mAppIdleParoleOn && mUsageStats.isAppIdle(packageName, userId);
}
@Override
@@ -86,4 +60,9 @@ class AppIdleMonitor implements AppIdleStateChangeListener {
if (idle) return;
mSyncManager.onAppNotIdle(packageName, userId);
}
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
+ setAppIdleParoleOn(isParoleOn);
+ }
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 7415b0e..658f6f8 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -19,6 +19,7 @@ package com.android.server.content;
import android.accounts.Account;
import android.accounts.AccountAndUser;
import android.accounts.AccountManager;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.AlarmManager;
import android.app.AppGlobals;
@@ -461,7 +462,7 @@ public class SyncManager {
mSyncAlarmIntent = PendingIntent.getBroadcast(
mContext, 0 /* ignored */, new Intent(ACTION_SYNC_ALARM), 0);
- mAppIdleMonitor = new AppIdleMonitor(this, mContext);
+ mAppIdleMonitor = new AppIdleMonitor(this);
IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
context.registerReceiver(mConnectivityIntentReceiver, intentFilter);
@@ -1271,7 +1272,7 @@ public class SyncManager {
* @param userId The user for which the package has become active. Can be USER_ALL if
* the device just plugged in.
*/
- void onAppNotIdle(String packageName, int userId) {
+ void onAppNotIdle(@Nullable String packageName, int userId) {
synchronized (mSyncQueue) {
// For all sync operations in sync queue, if marked as idle, compare with package name
// and unmark. And clear backoff for the operation.
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 35fbef6..8d2687b 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -231,6 +231,9 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
// The elapsed real time when the screen on was blocked.
private long mScreenOnBlockStartRealTime;
+ // True if we told the window manager policy that the screen was off.
+ private boolean mReportedScreenOffToPolicy;
+
// Remembers whether certain kinds of brightness adjustments
// were recently applied so that we can decide how to transition.
private boolean mAppliedAutoBrightness;
@@ -764,24 +767,30 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
} catch (RemoteException ex) {
// same process
}
+ }
- // Tell the window manager what's happening.
- // Temporarily block turning the screen on until the window manager is ready
- // by leaving a black surface covering the screen. This surface is essentially
- // the final state of the color fade animation.
- boolean isOn = (state != Display.STATE_OFF);
- if (wasOn && !isOn) {
+ // Tell the window manager policy when the screen is turned off or on unless it's due
+ // to the proximity sensor. We temporarily block turning the screen on until the
+ // window manager is ready by leaving a black surface covering the screen.
+ // This surface is essentially the final state of the color fade animation and
+ // it is only removed once the window manager tells us that the activity has
+ // finished drawing underneath.
+ final boolean isOff = (state == Display.STATE_OFF);
+ if (isOff && !mReportedScreenOffToPolicy && !mScreenOffBecauseOfProximity) {
+ mReportedScreenOffToPolicy = true;
+ unblockScreenOn();
+ mWindowManagerPolicy.screenTurnedOff();
+ } else if (!isOff && mReportedScreenOffToPolicy) {
+ mReportedScreenOffToPolicy = false;
+ if (mPowerState.getColorFadeLevel() == 0.0f) {
+ blockScreenOn();
+ } else {
unblockScreenOn();
- mWindowManagerPolicy.screenTurnedOff();
- } else if (!wasOn && isOn) {
- if (mPowerState.getColorFadeLevel() == 0.0f) {
- blockScreenOn();
- } else {
- unblockScreenOn();
- }
- mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
}
+ mWindowManagerPolicy.screenTurningOn(mPendingScreenOnUnblocker);
}
+
+ // Return true if the screen isn't blocked.
return mPendingScreenOnUnblocker == null;
}
@@ -1086,6 +1095,7 @@ final class DisplayPowerController implements AutomaticBrightnessController.Call
pw.println(" mAppliedLowPower=" + mAppliedLowPower);
pw.println(" mPendingScreenOnUnblocker=" + mPendingScreenOnUnblocker);
pw.println(" mPendingScreenOff=" + mPendingScreenOff);
+ pw.println(" mReportedScreenOffToPolicy=" + mReportedScreenOffToPolicy);
pw.println(" mScreenBrightnessRampAnimator.isAnimating()=" +
mScreenBrightnessRampAnimator.isAnimating());
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index 98fb11b..02d4f40 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -17,12 +17,7 @@
package com.android.server.job.controllers;
import android.app.usage.UsageStatsManagerInternal;
-import android.content.BroadcastReceiver;
import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.BatteryManager;
-import android.os.BatteryManagerInternal;
import android.util.Slog;
import com.android.server.LocalServices;
@@ -38,8 +33,7 @@ import java.util.ArrayList;
* for a certain amount of time (maybe hours or days) are considered idle. When the app comes
* out of idle state, it will be allowed to run scheduled jobs.
*/
-public class AppIdleController extends StateController
- implements UsageStatsManagerInternal.AppIdleStateChangeListener {
+public class AppIdleController extends StateController {
private static final String LOG_TAG = "AppIdleController";
private static final boolean DEBUG = false;
@@ -49,14 +43,7 @@ public class AppIdleController extends StateController
private static volatile AppIdleController sController;
final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
private final UsageStatsManagerInternal mUsageStatsInternal;
- private final BatteryManager mBatteryManager;
- private boolean mPluggedIn;
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override public void onReceive(Context context, Intent intent) {
- onPluggedIn(mBatteryManager.isCharging());
- }
- };
+ boolean mAppIdleParoleOn;
public static AppIdleController get(JobSchedulerService service) {
synchronized (sCreationLock) {
@@ -70,17 +57,8 @@ public class AppIdleController extends StateController
private AppIdleController(StateChangedListener stateChangedListener, Context context) {
super(stateChangedListener, context);
mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
- mBatteryManager = context.getSystemService(BatteryManager.class);
- mPluggedIn = mBatteryManager.isCharging();
- mUsageStatsInternal.addAppIdleStateChangeListener(this);
- registerReceivers();
- }
-
- private void registerReceivers() {
- // Monitor battery charging state
- IntentFilter filter = new IntentFilter(BatteryManager.ACTION_CHARGING);
- filter.addAction(BatteryManager.ACTION_DISCHARGING);
- mContext.registerReceiver(mReceiver, filter);
+ mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
+ mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
}
@Override
@@ -88,7 +66,7 @@ public class AppIdleController extends StateController
synchronized (mTrackedTasks) {
mTrackedTasks.add(jobStatus);
String packageName = jobStatus.job.getService().getPackageName();
- final boolean appIdle = !mPluggedIn && mUsageStatsInternal.isAppIdle(packageName,
+ final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
jobStatus.getUserId());
if (DEBUG) {
Slog.d(LOG_TAG, "Start tracking, setting idle state of "
@@ -108,7 +86,7 @@ public class AppIdleController extends StateController
@Override
public void dumpControllerState(PrintWriter pw) {
pw.println("AppIdle");
- pw.println("Plugged In: " + mPluggedIn);
+ pw.println("Parole On: " + mAppIdleParoleOn);
synchronized (mTrackedTasks) {
for (JobStatus task : mTrackedTasks) {
pw.print(task.job.getService().getPackageName());
@@ -119,48 +97,20 @@ public class AppIdleController extends StateController
}
}
- @Override
- public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
- boolean changed = false;
- synchronized (mTrackedTasks) {
- // If currently plugged in, we don't care about app idle state
- if (mPluggedIn) {
- return;
- }
- for (JobStatus task : mTrackedTasks) {
- if (task.job.getService().getPackageName().equals(packageName)
- && task.getUserId() == userId) {
- if (task.appNotIdleConstraintSatisfied.get() != !idle) {
- if (DEBUG) {
- Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
- + packageName + " to " + idle);
- }
- task.appNotIdleConstraintSatisfied.set(!idle);
- changed = true;
- }
- }
- }
- }
- if (changed) {
- mStateChangedListener.onControllerStateChanged();
- }
- }
-
- void onPluggedIn(boolean pluggedIn) {
+ void setAppIdleParoleOn(boolean isAppIdleParoleOn) {
// Flag if any app's idle state has changed
boolean changed = false;
synchronized (mTrackedTasks) {
- if (mPluggedIn == pluggedIn) {
+ if (mAppIdleParoleOn == isAppIdleParoleOn) {
return;
}
- mPluggedIn = pluggedIn;
+ mAppIdleParoleOn = isAppIdleParoleOn;
for (JobStatus task : mTrackedTasks) {
String packageName = task.job.getService().getPackageName();
- final boolean appIdle = !mPluggedIn && mUsageStatsInternal.isAppIdle(packageName,
+ final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
task.getUserId());
if (DEBUG) {
- Slog.d(LOG_TAG, "Plugged in " + pluggedIn + ", setting idle state of "
- + packageName + " to " + appIdle);
+ Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
}
if (task.appNotIdleConstraintSatisfied.get() == appIdle) {
task.appNotIdleConstraintSatisfied.set(!appIdle);
@@ -172,4 +122,41 @@ public class AppIdleController extends StateController
mStateChangedListener.onControllerStateChanged();
}
}
+
+ private class AppIdleStateChangeListener
+ extends UsageStatsManagerInternal.AppIdleStateChangeListener {
+ @Override
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+ boolean changed = false;
+ synchronized (mTrackedTasks) {
+ if (mAppIdleParoleOn) {
+ return;
+ }
+ for (JobStatus task : mTrackedTasks) {
+ if (task.job.getService().getPackageName().equals(packageName)
+ && task.getUserId() == userId) {
+ if (task.appNotIdleConstraintSatisfied.get() != !idle) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
+ + packageName + " to " + idle);
+ }
+ task.appNotIdleConstraintSatisfied.set(!idle);
+ changed = true;
+ }
+ }
+ }
+ }
+ if (changed) {
+ mStateChangedListener.onControllerStateChanged();
+ }
+ }
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
+ if (DEBUG) {
+ Slog.d(LOG_TAG, "Parole on: " + isParoleOn);
+ }
+ setAppIdleParoleOn(isParoleOn);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index b0550d6..847bcb5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -86,7 +86,6 @@ import android.app.IUidObserver;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.usage.UsageStatsManagerInternal;
-import android.app.usage.UsageStatsManagerInternal.AppIdleStateChangeListener;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -154,7 +153,6 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
-import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.google.android.collect.Lists;
@@ -182,8 +180,7 @@ import java.util.List;
* and delivers to listeners, such as {@link ConnectivityManager}, for
* enforcement.
*/
-public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
- implements AppIdleStateChangeListener {
+public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
private static final String TAG = "NetworkPolicy";
private static final boolean LOGD = false;
private static final boolean LOGV = false;
@@ -279,6 +276,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
final SparseIntArray mUidPolicy = new SparseIntArray();
/** Currently derived rules for each UID. */
final SparseIntArray mUidRules = new SparseIntArray();
+ /** Set of states for the child firewall chains. True if the chain is active. */
final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
/**
@@ -508,7 +506,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
WifiManager.NETWORK_STATE_CHANGED_ACTION);
mContext.registerReceiver(mWifiStateReceiver, wifiStateFilter, null, mHandler);
- mUsageStats.addAppIdleStateChangeListener(this);
+ mUsageStats.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
}
@@ -2043,7 +2041,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
}
setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
}
- enableFirewallChain(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
+ enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
+ }
+
+ void updateRulesForAppIdleParoleLocked() {
+ boolean enableChain = !mUsageStats.isAppIdleParoleOn();
+ enableFirewallChainLocked(FIREWALL_CHAIN_STANDBY, enableChain);
}
/**
@@ -2187,9 +2190,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
final boolean firewallReject = (uidRules & RULE_REJECT_ALL) != 0;
if (oldFirewallReject != firewallReject) {
setUidFirewallRule(FIREWALL_CHAIN_STANDBY, uid, firewallReject);
- if (mDeviceIdleMode && !firewallReject) {
- // if we are in device idle mode, and we decide to allow this uid. we need to punch
- // a hole in the device idle chain.
+ if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE) && !firewallReject) {
+ // if the dozable chain is on, and we decide to allow this uid. we need to punch
+ // a hole in the dozable chain.
setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, false);
}
}
@@ -2207,15 +2210,25 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
}
}
- @Override
- public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
- try {
- int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+ private class AppIdleStateChangeListener
+ extends UsageStatsManagerInternal.AppIdleStateChangeListener {
+
+ @Override
+ public void onAppIdleStateChanged(String packageName, int userId, boolean idle) {
+ try {
+ int uid = mContext.getPackageManager().getPackageUid(packageName, userId);
+ synchronized (mRulesLock) {
+ updateRulesForUidLocked(uid);
+ }
+ } catch (NameNotFoundException nnfe) {
+ }
+ }
+
+ @Override
+ public void onParoleStateChanged(boolean isParoleOn) {
synchronized (mRulesLock) {
- updateRulesForUidLocked(uid);
+ updateRulesForAppIdleParoleLocked();
}
- } catch (NameNotFoundException nnfe) {
- return;
}
}
@@ -2381,12 +2394,13 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub
/**
* Add or remove a uid to the firewall blacklist for all network ifaces.
*/
- private void enableFirewallChain(int chain, boolean enable) {
+ private void enableFirewallChainLocked(int chain, boolean enable) {
if (mFirewallChainStates.indexOfKey(chain) >= 0 &&
mFirewallChainStates.get(chain) == enable) {
// All is the same, nothing to do.
return;
}
+ mFirewallChainStates.put(chain, enable);
try {
mNetworkManager.setFirewallChainEnabled(chain, enable);
} catch (IllegalStateException e) {
diff --git a/services/core/java/com/android/server/notification/NotificationDelegate.java b/services/core/java/com/android/server/notification/NotificationDelegate.java
index fdb443e..87b4f8c 100644
--- a/services/core/java/com/android/server/notification/NotificationDelegate.java
+++ b/services/core/java/com/android/server/notification/NotificationDelegate.java
@@ -16,6 +16,8 @@
package com.android.server.notification;
+import com.android.internal.statusbar.NotificationVisibility;
+
public interface NotificationDelegate {
void onSetDisabled(int status);
void onClearAll(int callingUid, int callingPid, int userId);
@@ -30,6 +32,7 @@ public interface NotificationDelegate {
void onPanelHidden();
void clearEffects();
void onNotificationVisibilityChanged(
- String[] newlyVisibleKeys, String[] noLongerVisibleKeys);
+ NotificationVisibility[] newlyVisibleKeys,
+ NotificationVisibility[] noLongerVisibleKeys);
void onNotificationExpansionChanged(String key, boolean userAction, boolean expanded);
}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0dcad82..4524ff8 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -97,6 +97,7 @@ import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import com.android.internal.R;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.util.FastXmlSerializer;
import com.android.server.EventLogTags;
import com.android.server.LocalServices;
@@ -622,22 +623,24 @@ public class NotificationManagerService extends SystemService {
}
@Override
- public void onNotificationVisibilityChanged(
- String[] newlyVisibleKeys, String[] noLongerVisibleKeys) {
+ public void onNotificationVisibilityChanged(NotificationVisibility[] newlyVisibleKeys,
+ NotificationVisibility[] noLongerVisibleKeys) {
synchronized (mNotificationList) {
- for (String key : newlyVisibleKeys) {
- NotificationRecord r = mNotificationsByKey.get(key);
+ for (NotificationVisibility nv : newlyVisibleKeys) {
+ NotificationRecord r = mNotificationsByKey.get(nv.key);
if (r == null) continue;
- r.setVisibility(true);
+ r.setVisibility(true, nv.rank);
+ nv.recycle();
}
// Note that we might receive this event after notifications
// have already left the system, e.g. after dismissing from the
// shade. Hence not finding notifications in
// mNotificationsByKey is not an exceptional condition.
- for (String key : noLongerVisibleKeys) {
- NotificationRecord r = mNotificationsByKey.get(key);
+ for (NotificationVisibility nv : noLongerVisibleKeys) {
+ NotificationRecord r = mNotificationsByKey.get(nv.key);
if (r == null) continue;
- r.setVisibility(false);
+ r.setVisibility(false, nv.rank);
+ nv.recycle();
}
}
}
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index c4773ca..b7aea9d 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -314,13 +314,15 @@ public final class NotificationRecord {
/**
* Set the visibility of the notification.
*/
- public void setVisibility(boolean visible) {
+ public void setVisibility(boolean visible, int rank) {
final long now = System.currentTimeMillis();
mVisibleSinceMs = visible ? now : mVisibleSinceMs;
stats.onVisibilityChanged(visible);
EventLogTags.writeNotificationVisibility(getKey(), visible ? 1 : 0,
(int) (now - mCreationTimeMs),
- (int) (now - mUpdateTimeMs));
+ (int) (now - mUpdateTimeMs),
+ 0, // exposure time
+ rank);
}
/**
diff --git a/services/core/java/com/android/server/notification/NotificationUsageStats.java b/services/core/java/com/android/server/notification/NotificationUsageStats.java
index 2d5c199..2f0cc0f 100644
--- a/services/core/java/com/android/server/notification/NotificationUsageStats.java
+++ b/services/core/java/com/android/server/notification/NotificationUsageStats.java
@@ -16,11 +16,13 @@
package com.android.server.notification;
+import android.app.Notification;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
+import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
@@ -57,8 +59,8 @@ public class NotificationUsageStats {
private static final boolean DEBUG = false;
public static final int TEN_SECONDS = 1000 * 10;
- public static final int ONE_HOUR = 1000 * 60 * 60;
- private static final long EMIT_PERIOD = DEBUG ? TEN_SECONDS : ONE_HOUR;
+ public static final int FOUR_HOURS = 1000 * 60 * 60 * 4;
+ private static final long EMIT_PERIOD = DEBUG ? TEN_SECONDS : FOUR_HOURS;
// Guarded by synchronized(this).
private final Map<String, AggregatedStats> mStats = new HashMap<>();
@@ -98,6 +100,7 @@ public class NotificationUsageStats {
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
for (AggregatedStats stats : aggregatedStatsArray) {
stats.numPostedByApp++;
+ stats.countApiUse(notification);
}
releaseAggregatedStatsLocked(aggregatedStatsArray);
if (ENABLE_SQLITE_LOG) {
@@ -113,6 +116,7 @@ public class NotificationUsageStats {
AggregatedStats[] aggregatedStatsArray = getAggregatedStatsLocked(notification);
for (AggregatedStats stats : aggregatedStatsArray) {
stats.numUpdatedByApp++;
+ stats.countApiUse(notification);
}
releaseAggregatedStatsLocked(aggregatedStatsArray);
}
@@ -246,6 +250,7 @@ public class NotificationUsageStats {
private final Context mContext;
public final String key;
+ private AggregatedStats mPrevious;
// ---- Updated as the respective events occur.
public int numPostedByApp;
@@ -256,14 +261,103 @@ public class NotificationUsageStats {
public int numWithStaredPeople;
public int numWithValidPeople;
public int numBlocked;
-
- private AggregatedStats mPrevious;
+ public int numWithActions;
+ public int numPrivate;
+ public int numSecret;
+ public int numPriorityMax;
+ public int numPriorityHigh;
+ public int numPriorityLow;
+ public int numPriorityMin;
+ public int numWithBigText;
+ public int numWithBigPicture;
+ public int numForegroundService;
+ public int numOngoing;
+ public int numAutoCancel;
+ public int numWithLargeIcon;
+ public int numWithInbox;
+ public int numWithMediaSession;
+ public int numWithTitle;
+ public int numWithText;
+ public int numWithSubText;
+ public int numWithInfoText;
+ public int numInterrupt;
public AggregatedStats(Context context, String key) {
this.key = key;
mContext = context;
}
+ public void countApiUse(NotificationRecord record) {
+ final Notification n = record.getNotification();
+ if (n.actions != null) {
+ numWithActions++;
+ }
+
+ if ((n.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+ numForegroundService++;
+ }
+
+ if ((n.flags & Notification.FLAG_ONGOING_EVENT) != 0) {
+ numOngoing++;
+ }
+
+ if ((n.flags & Notification.FLAG_AUTO_CANCEL) != 0) {
+ numAutoCancel++;
+ }
+
+ if ((n.defaults & Notification.DEFAULT_SOUND) != 0 ||
+ (n.defaults & Notification.DEFAULT_VIBRATE) != 0 ||
+ n.sound != null || n.vibrate != null) {
+ numInterrupt++;
+ }
+
+ switch (n.visibility) {
+ case Notification.VISIBILITY_PRIVATE:
+ numPrivate++;
+ break;
+ case Notification.VISIBILITY_SECRET:
+ numSecret++;
+ break;
+ }
+
+ switch (n.priority) {
+ case Notification.PRIORITY_MAX:
+ numPriorityMax++;
+ break;
+ case Notification.PRIORITY_HIGH:
+ numPriorityHigh++;
+ break;
+ case Notification.PRIORITY_LOW:
+ numPriorityLow++;
+ break;
+ case Notification.PRIORITY_MIN:
+ numPriorityMin++;
+ break;
+ }
+
+ for (String Key : n.extras.keySet()) {
+ if (Notification.EXTRA_BIG_TEXT.equals(key)) {
+ numWithBigText++;
+ } else if (Notification.EXTRA_PICTURE.equals(key)) {
+ numWithBigPicture++;
+ } else if (Notification.EXTRA_LARGE_ICON.equals(key)) {
+ numWithLargeIcon++;
+ } else if (Notification.EXTRA_TEXT_LINES.equals(key)) {
+ numWithInbox++;
+ } else if (Notification.EXTRA_MEDIA_SESSION.equals(key)) {
+ numWithMediaSession++;
+ } else if (Notification.EXTRA_TITLE.equals(key)) {
+ numWithTitle++;
+ } else if (Notification.EXTRA_TEXT.equals(key)) {
+ numWithText++;
+ } else if (Notification.EXTRA_SUB_TEXT.equals(key)) {
+ numWithSubText++;
+ } else if (Notification.EXTRA_INFO_TEXT.equals(key)) {
+ numWithInfoText++;
+ }
+ }
+ }
+
public void emit() {
if (mPrevious == null) {
mPrevious = new AggregatedStats(null, key);
@@ -277,6 +371,26 @@ public class NotificationUsageStats {
maybeCount("people_cache_hit", (numPeopleCacheHit - mPrevious.numPeopleCacheHit));
maybeCount("people_cache_miss", (numPeopleCacheMiss - mPrevious.numPeopleCacheMiss));
maybeCount("note_blocked", (numBlocked - mPrevious.numBlocked));
+ maybeCount("note_with_actions", (numWithActions - mPrevious.numWithActions));
+ maybeCount("note_private", (numPrivate - mPrevious.numPrivate));
+ maybeCount("note_secret", (numSecret - mPrevious.numSecret));
+ maybeCount("note_prio_max", (numPriorityMax - mPrevious.numPriorityMax));
+ maybeCount("note_prio_high", (numPriorityHigh - mPrevious.numPriorityHigh));
+ maybeCount("note_prio_low", (numPriorityLow - mPrevious.numPriorityLow));
+ maybeCount("note_prio_min", (numPriorityMin - mPrevious.numPriorityMin));
+ maybeCount("note_interupt", (numInterrupt - mPrevious.numInterrupt));
+ maybeCount("note_big_text", (numWithBigText - mPrevious.numWithBigText));
+ maybeCount("note_big_pic", (numWithBigPicture - mPrevious.numWithBigPicture));
+ maybeCount("note_fg", (numForegroundService - mPrevious.numForegroundService));
+ maybeCount("note_ongoing", (numOngoing - mPrevious.numOngoing));
+ maybeCount("note_auto", (numAutoCancel - mPrevious.numAutoCancel));
+ maybeCount("note_large_icon", (numWithLargeIcon - mPrevious.numWithLargeIcon));
+ maybeCount("note_inbox", (numWithInbox - mPrevious.numWithInbox));
+ maybeCount("note_media", (numWithMediaSession - mPrevious.numWithMediaSession));
+ maybeCount("note_title", (numWithTitle - mPrevious.numWithTitle));
+ maybeCount("note_text", (numWithText - mPrevious.numWithText));
+ maybeCount("note_sub_text", (numWithSubText - mPrevious.numWithSubText));
+ maybeCount("note_info_text", (numWithInfoText - mPrevious.numWithInfoText));
mPrevious.numPostedByApp = numPostedByApp;
mPrevious.numUpdatedByApp = numUpdatedByApp;
@@ -286,6 +400,26 @@ public class NotificationUsageStats {
mPrevious.numWithStaredPeople = numWithStaredPeople;
mPrevious.numWithValidPeople = numWithValidPeople;
mPrevious.numBlocked = numBlocked;
+ mPrevious.numWithActions = numWithActions;
+ mPrevious.numPrivate = numPrivate;
+ mPrevious.numSecret = numSecret;
+ mPrevious.numPriorityMax = numPriorityMax;
+ mPrevious.numPriorityHigh = numPriorityHigh;
+ mPrevious.numPriorityLow = numPriorityLow;
+ mPrevious.numPriorityMin = numPriorityMin;
+ mPrevious.numInterrupt = numInterrupt;
+ mPrevious.numWithBigText = numWithBigText;
+ mPrevious.numWithBigPicture = numWithBigPicture;
+ mPrevious.numForegroundService = numForegroundService;
+ mPrevious.numOngoing = numOngoing;
+ mPrevious.numAutoCancel = numAutoCancel;
+ mPrevious.numWithLargeIcon = numWithLargeIcon;
+ mPrevious.numWithInbox = numWithInbox;
+ mPrevious.numWithMediaSession = numWithMediaSession;
+ mPrevious.numWithTitle = numWithTitle;
+ mPrevious.numWithText = numWithText;
+ mPrevious.numWithSubText = numWithSubText;
+ mPrevious.numWithInfoText = numWithInfoText;
}
void maybeCount(String name, int value) {
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index fe3103b..62c686c 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -106,7 +106,7 @@ final class DefaultPermissionGrantPolicy {
private static final Set<String> STORAGE_PERMISSIONS = new ArraySet<>();
static {
-// STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+ STORAGE_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
STORAGE_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 41d3ffd..7a39c2b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3354,11 +3354,8 @@ public class PackageManagerService extends IPackageManager.Stub {
enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
"updatePermissionFlags");
- // Only the system can change policy and system fixed flags.
+ // Only the system can change system fixed flags.
if (getCallingUid() != Process.SYSTEM_UID) {
- flagMask &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
- flagValues &= ~PackageManager.FLAG_PERMISSION_POLICY_FIXED;
-
flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
}
@@ -3387,18 +3384,63 @@ public class PackageManagerService extends IPackageManager.Stub {
return;
}
+ boolean hadState = permissionsState.getRuntimePermissionState(name, userId) != null;
+
if (permissionsState.updatePermissionFlags(bp, userId, flagMask, flagValues)) {
// Install and runtime permissions are stored in different places,
// so figure out what permission changed and persist the change.
if (permissionsState.getInstallPermissionState(name) != null) {
scheduleWriteSettingsLocked();
- } else if (permissionsState.getRuntimePermissionState(name, userId) != null) {
+ } else if (permissionsState.getRuntimePermissionState(name, userId) != null
+ || hadState) {
mSettings.writeRuntimePermissionsForUserLPr(userId, false);
}
}
}
}
+ /**
+ * Update the permission flags for all packages and runtime permissions of a user in order
+ * to allow device or profile owner to remove POLICY_FIXED.
+ */
+ @Override
+ public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) {
+ if (!sUserManager.exists(userId)) {
+ return;
+ }
+
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.GRANT_REVOKE_PERMISSIONS,
+ "updatePermissionFlagsForAllApps");
+
+ enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+ "updatePermissionFlagsForAllApps");
+
+ // Only the system can change system fixed flags.
+ if (getCallingUid() != Process.SYSTEM_UID) {
+ flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ flagValues &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
+ }
+
+ synchronized (mPackages) {
+ boolean changed = false;
+ final int packageCount = mPackages.size();
+ for (int pkgIndex = 0; pkgIndex < packageCount; pkgIndex++) {
+ final PackageParser.Package pkg = mPackages.valueAt(pkgIndex);
+ SettingBase sb = (SettingBase) pkg.mExtras;
+ if (sb == null) {
+ continue;
+ }
+ PermissionsState permissionsState = sb.getPermissionsState();
+ changed |= permissionsState.updatePermissionFlagsForAllPermissions(
+ userId, flagMask, flagValues);
+ }
+ if (changed) {
+ mSettings.writeRuntimePermissionsForUserLPr(userId, false);
+ }
+ }
+ }
+
@Override
public boolean shouldShowRequestPermissionRationale(String permissionName,
String packageName, int userId) {
diff --git a/services/core/java/com/android/server/pm/PermissionsState.java b/services/core/java/com/android/server/pm/PermissionsState.java
index ad662be..04beafd 100644
--- a/services/core/java/com/android/server/pm/PermissionsState.java
+++ b/services/core/java/com/android/server/pm/PermissionsState.java
@@ -344,6 +344,22 @@ public final class PermissionsState {
return permissionData.updateFlags(userId, flagMask, flagValues);
}
+ public boolean updatePermissionFlagsForAllPermissions(
+ int userId, int flagMask, int flagValues) {
+ enforceValidUserId(userId);
+
+ if (mPermissions == null) {
+ return false;
+ }
+ boolean changed = false;
+ final int permissionCount = mPermissions.size();
+ for (int i = 0; i < permissionCount; i++) {
+ PermissionData permissionData = mPermissions.valueAt(i);
+ changed |= permissionData.updateFlags(userId, flagMask, flagValues);
+ }
+ return changed;
+ }
+
/**
* Compute the Linux gids for a given device user from the permissions
* granted to this user. Note that these are computed to avoid additional
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index a754379..7640837 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -29,6 +29,7 @@ import android.util.Slog;
import com.android.internal.statusbar.IStatusBar;
import com.android.internal.statusbar.IStatusBarService;
+import com.android.internal.statusbar.NotificationVisibility;
import com.android.internal.statusbar.StatusBarIcon;
import com.android.internal.statusbar.StatusBarIconList;
import com.android.server.LocalServices;
@@ -660,7 +661,8 @@ public class StatusBarManagerService extends IStatusBarService.Stub {
@Override
public void onNotificationVisibilityChanged(
- String[] newlyVisibleKeys, String[] noLongerVisibleKeys) throws RemoteException {
+ NotificationVisibility[] newlyVisibleKeys, NotificationVisibility[] noLongerVisibleKeys)
+ throws RemoteException {
enforceStatusBarService();
long identity = Binder.clearCallingIdentity();
try {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ace5997..b285b66 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2671,6 +2671,16 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized(mWindowMap) {
mScreenCaptureDisabled.put(userId, disabled);
+ // Update secure surface for all windows belonging to this user.
+ for (int displayNdx = mDisplayContents.size() - 1; displayNdx >= 0; --displayNdx) {
+ WindowList windows = mDisplayContents.valueAt(displayNdx).getWindowList();
+ for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+ final WindowState win = windows.get(winNdx);
+ if (win.mHasSurface && userId == UserHandle.getUserId(win.mOwnerUid)) {
+ win.mWinAnimator.setSecureLocked(disabled);
+ }
+ }
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index f1331e9..d818519 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -658,6 +658,11 @@ class WindowStateAnimator {
}
@Override
+ public void setSecure(boolean isSecure) {
+ super.setSecure(isSecure);
+ }
+
+ @Override
public void setMatrix(float dsdx, float dtdx, float dsdy, float dtdy) {
if (dsdx != mDsdx || dtdx != mDtdx || dsdy != mDsdy || dtdy != mDtdy) {
if (logSurfaceTrace) Slog.v(SURFACE_TAG, "setMatrix(" + dsdx + "," + dtdx + ","
@@ -1663,6 +1668,22 @@ class WindowStateAnimator {
}
}
+ void setSecureLocked(boolean isSecure) {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setSecureLocked");
+ SurfaceControl.openTransaction();
+ try {
+ if (SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin, "isSecure=" + isSecure,
+ null);
+ mSurfaceControl.setSecure(isSecure);
+ } finally {
+ SurfaceControl.closeTransaction();
+ if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION setSecureLocked");
+ }
+ }
+
// This must be called while inside a transaction.
boolean performShowLocked() {
if (mWin.isHiddenFromUserLocked()) {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 416ea73..e44a7ab 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -246,6 +246,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_SLEEP_POLICY);
GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.STAY_ON_WHILE_PLUGGED_IN);
+ GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_DEVICE_OWNER_CONFIGS_LOCKDOWN);
}
// Keyguard features that when set of a profile will affect the profiles
@@ -4216,11 +4217,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
clearUserRestrictions(new UserHandle(UserHandle.USER_OWNER));
+ AppGlobals.getPackageManager().updatePermissionFlagsForAllApps(
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED,
+ 0, UserHandle.USER_OWNER);
if (mDeviceOwner != null) {
mDeviceOwner.clearDeviceOwner();
mDeviceOwner.writeOwnerFile();
updateDeviceOwnerLocked();
}
+ } catch (RemoteException re) {
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -4387,10 +4392,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long ident = Binder.clearCallingIdentity();
try {
clearUserRestrictions(callingUser);
+ AppGlobals.getPackageManager().updatePermissionFlagsForAllApps(
+ PackageManager.FLAG_PERMISSION_POLICY_FIXED,
+ 0, callingUser.getIdentifier());
if (mDeviceOwner != null) {
mDeviceOwner.removeProfileOwner(userId);
mDeviceOwner.writeOwnerFile();
}
+ } catch (RemoteException re) {
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -6389,21 +6398,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
long ident = Binder.clearCallingIdentity();
try {
- PackageManager packageManager = mContext.getPackageManager();
+ final ApplicationInfo ai = AppGlobals.getPackageManager()
+ .getApplicationInfo(packageName, 0, user.getIdentifier());
+ final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion;
+ if (targetSdkVersion < android.os.Build.VERSION_CODES.MNC) {
+ return false;
+ }
+ final PackageManager packageManager = mContext.getPackageManager();
switch (grantState) {
case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: {
+ packageManager.grantRuntimePermission(packageName, permission, user);
packageManager.updatePermissionFlags(permission, packageName,
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
- packageManager.grantRuntimePermission(packageName, permission, user);
} break;
case DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED: {
+ packageManager.revokeRuntimePermission(packageName,
+ permission, user);
packageManager.updatePermissionFlags(permission, packageName,
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
- packageManager.revokeRuntimePermission(packageName,
- permission, user);
} break;
case DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT: {
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 712db09..fb8a5bb 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -34,6 +34,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
+import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
@@ -792,6 +793,30 @@ public class ConnectivityServiceTest extends AndroidTestCase {
handlerThread.quit();
}
+ @LargeTest
+ public void testNoMutableNetworkRequests() throws Exception {
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, 0, new Intent("a"), 0);
+ NetworkRequest.Builder builder = new NetworkRequest.Builder();
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED);
+ try {
+ mCm.requestNetwork(builder.build(), new NetworkCallback());
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ mCm.requestNetwork(builder.build(), pendingIntent);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ builder = new NetworkRequest.Builder();
+ builder.addCapability(NetworkCapabilities.NET_CAPABILITY_CAPTIVE_PORTAL);
+ try {
+ mCm.requestNetwork(builder.build(), new NetworkCallback());
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ try {
+ mCm.requestNetwork(builder.build(), pendingIntent);
+ fail();
+ } catch (IllegalArgumentException expected) {}
+ }
// @Override
// public void tearDown() throws Exception {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 490236e..c49a5f9 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -119,6 +119,7 @@ public class UsageStatsService extends SystemService implements
static final int MSG_CHECK_PAROLE_TIMEOUT = 6;
static final int MSG_PAROLE_END_TIMEOUT = 7;
static final int MSG_REPORT_CONTENT_PROVIDER_USAGE = 8;
+ static final int MSG_PAROLE_STATE_CHANGED = 9;
private final Object mLock = new Object();
Handler mHandler;
@@ -313,7 +314,7 @@ public class UsageStatsService extends SystemService implements
mLastAppIdleParoledTime = checkAndGetTimeLocked();
postNextParoleTimeout();
}
- postCheckIdleStates(UserHandle.USER_ALL);
+ postParoleStateChanged();
}
}
}
@@ -338,6 +339,12 @@ public class UsageStatsService extends SystemService implements
mHandler.sendEmptyMessageDelayed(MSG_PAROLE_END_TIMEOUT, mAppIdleParoleDurationMillis);
}
+ private void postParoleStateChanged() {
+ if (DEBUG) Slog.d(TAG, "Posting MSG_PAROLE_STATE_CHANGED");
+ mHandler.removeMessages(MSG_PAROLE_STATE_CHANGED);
+ mHandler.sendEmptyMessage(MSG_PAROLE_STATE_CHANGED);
+ }
+
void postCheckIdleStates(int userId) {
mHandler.sendMessage(mHandler.obtainMessage(MSG_CHECK_IDLE_STATES, userId, 0));
}
@@ -756,6 +763,13 @@ public class UsageStatsService extends SystemService implements
}
}
+ boolean isAppIdleFilteredOrParoled(String packageName, int userId, long timeNow) {
+ if (mAppIdleParoled) {
+ return false;
+ }
+ return isAppIdleFiltered(packageName, userId, timeNow);
+ }
+
boolean isAppIdleFiltered(String packageName, int userId, long timeNow) {
final UserUsageStatsService userService;
final long screenOnTime;
@@ -782,13 +796,6 @@ public class UsageStatsService extends SystemService implements
if (!mAppIdleEnabled) {
return false;
}
- synchronized (mLock) {
- // Temporary exemption, probably due to device charging or occasional allowance to
- // be allowed to sync, etc.
- if (mAppIdleParoled) {
- return false;
- }
- }
if (packageName.equals("android")) return false;
try {
if (mDeviceIdleController.isPowerSaveWhitelistApp(packageName)) {
@@ -846,6 +853,12 @@ public class UsageStatsService extends SystemService implements
}
}
+ void informParoleStateChanged() {
+ for (AppIdleStateChangeListener listener : mPackageAccessListeners) {
+ listener.onParoleStateChanged(mAppIdleParoled);
+ }
+ }
+
private static boolean validRange(long currentTime, long beginTime, long endTime) {
return beginTime <= currentTime && beginTime < endTime;
}
@@ -975,6 +988,11 @@ public class UsageStatsService extends SystemService implements
args.recycle();
break;
+ case MSG_PAROLE_STATE_CHANGED:
+ if (DEBUG) Slog.d(TAG, "Parole state changed: " + mAppIdleParoled);
+ informParoleStateChanged();
+ break;
+
default:
super.handleMessage(msg);
break;
@@ -1126,7 +1144,7 @@ public class UsageStatsService extends SystemService implements
}
final long token = Binder.clearCallingIdentity();
try {
- return UsageStatsService.this.isAppIdleFiltered(packageName, userId, -1);
+ return UsageStatsService.this.isAppIdleFilteredOrParoled(packageName, userId, -1);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1251,6 +1269,11 @@ public class UsageStatsService extends SystemService implements
}
@Override
+ public boolean isAppIdleParoleOn() {
+ return mAppIdleParoled;
+ }
+
+ @Override
public void prepareShutdown() {
// This method *WILL* do IO work, but we must block until it is finished or else
// we might not shutdown cleanly. This is ok to do with the 'am' lock held, because
@@ -1261,6 +1284,7 @@ public class UsageStatsService extends SystemService implements
@Override
public void addAppIdleStateChangeListener(AppIdleStateChangeListener listener) {
UsageStatsService.this.addListener(listener);
+ listener.onParoleStateChanged(isAppIdleParoleOn());
}
@Override
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 8a72341..439ace8 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -17,7 +17,7 @@
package com.android.test.voiceinteraction;
import android.annotation.Nullable;
-import android.app.AssistStructure;
+import android.app.assist.AssistStructure;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 3090a11..90a781c 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -18,8 +18,8 @@ package com.android.test.voiceinteraction;
import android.app.ActivityManager;
import android.app.VoiceInteractor;
-import android.app.AssistContent;
-import android.app.AssistStructure;
+import android.app.assist.AssistContent;
+import android.app.assist.AssistStructure;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -123,34 +123,8 @@ public class MainInteractionSession extends VoiceInteractionSession
}
public void onHandleAssist(Bundle assistBundle) {
- boolean hasStructure = false;
- if (assistBundle != null) {
- Bundle assistContext = assistBundle.getBundle(Intent.EXTRA_ASSIST_CONTEXT);
- if (assistContext != null) {
- mAssistStructure = AssistStructure.getAssistStructure(assistContext);
- if (mAssistStructure != null) {
- if (mAssistVisualizer != null) {
- mAssistVisualizer.setAssistStructure(mAssistStructure);
- hasStructure = true;
- }
- }
- AssistContent content = AssistContent.getAssistContent(assistContext);
- if (content != null) {
- Log.i(TAG, "Assist intent: " + content.getIntent());
- Log.i(TAG, "Assist clipdata: " + content.getClipData());
- }
- }
- Uri referrer = assistBundle.getParcelable(Intent.EXTRA_REFERRER);
- if (referrer != null) {
- Log.i(TAG, "Referrer: " + referrer);
- }
- }
- if (!hasStructure && mAssistVisualizer != null) {
- mAssistVisualizer.clearAssistData();
- }
}
- /*
@Override
public void onHandleAssist(Bundle data, AssistStructure structure, AssistContent content) {
mAssistStructure = structure;
@@ -158,13 +132,22 @@ public class MainInteractionSession extends VoiceInteractionSession
if (mAssistVisualizer != null) {
mAssistVisualizer.setAssistStructure(mAssistStructure);
}
+ } else {
+ if (mAssistVisualizer != null) {
+ mAssistVisualizer.clearAssistData();
+ }
}
if (content != null) {
Log.i(TAG, "Assist intent: " + content.getIntent());
Log.i(TAG, "Assist clipdata: " + content.getClipData());
}
+ if (data != null) {
+ Uri referrer = data.getParcelable(Intent.EXTRA_REFERRER);
+ if (referrer != null) {
+ Log.i(TAG, "Referrer: " + referrer);
+ }
+ }
}
- */
@Override
public void onHandleScreenshot(Bitmap screenshot) {
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
index c038414..943c647 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/TestInteractionActivity.java
@@ -16,6 +16,7 @@
package com.android.test.voiceinteraction;
+import android.annotation.Nullable;
import android.app.Activity;
import android.app.VoiceInteractor;
import android.content.ComponentName;
@@ -111,38 +112,10 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
@Override
public void onClick(View v) {
if (v == mAbortButton) {
- VoiceInteractor.AbortVoiceRequest req = new VoiceInteractor.AbortVoiceRequest(
- new VoiceInteractor.Prompt("Dammit, we suck :("), null) {
- @Override
- public void onCancel() {
- Log.i(TAG, "Canceled!");
- mLog.append("Canceled abort\n");
- }
-
- @Override
- public void onAbortResult(Bundle result) {
- Log.i(TAG, "Abort result: result=" + result);
- mLog.append("Abort: result=" + result + "\n");
- getActivity().finish();
- }
- };
+ VoiceInteractor.AbortVoiceRequest req = new TestAbortVoice();
mInteractor.submitRequest(req, REQUEST_ABORT);
} else if (v == mCompleteButton) {
- VoiceInteractor.CompleteVoiceRequest req = new VoiceInteractor.CompleteVoiceRequest(
- new VoiceInteractor.Prompt("Woohoo, completed!"), null) {
- @Override
- public void onCancel() {
- Log.i(TAG, "Canceled!");
- mLog.append("Canceled complete\n");
- }
-
- @Override
- public void onCompleteResult(Bundle result) {
- Log.i(TAG, "Complete result: result=" + result);
- mLog.append("Complete: result=" + result + "\n");
- getActivity().finish();
- }
- };
+ VoiceInteractor.CompleteVoiceRequest req = new TestCompleteVoice();
mInteractor.submitRequest(req, REQUEST_COMPLETE);
} else if (v == mPickButton) {
VoiceInteractor.PickOptionRequest.Option[] options =
@@ -152,36 +125,7 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
options[2] = new VoiceInteractor.PickOptionRequest.Option("Three");
options[3] = new VoiceInteractor.PickOptionRequest.Option("Four");
options[4] = new VoiceInteractor.PickOptionRequest.Option("Five");
- VoiceInteractor.PickOptionRequest req = new VoiceInteractor.PickOptionRequest(
- new VoiceInteractor.Prompt("Need to pick something"), options, null) {
- @Override
- public void onCancel() {
- Log.i(TAG, "Canceled!");
- mLog.append("Canceled pick\n");
- }
-
- @Override
- public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
- Log.i(TAG, "Pick result: finished=" + finished + " selections=" + selections
- + " result=" + result);
- StringBuilder sb = new StringBuilder();
- if (finished) {
- sb.append("Pick final result: ");
- } else {
- sb.append("Pick intermediate result: ");
- }
- for (int i=0; i<selections.length; i++) {
- if (i >= 1) {
- sb.append(", ");
- }
- sb.append(selections[i].getLabel());
- }
- mLog.append(sb.toString());
- if (finished) {
- getActivity().finish();
- }
- }
- };
+ VoiceInteractor.PickOptionRequest req = new TestPickOption(options);
mInteractor.submitRequest(req, REQUEST_PICK);
} else if (v == mJumpOutButton) {
Log.i(TAG, "Jump out");
@@ -200,4 +144,66 @@ public class TestInteractionActivity extends Activity implements View.OnClickLis
public void onDestroy() {
super.onDestroy();
}
+
+ static class TestAbortVoice extends VoiceInteractor.AbortVoiceRequest {
+ public TestAbortVoice() {
+ super(new VoiceInteractor.Prompt("Dammit, we suck :("), null);
+ }
+ @Override public void onCancel() {
+ Log.i(TAG, "Canceled!");
+ ((TestInteractionActivity)getActivity()).mLog.append("Canceled abort\n");
+ }
+ @Override public void onAbortResult(Bundle result) {
+ Log.i(TAG, "Abort result: result=" + result);
+ ((TestInteractionActivity)getActivity()).mLog.append("Abort: result=" + result + "\n");
+ getActivity().finish();
+ }
+ }
+
+ static class TestCompleteVoice extends VoiceInteractor.CompleteVoiceRequest {
+ public TestCompleteVoice() {
+ super(new VoiceInteractor.Prompt("Woohoo, completed!"), null);
+ }
+ @Override public void onCancel() {
+ Log.i(TAG, "Canceled!");
+ ((TestInteractionActivity)getActivity()).mLog.append("Canceled complete\n");
+ }
+ @Override public void onCompleteResult(Bundle result) {
+ Log.i(TAG, "Complete result: result=" + result);
+ ((TestInteractionActivity)getActivity()).mLog.append("Complete: result="
+ + result + "\n");
+ getActivity().finish();
+ }
+ }
+
+ static class TestPickOption extends VoiceInteractor.PickOptionRequest {
+ public TestPickOption(Option[] options) {
+ super(new VoiceInteractor.Prompt("Need to pick something"), options, null);
+ }
+ @Override public void onCancel() {
+ Log.i(TAG, "Canceled!");
+ ((TestInteractionActivity)getActivity()).mLog.append("Canceled pick\n");
+ }
+ @Override
+ public void onPickOptionResult(boolean finished, Option[] selections, Bundle result) {
+ Log.i(TAG, "Pick result: finished=" + finished + " selections=" + selections
+ + " result=" + result);
+ StringBuilder sb = new StringBuilder();
+ if (finished) {
+ sb.append("Pick final result: ");
+ } else {
+ sb.append("Pick intermediate result: ");
+ }
+ for (int i=0; i<selections.length; i++) {
+ if (i >= 1) {
+ sb.append(", ");
+ }
+ sb.append(selections[i].getLabel());
+ }
+ ((TestInteractionActivity)getActivity()).mLog.append(sb.toString());
+ if (finished) {
+ getActivity().finish();
+ }
+ }
+ }
}
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 5dc70bd..fc6a3de 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -18,6 +18,7 @@ package android.net.wifi;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
/**
* Describes information about a detected access point. In addition
@@ -80,27 +81,30 @@ public class ScanResult implements Parcelable {
public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
/**
- * AP Channel bandwidth
+ * AP Channel bandwidth; one of {@link #CHANNEL_WIDTH_20MHZ}, {@link #CHANNEL_WIDTH_40MHZ},
+ * {@link #CHANNEL_WIDTH_80MHZ}, {@link #CHANNEL_WIDTH_160MHZ}
+ * or {@link #CHANNEL_WIDTH_80MHZ_PLUS_MHZ}.
*/
public int channelWidth;
/**
* Not used if the AP bandwidth is 20 MHz
- * If the AP use 40, 80 or 160 MHz, this is the center frequency
- * if the AP use 80 + 80 MHz, this is the center frequency of the first segment
+ * If the AP use 40, 80 or 160 MHz, this is the center frequency (in MHz)
+ * if the AP use 80 + 80 MHz, this is the center frequency of the first segment (in MHz)
*/
public int centerFreq0;
/**
* Only used if the AP bandwidth is 80 + 80 MHz
- * if the AP use 80 + 80 MHz, this is the center frequency of the second segment
+ * if the AP use 80 + 80 MHz, this is the center frequency of the second segment (in MHz)
*/
public int centerFreq1;
/**
- * Whether the AP support 802.11mc Responder
+ * @deprecated use is80211mcResponder() instead
+ * @hide
*/
- public boolean is80211McRTTResponder;
+ public boolean is80211McRTTResponder;
/**
* timestamp in microseconds (since boot) when
@@ -123,7 +127,7 @@ public class ScanResult implements Parcelable {
/**
* @hide
* Update RSSI of the scan result
- * @param previousRSSI
+ * @param previousRssi
* @param previousSeen
* @param maxAge
*/
@@ -206,26 +210,56 @@ public class ScanResult implements Parcelable {
public int distanceCm;
/**
- * The standard deviation of the distance to the AP, if available.
+ * The standard deviation of the distance to the access point, if available.
* Else {@link UNSPECIFIED}.
* {@hide}
*/
public int distanceSdCm;
+ public static final long FLAG_PASSPOINT_NETWORK = 0x0000000000000001;
+ public static final long FLAG_80211mc_RESPONDER = 0x0000000000000002;
+
/**
- * Indicates if the scan result represents a passpoint AP
+ * Defines flags; such as {@link #FLAG_PASSPOINT_NETWORK}.
*/
- public boolean passpointNetwork;
+ public long flags;
/**
- * Indicates if venue name
+ * sets a flag in {@link #flags} field
+ * @param flag flag to set
+ * @hide
*/
- public String venueName;
+ public void setFlag(long flag) {
+ flags |= flag;
+ }
/**
- * Indicates operator name
+ * clears a flag in {@link #flags} field
+ * @param flag flag to set
+ * @hide
*/
- public String operatorFriendlyName;
+ public void clearFlag(long flag) {
+ flags &= ~flag;
+ }
+
+ public boolean is80211mcResponder() {
+ return (flags & FLAG_80211mc_RESPONDER) != 0;
+ }
+
+ public boolean isPasspointNetwork() {
+ return (flags & FLAG_PASSPOINT_NETWORK) != 0;
+ }
+
+ /**
+ * Indicates venue name (such as 'San Francisco Airport') published by access point; only
+ * available on passpoint network and if published by access point.
+ */
+ public CharSequence venueName;
+
+ /**
+ * Indicates passpoint operator name published by access point.
+ */
+ public CharSequence operatorFriendlyName;
/**
* {@hide}
@@ -267,7 +301,7 @@ public class ScanResult implements Parcelable {
**/
public byte[] bytes;
- /** information element from beacon
+ /** information elements from beacon
* @hide
*/
public static class InformationElement {
@@ -303,8 +337,7 @@ public class ScanResult implements Parcelable {
this.channelWidth = UNSPECIFIED;
this.centerFreq0 = UNSPECIFIED;
this.centerFreq1 = UNSPECIFIED;
- this.is80211McRTTResponder = false;
- this.passpointNetwork = false;
+ this.flags = 0;
}
/** {@hide} */
@@ -322,8 +355,7 @@ public class ScanResult implements Parcelable {
this.channelWidth = UNSPECIFIED;
this.centerFreq0 = UNSPECIFIED;
this.centerFreq1 = UNSPECIFIED;
- this.is80211McRTTResponder = false;
- this.passpointNetwork = false;
+ this.flags = 0;
}
/** {@hide} */
@@ -342,8 +374,11 @@ public class ScanResult implements Parcelable {
this.channelWidth = channelWidth;
this.centerFreq0 = centerFreq0;
this.centerFreq1 = centerFreq1;
- this.is80211McRTTResponder = is80211McRTTResponder;
- this.passpointNetwork = false;
+ if (is80211McRTTResponder) {
+ this.flags = FLAG_80211mc_RESPONDER;
+ } else {
+ this.flags = 0;
+ }
}
/** copy constructor {@hide} */
@@ -358,7 +393,6 @@ public class ScanResult implements Parcelable {
channelWidth = source.channelWidth;
centerFreq0 = source.centerFreq0;
centerFreq1 = source.centerFreq1;
- is80211McRTTResponder = source.is80211McRTTResponder;
timestamp = source.timestamp;
distanceCm = source.distanceCm;
distanceSdCm = source.distanceSdCm;
@@ -369,9 +403,9 @@ public class ScanResult implements Parcelable {
numUsage = source.numUsage;
numIpConfigFailures = source.numIpConfigFailures;
isAutoJoinCandidate = source.isAutoJoinCandidate;
- passpointNetwork = source.passpointNetwork;
venueName = source.venueName;
operatorFriendlyName = source.operatorFriendlyName;
+ flags = source.flags;
}
}
@@ -405,15 +439,16 @@ public class ScanResult implements Parcelable {
sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
append("(cm)");
- sb.append(", passpoint: ").append(passpointNetwork ? "yes" : "no");
+ sb.append(", passpoint: ");
+ sb.append(((flags & FLAG_PASSPOINT_NETWORK) != 0) ? "yes" : "no");
if (autoJoinStatus != 0) {
sb.append(", status: ").append(autoJoinStatus);
}
sb.append(", ChannelBandwidth: ").append(channelWidth);
sb.append(", centerFreq0: ").append(centerFreq0);
sb.append(", centerFreq1: ").append(centerFreq1);
- sb.append(", 80211mcResponder: ").append(is80211McRTTResponder?
- "is supported":"is not supported");
+ sb.append(", 80211mcResponder: ");
+ sb.append(((flags & FLAG_80211mc_RESPONDER) != 0) ? "is supported" : "is not supported");
return sb.toString();
}
@@ -440,7 +475,6 @@ public class ScanResult implements Parcelable {
dest.writeInt(channelWidth);
dest.writeInt(centerFreq0);
dest.writeInt(centerFreq1);
- dest.writeInt(is80211McRTTResponder ? 1 : 0);
dest.writeLong(seen);
dest.writeInt(autoJoinStatus);
dest.writeInt(untrusted ? 1 : 0);
@@ -448,9 +482,9 @@ public class ScanResult implements Parcelable {
dest.writeInt(numUsage);
dest.writeInt(numIpConfigFailures);
dest.writeInt(isAutoJoinCandidate);
- dest.writeInt(passpointNetwork ? 1 : 0);
- dest.writeString(venueName);
- dest.writeString(operatorFriendlyName);
+ dest.writeString((venueName != null) ? venueName.toString() : "");
+ dest.writeString((operatorFriendlyName != null) ? operatorFriendlyName.toString() : "");
+ dest.writeLong(this.flags);
if (informationElements != null) {
dest.writeInt(informationElements.length);
@@ -474,18 +508,19 @@ public class ScanResult implements Parcelable {
}
ScanResult sr = new ScanResult(
wifiSsid,
- in.readString(),
- in.readString(),
- in.readInt(),
- in.readInt(),
- in.readLong(),
- in.readInt(),
- in.readInt(),
- in.readInt(),
- in.readInt(),
- in.readInt(),
- in.readInt() == 1
+ in.readString(), /* BSSID */
+ in.readString(), /* capabilities */
+ in.readInt(), /* level */
+ in.readInt(), /* frequency */
+ in.readLong(), /* timestamp */
+ in.readInt(), /* distanceCm */
+ in.readInt(), /* distanceSdCm */
+ in.readInt(), /* channelWidth */
+ in.readInt(), /* centerFreq0 */
+ in.readInt(), /* centerFreq1 */
+ false /* rtt responder, fixed with flags below */
);
+
sr.seen = in.readLong();
sr.autoJoinStatus = in.readInt();
sr.untrusted = in.readInt() != 0;
@@ -493,9 +528,9 @@ public class ScanResult implements Parcelable {
sr.numUsage = in.readInt();
sr.numIpConfigFailures = in.readInt();
sr.isAutoJoinCandidate = in.readInt();
- sr.passpointNetwork = in.readInt() == 1;
sr.venueName = in.readString();
sr.operatorFriendlyName = in.readString();
+ sr.flags = in.readLong();
int n = in.readInt();
if (n != 0) {
sr.informationElements = new InformationElement[n];
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 5d55ec6..5d834f6 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -344,14 +344,15 @@ public class WifiConfiguration implements Parcelable {
public String FQDN;
/**
- * Service provider name, for Passpoint credential.
+ * Name of passpoint credential provider
*/
public String providerFriendlyName;
/**
- * Roaming Consortium Id, for Passpoint credential.
+ * Roaming Consortium Id list for passpoint credential; identifies a set of networks where
+ * passpoint credential will be considered valid
*/
- public HashSet<Long> roamingConsortiumIds;
+ public Long[] roamingConsortiumIds;
/**
* @hide
@@ -906,7 +907,7 @@ public class WifiConfiguration implements Parcelable {
SSID = null;
BSSID = null;
FQDN = null;
- roamingConsortiumIds = new HashSet<Long>();
+ roamingConsortiumIds = new Long[0];
priority = 0;
hiddenSSID = false;
disableReason = DISABLED_UNKNOWN_REASON;
@@ -1437,11 +1438,7 @@ public class WifiConfiguration implements Parcelable {
SSID = source.SSID;
BSSID = source.BSSID;
FQDN = source.FQDN;
- roamingConsortiumIds = new HashSet<Long>();
- for (Long roamingConsortiumId : source.roamingConsortiumIds) {
- roamingConsortiumIds.add(roamingConsortiumId);
- }
-
+ roamingConsortiumIds = source.roamingConsortiumIds.clone();
providerFriendlyName = source.providerFriendlyName;
preSharedKey = source.preSharedKey;
@@ -1546,7 +1543,7 @@ public class WifiConfiguration implements Parcelable {
dest.writeString(autoJoinBSSID);
dest.writeString(FQDN);
dest.writeString(providerFriendlyName);
- dest.writeInt(roamingConsortiumIds.size());
+ dest.writeInt(roamingConsortiumIds.length);
for (Long roamingConsortiumId : roamingConsortiumIds) {
dest.writeLong(roamingConsortiumId);
}
@@ -1622,8 +1619,9 @@ public class WifiConfiguration implements Parcelable {
config.FQDN = in.readString();
config.providerFriendlyName = in.readString();
int numRoamingConsortiumIds = in.readInt();
+ config.roamingConsortiumIds = new Long[numRoamingConsortiumIds];
for (int i = 0; i < numRoamingConsortiumIds; i++) {
- config.roamingConsortiumIds.add(in.readLong());
+ config.roamingConsortiumIds[i] = in.readLong();
}
config.preSharedKey = in.readString();
for (int i = 0; i < config.wepKeys.length; i++) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 3525ec2..e611ea4 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -604,12 +604,13 @@ public class WifiEnterpriseConfig implements Parcelable {
* Get the domain_suffix_match value. See setDomSuffixMatch.
* @return The domain value.
*/
- public String getDomainSubjectMatch() {
+ public String getDomainSuffixMatch() {
return getFieldValue(DOM_SUFFIX_MATCH_KEY, "");
}
/**
- * Set realm for passpoint credential
+ * Set realm for passpoint credential; realm identifies a set of networks where your
+ * passpoint credential can be used
* @param realm the realm
*/
public void setRealm(String realm) {
@@ -617,7 +618,7 @@ public class WifiEnterpriseConfig implements Parcelable {
}
/**
- * Get realm for passpoint credential
+ * Get realm for passpoint credential; see {@link #setRealm(String)} for more information
* @return the realm
*/
public String getRealm() {
@@ -625,15 +626,16 @@ public class WifiEnterpriseConfig implements Parcelable {
}
/**
- * Set plmn for passpoint credential
- * @param plmn the plmn value derived from mcc & mnc
+ * Set plmn (Public Land Mobile Network) of the provider of passpoint credential
+ * @param plmn the plmn value derived from mcc (mobile country code) & mnc (mobile network code)
*/
public void setPlmn(String plmn) {
setFieldValue(PLMN_KEY, plmn, "");
}
/**
- * Get plmn for passpoint credential
+ * Get plmn (Public Land Mobile Network) for passpoint credential; see {@link #setPlmn
+ * (String)} for more information
* @return the plmn
*/
public String getPlmn() {
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 64fa0e5..d00c654 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -399,14 +399,16 @@ public class WifiManager {
public static final int CHANGE_REASON_CONFIG_CHANGE = 2;
/**
* An access point scan has completed, and results are available from the supplicant.
- * Call {@link #getScanResults()} to obtain the results.
+ * Call {@link #getScanResults()} to obtain the results. {@link #EXTRA_RESULTS_UPDATED}
+ * indicates if the scan was completed successfully.
*/
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String SCAN_RESULTS_AVAILABLE_ACTION = "android.net.wifi.SCAN_RESULTS";
/**
- * The result of previous scan, reported with {@link #SCAN_RESULTS_AVAILABLE_ACTION}.
- * @return true scan was successful, results updated
+ * Lookup key for a {@code boolean} representing the result of previous {@link #startScan}
+ * operation, reported with {@link #SCAN_RESULTS_AVAILABLE_ACTION}.
+ * @return true scan was successful, results are updated
* @return false scan was not successful, results haven't been updated since previous scan
*/
public static final String EXTRA_RESULTS_UPDATED = "resultsUpdated";