summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--apct-tests/perftests/core/jni/SystemPerfTest.cpp2
-rw-r--r--apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java (renamed from apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java)2
-rw-r--r--api/current.txt218
-rw-r--r--api/system-current.txt224
-rw-r--r--api/test-current.txt218
-rw-r--r--cmds/pm/src/com/android/commands/pm/Pm.java6
-rw-r--r--core/java/android/app/AppOpsManager.java16
-rw-r--r--core/java/android/app/NotificationManager.java13
-rw-r--r--core/java/android/content/Context.java13
-rw-r--r--core/java/android/content/pm/BaseParceledListSlice.java201
-rw-r--r--core/java/android/content/pm/InstantAppInfo.java2
-rw-r--r--core/java/android/content/pm/PackageInstaller.java32
-rw-r--r--core/java/android/content/pm/ParceledListSlice.java171
-rw-r--r--core/java/android/content/pm/ResolveInfo.java8
-rw-r--r--core/java/android/content/pm/StringParceledListSlice.aidl19
-rw-r--r--core/java/android/content/pm/StringParceledListSlice.java83
-rw-r--r--core/java/android/net/IpSecAlgorithm.java181
-rw-r--r--core/java/android/net/IpSecConfig.aidl20
-rw-r--r--core/java/android/net/IpSecConfig.java197
-rw-r--r--core/java/android/net/IpSecManager.java379
-rw-r--r--core/java/android/net/IpSecTransform.java471
-rw-r--r--core/java/android/net/NetworkPolicyManager.java17
-rw-r--r--core/java/android/net/NetworkScoreManager.java4
-rw-r--r--core/java/android/os/BatteryManager.java2
-rwxr-xr-xcore/java/android/provider/Settings.java2
-rw-r--r--core/java/android/service/notification/ConditionProviderService.java2
-rw-r--r--core/java/android/service/notification/NotificationListenerService.java4
-rw-r--r--core/java/android/service/notification/StatusBarNotification.java3
-rw-r--r--core/java/android/view/SurfaceControl.java17
-rw-r--r--core/java/android/view/SurfaceSession.java5
-rw-r--r--core/java/android/view/SurfaceView.java440
-rw-r--r--core/java/android/view/ViewRootImpl.java10
-rw-r--r--core/java/android/widget/TextView.java2
-rw-r--r--core/java/android/widget/TimePickerClockDelegate.java9
-rw-r--r--core/java/com/android/internal/notification/SystemNotificationChannels.java136
-rw-r--r--core/java/com/android/internal/util/ParcelableString.java52
-rw-r--r--core/java/com/android/internal/view/SurfaceCallbackHelper.java21
-rw-r--r--core/java/com/android/internal/view/menu/CascadingMenuPopup.java29
-rwxr-xr-xcore/jni/android/graphics/Bitmap.cpp6
-rw-r--r--core/jni/android_view_InputChannel.cpp9
-rw-r--r--core/jni/android_view_RenderNode.cpp4
-rw-r--r--core/jni/android_view_SurfaceControl.cpp28
-rw-r--r--core/jni/android_view_SurfaceSession.cpp11
-rw-r--r--core/res/AndroidManifest.xml13
-rw-r--r--core/res/res/values/attrs.xml8
-rw-r--r--core/res/res/values/strings.xml47
-rw-r--r--core/res/res/values/symbols.xml17
-rw-r--r--core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java22
-rw-r--r--graphics/tests/graphicstests/src/android/graphics/BitmapTest.java38
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl6
-rw-r--r--libs/hwui/SkiaCanvas.cpp23
-rw-r--r--media/java/android/media/MediaPlayer.java70
-rw-r--r--media/java/android/media/tv/TvContract.java1321
-rw-r--r--media/java/android/media/tv/TvInputManager.java34
-rw-r--r--media/java/android/media/tv/TvView.java4
-rw-r--r--native/android/libandroid.map.txt7
-rw-r--r--native/android/sensor.cpp109
-rw-r--r--packages/SettingsLib/res/layout/drawer_category.xml38
-rw-r--r--packages/SettingsLib/res/layout/drawer_item.xml44
-rw-r--r--packages/SettingsLib/res/layout/drawer_spacer.xml20
-rw-r--r--packages/SettingsLib/res/layout/settings_with_drawer.xml9
-rwxr-xr-xpackages/SettingsLib/res/values/config.xml3
-rw-r--r--packages/SettingsLib/res/values/dimens.xml6
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java268
-rw-r--r--packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java147
-rw-r--r--packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java10
-rw-r--r--services/core/java/com/android/server/BluetoothManagerService.java2
-rw-r--r--services/core/java/com/android/server/InputMethodManagerService.java16
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java30
-rw-r--r--services/core/java/com/android/server/NetworkScoreService.java18
-rw-r--r--services/core/java/com/android/server/UiModeManagerService.java4
-rw-r--r--services/core/java/com/android/server/accounts/AccountManagerService.java26
-rw-r--r--services/core/java/com/android/server/am/ActiveServices.java5
-rw-r--r--services/core/java/com/android/server/am/ActivityManagerService.java20
-rw-r--r--services/core/java/com/android/server/am/PreBootBroadcaster.java7
-rw-r--r--services/core/java/com/android/server/am/ServiceRecord.java20
-rw-r--r--services/core/java/com/android/server/audio/PlaybackActivityMonitor.java8
-rw-r--r--services/core/java/com/android/server/connectivity/NetworkNotificationManager.java9
-rw-r--r--services/core/java/com/android/server/connectivity/Tethering.java16
-rw-r--r--services/core/java/com/android/server/connectivity/Vpn.java22
-rw-r--r--services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java3
-rw-r--r--services/core/java/com/android/server/content/SyncManager.java6
-rw-r--r--services/core/java/com/android/server/fingerprint/ClientMonitor.java4
-rw-r--r--services/core/java/com/android/server/input/InputManagerService.java23
-rw-r--r--services/core/java/com/android/server/net/LockdownVpnTracker.java25
-rw-r--r--services/core/java/com/android/server/net/NetworkPolicyManagerService.java19
-rw-r--r--services/core/java/com/android/server/notification/NotificationManagerService.java5
-rw-r--r--services/core/java/com/android/server/pm/InstantAppRegistry.java1
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerService.java3
-rw-r--r--services/core/java/com/android/server/pm/PackageInstallerSession.java22
-rw-r--r--services/core/java/com/android/server/pm/PackageManagerService.java58
-rw-r--r--services/core/java/com/android/server/storage/DeviceStorageMonitorService.java49
-rw-r--r--services/core/java/com/android/server/wm/AppWindowToken.java10
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java9
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowSurfaceController.java14
-rw-r--r--services/core/jni/com_android_server_location_GnssLocationProvider.cpp20
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java52
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java29
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java17
-rw-r--r--services/java/com/android/server/SystemServer.java2
-rw-r--r--services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java3
-rw-r--r--services/tests/notification/AndroidManifest.xml1
-rw-r--r--services/tests/notification/src/com/android/server/notification/GroupHelperTest.java2
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java21
-rw-r--r--services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java6
-rw-r--r--services/tests/notification/src/com/android/server/notification/RankingHelperTest.java11
-rw-r--r--services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java16
-rw-r--r--services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java28
-rw-r--r--services/usb/java/com/android/server/usb/MtpNotificationManager.java14
-rw-r--r--services/usb/java/com/android/server/usb/UsbDeviceManager.java9
-rw-r--r--telecomm/java/android/telecom/Call.java1
-rw-r--r--telecomm/java/android/telecom/TelecomManager.java24
-rw-r--r--telecomm/java/com/android/internal/telecom/ITelecomService.aidl4
-rw-r--r--telephony/java/android/telephony/ims/ImsService.java25
-rw-r--r--telephony/java/android/telephony/ims/feature/ImsFeature.java63
-rw-r--r--tests/net/java/com/android/server/ConnectivityServiceTest.java285
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java2
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java2
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java11
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java48
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java9
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java339
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java80
-rw-r--r--wifi/java/android/net/wifi/aware/DiscoverySession.java109
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareManager.java114
-rw-r--r--wifi/java/android/net/wifi/aware/WifiAwareSession.java97
-rw-r--r--wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java54
129 files changed, 4856 insertions, 2673 deletions
diff --git a/apct-tests/perftests/core/jni/SystemPerfTest.cpp b/apct-tests/perftests/core/jni/SystemPerfTest.cpp
index eb5540844808..f102e3ec0a71 100644
--- a/apct-tests/perftests/core/jni/SystemPerfTest.cpp
+++ b/apct-tests/perftests/core/jni/SystemPerfTest.cpp
@@ -73,7 +73,7 @@ jint JNI_OnLoad(JavaVM* jvm, void*) {
return JNI_ERR;
}
- if (registerNativeMethods(env, "java/lang/perftests/SystemPerfTest",
+ if (registerNativeMethods(env, "android/perftests/SystemPerfTest",
sMethods, NELEM(sMethods)) == -1) {
return JNI_ERR;
}
diff --git a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
index afc9d0cf10e1..95a714486062 100644
--- a/apct-tests/perftests/core/src/java/lang/perftests/SystemPerfTest.java
+++ b/apct-tests/perftests/core/src/android/perftests/SystemPerfTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package java.lang.perftests;
+package android.perftests;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;
diff --git a/api/current.txt b/api/current.txt
index 445c576cf091..c7074cca6e0e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16,6 +16,7 @@ package android {
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -4143,6 +4144,7 @@ package android.app {
field public static final int MODE_ERRORED = 2; // 0x2
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -8674,6 +8676,7 @@ package android.content {
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -10166,9 +10169,11 @@ package android.content.pm {
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10211,6 +10216,7 @@ package android.content.pm {
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -10600,6 +10606,7 @@ package android.content.pm {
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -24132,17 +24139,79 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+ }
+
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
}
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -24175,6 +24244,7 @@ package android.media.tv {
field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
field public static final java.lang.String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
field public static final java.lang.String COLUMN_APP_LINK_TEXT = "app_link_text";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
@@ -24247,69 +24317,17 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -24345,6 +24363,7 @@ package android.media.tv {
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -24357,6 +24376,19 @@ package android.media.tv {
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public final class TvInputInfo implements android.os.Parcelable {
method public boolean canRecord();
method public android.content.Intent createSettingsIntent();
@@ -24406,15 +24438,10 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -24986,6 +25013,68 @@ package android.net {
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -30036,7 +30125,7 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -38155,9 +38244,6 @@ package android.telecom {
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -38698,6 +38784,8 @@ package android.telecom {
}
public class TelecomManager {
+ method public void acceptRingingCall();
+ method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
diff --git a/api/system-current.txt b/api/system-current.txt
index e00507ee884c..a46735122ef5 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -25,6 +25,7 @@ package android {
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final java.lang.String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BACKUP = "android.permission.BACKUP";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
@@ -4286,6 +4287,7 @@ package android.app {
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ACTIVATE_VPN = "android:activate_vpn";
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -9137,6 +9139,7 @@ package android.content {
field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -10703,9 +10706,11 @@ package android.content.pm {
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10748,6 +10753,7 @@ package android.content.pm {
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -11222,6 +11228,7 @@ package android.content.pm {
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -25962,23 +25969,86 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
field public static final java.lang.String EXTRA_COLUMN_NAME = "android.media.tv.extra.COLUMN_NAME";
field public static final java.lang.String EXTRA_DATA_TYPE = "android.media.tv.extra.DATA_TYPE";
field public static final java.lang.String EXTRA_DEFAULT_VALUE = "android.media.tv.extra.DEFAULT_VALUE";
field public static final java.lang.String EXTRA_EXISTING_COLUMN_NAMES = "android.media.tv.extra.EXISTING_COLUMN_NAMES";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
field public static final java.lang.String METHOD_ADD_COLUMN = "add_column";
field public static final java.lang.String METHOD_GET_COLUMNS = "get_columns";
}
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TRANSIENT = "transient";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+ }
+
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -26087,70 +26157,17 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TRANSIENT = "transient";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -26186,6 +26203,7 @@ package android.media.tv {
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -26198,6 +26216,19 @@ package android.media.tv {
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public static final class TvContract.WatchedPrograms implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
@@ -26327,15 +26358,10 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -27011,6 +27037,73 @@ package android.net {
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public void removeTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform buildTunnelModeTransform(java.net.InetAddress, java.net.InetAddress);
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setNattKeepalive(int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -32634,7 +32727,7 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -41206,9 +41299,6 @@ package android.telecom {
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -42514,7 +42604,9 @@ package android.telephony {
method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+ method public void sendMultipartTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
diff --git a/api/test-current.txt b/api/test-current.txt
index 500a0569bfd2..1a12b4c088eb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -16,6 +16,7 @@ package android {
field public static final java.lang.String ACCOUNT_MANAGER = "android.permission.ACCOUNT_MANAGER";
field public static final java.lang.String ADD_VOICEMAIL = "com.android.voicemail.permission.ADD_VOICEMAIL";
field public static final java.lang.String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
+ field public static final java.lang.String ANSWER_PHONE_CALLS = "android.permission.ANSWER_PHONE_CALLS";
field public static final java.lang.String BATTERY_STATS = "android.permission.BATTERY_STATS";
field public static final java.lang.String BIND_ACCESSIBILITY_SERVICE = "android.permission.BIND_ACCESSIBILITY_SERVICE";
field public static final java.lang.String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
@@ -4153,6 +4154,7 @@ package android.app {
field public static final int MODE_ERRORED = 2; // 0x2
field public static final int MODE_IGNORED = 1; // 0x1
field public static final java.lang.String OPSTR_ADD_VOICEMAIL = "android:add_voicemail";
+ field public static final java.lang.String OPSTR_ANSWER_PHONE_CALLS = "android:answer_phone_calls";
field public static final java.lang.String OPSTR_BODY_SENSORS = "android:body_sensors";
field public static final java.lang.String OPSTR_CALL_PHONE = "android:call_phone";
field public static final java.lang.String OPSTR_CAMERA = "android:camera";
@@ -8702,6 +8704,7 @@ package android.content {
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
+ field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -10198,9 +10201,11 @@ package android.content.pm {
method public void unregisterSessionCallback(android.content.pm.PackageInstaller.SessionCallback);
method public void updateSessionAppIcon(int, android.graphics.Bitmap);
method public void updateSessionAppLabel(int, java.lang.CharSequence);
+ field public static final java.lang.String ACTION_SESSION_COMMITTED = "android.content.pm.action.SESSION_COMMITTED";
field public static final java.lang.String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
field public static final java.lang.String EXTRA_OTHER_PACKAGE_NAME = "android.content.pm.extra.OTHER_PACKAGE_NAME";
field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.content.pm.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_SESSION = "android.content.pm.extra.SESSION";
field public static final java.lang.String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
field public static final java.lang.String EXTRA_STATUS = "android.content.pm.extra.STATUS";
field public static final java.lang.String EXTRA_STATUS_MESSAGE = "android.content.pm.extra.STATUS_MESSAGE";
@@ -10243,6 +10248,7 @@ package android.content.pm {
method public android.graphics.Bitmap getAppIcon();
method public java.lang.CharSequence getAppLabel();
method public java.lang.String getAppPackageName();
+ method public int getInstallReason();
method public java.lang.String getInstallerPackageName();
method public float getProgress();
method public int getSessionId();
@@ -10636,6 +10642,7 @@ package android.content.pm {
field public android.content.pm.ActivityInfo activityInfo;
field public android.content.IntentFilter filter;
field public int icon;
+ field public boolean instantAppAvailable;
field public boolean isDefault;
field public int labelRes;
field public int match;
@@ -24228,17 +24235,79 @@ package android.media.tv {
method public static final android.net.Uri buildProgramsUriForChannel(long, long, long);
method public static final android.net.Uri buildProgramsUriForChannel(android.net.Uri, long, long);
method public static final android.net.Uri buildRecordedProgramUri(long);
+ method public static final android.net.Uri buildWatchNextProgramUri(long);
method public static final boolean isChannelUri(android.net.Uri);
method public static final boolean isChannelUriForPassthroughInput(android.net.Uri);
method public static final boolean isChannelUriForTunerInput(android.net.Uri);
method public static final boolean isProgramUri(android.net.Uri);
+ field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT = "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+ field public static final java.lang.String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+ field public static final java.lang.String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String AUTHORITY = "android.media.tv";
+ field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+ field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+ field public static final java.lang.String EXTRA_PREVIEW_PROGRAM_ID = "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+ field public static final java.lang.String EXTRA_WATCH_NEXT_PROGRAM_ID = "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+ }
+
+ public static abstract interface TvContract.BasePreviewProgramColumns implements android.media.tv.TvContract.BaseProgramColumns {
+ field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+ field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+ field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+ field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+ field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+ field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+ field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+ field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
+ field public static final java.lang.String COLUMN_AUTHOR = "author";
+ field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
+ field public static final java.lang.String COLUMN_CONTENT_ID = "content_id";
+ field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
+ field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
+ field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
+ field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+ field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
+ field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
+ field public static final java.lang.String COLUMN_LIVE = "live";
+ field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
+ field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
+ field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+ field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+ field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
+ field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
+ field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+ field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
+ field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+ field public static final java.lang.String COLUMN_TYPE = "type";
+ field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+ field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+ field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+ field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+ field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+ field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
+ field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+ field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+ field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
+ field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
+ field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
+ field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
+ field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
+ field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
+ field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
+ field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
+ field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+ field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
}
public static abstract interface TvContract.BaseProgramColumns implements android.media.tv.TvContract.BaseTvColumns {
field public static final java.lang.String COLUMN_AUDIO_LANGUAGE = "audio_language";
field public static final java.lang.String COLUMN_CANONICAL_GENRE = "canonical_genre";
- field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_CONTENT_RATING = "content_rating";
field public static final java.lang.String COLUMN_EPISODE_DISPLAY_NUMBER = "episode_display_number";
field public static final java.lang.String COLUMN_EPISODE_TITLE = "episode_title";
@@ -24271,6 +24340,7 @@ package android.media.tv {
field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
field public static final java.lang.String COLUMN_APP_LINK_POSTER_ART_URI = "app_link_poster_art_uri";
field public static final java.lang.String COLUMN_APP_LINK_TEXT = "app_link_text";
+ field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
field public static final java.lang.String COLUMN_DESCRIPTION = "description";
field public static final java.lang.String COLUMN_DISPLAY_NAME = "display_name";
field public static final java.lang.String COLUMN_DISPLAY_NUMBER = "display_number";
@@ -24343,69 +24413,17 @@ package android.media.tv {
field public static final java.lang.String CONTENT_DIRECTORY = "logo";
}
- public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BaseProgramColumns {
- field public static final java.lang.String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
- field public static final java.lang.String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
- field public static final java.lang.String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
- field public static final java.lang.String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
- field public static final java.lang.String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
- field public static final java.lang.String AVAILABILITY_FREE_WITH_SUBSCRIPTION = "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
- field public static final java.lang.String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
- field public static final java.lang.String COLUMN_APP_LINK_INTENT_URI = "app_link_intent_uri";
- field public static final java.lang.String COLUMN_AUTHOR = "author";
- field public static final java.lang.String COLUMN_AVAILABILITY = "availability";
- field public static final java.lang.String COLUMN_BROWSABLE = "browsable";
- field public static final java.lang.String COLUMN_DURATION_MILLIS = "duration_millis";
- field public static final java.lang.String COLUMN_INTERACTION_COUNT = "interaction_count";
- field public static final java.lang.String COLUMN_INTERACTION_TYPE = "interaction_type";
- field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
- field public static final java.lang.String COLUMN_ITEM_COUNT = "item_count";
- field public static final java.lang.String COLUMN_LAST_PLAYBACK_POSITION_MILLIS = "last_playback_position_millis";
- field public static final java.lang.String COLUMN_LIVE = "live";
- field public static final java.lang.String COLUMN_LOGO_URI = "logo_uri";
- field public static final java.lang.String COLUMN_OFFER_PRICE = "offer_price";
- field public static final java.lang.String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
- field public static final java.lang.String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
- field public static final java.lang.String COLUMN_RELEASE_DATE = "release_date";
- field public static final java.lang.String COLUMN_REVIEW_RATING = "review_rating";
- field public static final java.lang.String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
- field public static final java.lang.String COLUMN_STARTING_PRICE = "starting_price";
- field public static final java.lang.String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
- field public static final java.lang.String COLUMN_TYPE = "type";
- field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ public static final class TvContract.PreviewPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_WEIGHT = "weight";
field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/preview_program";
field public static final android.net.Uri CONTENT_URI;
- field public static final java.lang.String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
- field public static final java.lang.String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
- field public static final java.lang.String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
- field public static final java.lang.String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
- field public static final java.lang.String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
- field public static final java.lang.String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
- field public static final java.lang.String REVIEW_RATING_STYLE_PERCENTAGE = "REVIEW_RATING_STYLE_PERCENTAGE";
- field public static final java.lang.String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
- field public static final java.lang.String REVIEW_RATING_STYLE_THUMBS_UP_DOWN = "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
- field public static final java.lang.String TYPE_ALBUM = "TYPE_ALBUM";
- field public static final java.lang.String TYPE_ARTIST = "TYPE_ARTIST";
- field public static final java.lang.String TYPE_CHANNEL = "TYPE_CHANNEL";
- field public static final java.lang.String TYPE_CLIP = "TYPE_CLIP";
- field public static final java.lang.String TYPE_EVENT = "TYPE_EVENT";
- field public static final java.lang.String TYPE_MOVIE = "TYPE_MOVIE";
- field public static final java.lang.String TYPE_PLAYLIST = "TYPE_PLAYLIST";
- field public static final java.lang.String TYPE_STATION = "TYPE_STATION";
- field public static final java.lang.String TYPE_TRACK = "TYPE_TRACK";
- field public static final java.lang.String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
- field public static final java.lang.String TYPE_TV_SEASON = "TYPE_TV_SEASON";
- field public static final java.lang.String TYPE_TV_SERIES = "TYPE_TV_SERIES";
- field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
}
public static final class TvContract.Programs implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final deprecated java.lang.String COLUMN_EPISODE_NUMBER = "episode_number";
field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
@@ -24441,6 +24459,7 @@ package android.media.tv {
public static final class TvContract.RecordedPrograms implements android.media.tv.TvContract.BaseProgramColumns {
field public static final java.lang.String COLUMN_BROADCAST_GENRE = "broadcast_genre";
+ field public static final java.lang.String COLUMN_CHANNEL_ID = "channel_id";
field public static final java.lang.String COLUMN_END_TIME_UTC_MILLIS = "end_time_utc_millis";
field public static final java.lang.String COLUMN_INPUT_ID = "input_id";
field public static final java.lang.String COLUMN_RECORDING_DATA_BYTES = "recording_data_bytes";
@@ -24453,6 +24472,19 @@ package android.media.tv {
field public static final android.net.Uri CONTENT_URI;
}
+ public static final class TvContract.WatchNextPrograms implements android.media.tv.TvContract.BasePreviewProgramColumns {
+ ctor public TvContract.WatchNextPrograms();
+ field public static final java.lang.String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS = "last_engagement_time_utc_millis";
+ field public static final java.lang.String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
+ field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
+ field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
+ field public static final android.net.Uri CONTENT_URI;
+ field public static final java.lang.String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
+ field public static final java.lang.String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
+ field public static final java.lang.String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
+ }
+
public final class TvInputInfo implements android.os.Parcelable {
method public boolean canRecord();
method public android.content.Intent createSettingsIntent();
@@ -24502,15 +24534,10 @@ package android.media.tv {
method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
method public void updateTvInputInfo(android.media.tv.TvInputInfo);
field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
- field public static final java.lang.String ACTION_MAKE_CHANNEL_BROWSABLE = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
- field public static final java.lang.String ACTION_PROGRAM_BROWSABLE_DISABLED = "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
field public static final java.lang.String ACTION_SETUP_INPUTS = "android.media.tv.action.SETUP_INPUTS";
field public static final java.lang.String ACTION_VIEW_RECORDING_SCHEDULES = "android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- field public static final java.lang.String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
- field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
- field public static final java.lang.String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
field public static final int INPUT_STATE_CONNECTED = 0; // 0x0
field public static final int INPUT_STATE_CONNECTED_STANDBY = 1; // 0x1
field public static final int INPUT_STATE_DISCONNECTED = 2; // 0x2
@@ -25082,6 +25109,68 @@ package android.net {
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
+ public final class IpSecAlgorithm implements android.os.Parcelable {
+ ctor public IpSecAlgorithm(java.lang.String, byte[]);
+ ctor public IpSecAlgorithm(java.lang.String, byte[], int);
+ method public int describeContents();
+ method public byte[] getKey();
+ method public java.lang.String getName();
+ method public int getTruncationLengthBits();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final java.lang.String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ public final class IpSecManager {
+ method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
+ method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
+ method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
+ method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
+ }
+
+ public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
+ }
+
+ public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
+ method public int getSpi();
+ }
+
+ public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
+ method public void close();
+ method public int getPort();
+ method public java.io.FileDescriptor getSocket();
+ }
+
+ public final class IpSecTransform implements java.lang.AutoCloseable {
+ method public void close();
+ field public static final int DIRECTION_IN = 0; // 0x0
+ field public static final int DIRECTION_OUT = 1; // 0x1
+ }
+
+ public static class IpSecTransform.Builder {
+ ctor public IpSecTransform.Builder(android.content.Context);
+ method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
+ method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
+ method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, int);
+ method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
+ }
+
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -30132,7 +30221,7 @@ package android.os {
field public static final int BATTERY_PLUGGED_AC = 1; // 0x1
field public static final int BATTERY_PLUGGED_USB = 2; // 0x2
field public static final int BATTERY_PLUGGED_WIRELESS = 4; // 0x4
- field public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6; // 0x6
+ field public static final int BATTERY_PROPERTY_STATUS = 6; // 0x6
field public static final int BATTERY_PROPERTY_CAPACITY = 4; // 0x4
field public static final int BATTERY_PROPERTY_CHARGE_COUNTER = 1; // 0x1
field public static final int BATTERY_PROPERTY_CURRENT_AVERAGE = 3; // 0x3
@@ -38339,9 +38428,6 @@ package android.telecom {
field public static final int RTT_MODE_VCO = 3; // 0x3
}
- public static abstract class Call.RttCall.RttAudioMode implements java.lang.annotation.Annotation {
- }
-
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -38882,6 +38968,8 @@ package android.telecom {
}
public class TelecomManager {
+ method public void acceptRingingCall();
+ method public void acceptRingingCall(int);
method public void addNewIncomingCall(android.telecom.PhoneAccountHandle, android.os.Bundle);
method public void cancelMissedCallsNotification();
method public android.content.Intent createManageBlockedNumbersIntent();
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 1aef3639e449..91520f1a7d8e 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -547,6 +547,12 @@ public final class Pm {
throw new IllegalArgumentException("Missing inherit package name");
}
break;
+ case "--pkg":
+ sessionParams.appPackageName = nextOptionData();
+ if (sessionParams.appPackageName == null) {
+ throw new IllegalArgumentException("Missing package name");
+ }
+ break;
case "-S":
final long sizeBytes = Long.parseLong(nextOptionData());
if (sizeBytes <= 0) {
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 6dd31a852172..0f2ce3c09f00 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -249,8 +249,10 @@ public class AppOpsManager {
public static final int OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE = 67;
/** @hide Instant app start foreground service. */
public static final int OP_INSTANT_APP_START_FOREGROUND = 68;
+ /** @hide Answer incoming phone calls */
+ public static final int OP_ANSWER_PHONE_CALLS = 69;
/** @hide */
- public static final int _NUM_OP = 69;
+ public static final int _NUM_OP = 70;
/** Access to coarse location information. */
public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -356,6 +358,9 @@ public class AppOpsManager {
/** @hide */
public static final String OPSTR_INSTANT_APP_START_FOREGROUND
= "android:instant_app_start_foreground";
+ /** Answer incoming phone calls */
+ public static final String OPSTR_ANSWER_PHONE_CALLS
+ = "android:answer_phone_calls";
private static final int[] RUNTIME_AND_APPOP_PERMISSIONS_OPS = {
// RUNTIME PERMISSIONS
@@ -388,6 +393,7 @@ public class AppOpsManager {
OP_ADD_VOICEMAIL,
OP_USE_SIP,
OP_PROCESS_OUTGOING_CALLS,
+ OP_ANSWER_PHONE_CALLS,
// Microphone
OP_RECORD_AUDIO,
// Camera
@@ -480,6 +486,7 @@ public class AppOpsManager {
OP_REQUEST_INSTALL_PACKAGES,
OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE,
OP_INSTANT_APP_START_FOREGROUND,
+ OP_ANSWER_PHONE_CALLS
};
/**
@@ -556,6 +563,7 @@ public class AppOpsManager {
null, // OP_REQUEST_INSTALL_PACKAGES
null,
OPSTR_INSTANT_APP_START_FOREGROUND,
+ OPSTR_ANSWER_PHONE_CALLS,
};
/**
@@ -632,6 +640,7 @@ public class AppOpsManager {
"REQUEST_INSTALL_PACKAGES",
"OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE",
"INSTANT_APP_START_FOREGROUND",
+ "ANSWER_PHONE_CALLS",
};
/**
@@ -708,6 +717,7 @@ public class AppOpsManager {
Manifest.permission.REQUEST_INSTALL_PACKAGES,
null, // no permission for entering picture-in-picture on hide
Manifest.permission.INSTANT_APP_FOREGROUND_SERVICE,
+ Manifest.permission.ANSWER_PHONE_CALLS,
};
/**
@@ -785,6 +795,7 @@ public class AppOpsManager {
null, // REQUEST_INSTALL_PACKAGES
null, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
null, // INSTANT_APP_START_FOREGROUND
+ null, // ANSWER_PHONE_CALLS
};
/**
@@ -861,6 +872,7 @@ public class AppOpsManager {
false, // REQUEST_INSTALL_PACKAGES
false, // ENTER_PICTURE_IN_PICTURE_ON_HIDE
false, // INSTANT_APP_START_FOREGROUND
+ false, // ANSWER_PHONE_CALLS
};
/**
@@ -936,6 +948,7 @@ public class AppOpsManager {
AppOpsManager.MODE_DEFAULT, // OP_REQUEST_INSTALL_PACKAGES
AppOpsManager.MODE_ALLOWED, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
AppOpsManager.MODE_DEFAULT, // OP_INSTANT_APP_START_FOREGROUND
+ AppOpsManager.MODE_ALLOWED, // ANSWER_PHONE_CALLS
};
/**
@@ -1015,6 +1028,7 @@ public class AppOpsManager {
false, // OP_REQUEST_INSTALL_PACKAGES
false, // OP_ENTER_PICTURE_IN_PICTURE_ON_HIDE
false,
+ false, // ANSWER_PHONE_CALLS
};
/**
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 5205959361a5..d37e2099c1d7 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -447,6 +447,19 @@ public class NotificationManager
}
/**
+ * @hide
+ */
+ public void createNotificationChannelsForPackage(String pkg,
+ @NonNull List<NotificationChannel> channels) {
+ INotificationManager service = getService();
+ try {
+ service.createNotificationChannels(pkg, new ParceledListSlice(channels));
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Returns the notification channel settings for a given channel id.
*/
public NotificationChannel getNotificationChannel(String channelId) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index aff00c3e84b6..de503c0f5499 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2711,6 +2711,7 @@ public abstract class Context {
VIBRATOR_SERVICE,
//@hide: STATUS_BAR_SERVICE,
CONNECTIVITY_SERVICE,
+ IPSEC_SERVICE,
//@hide: UPDATE_LOCK_SERVICE,
//@hide: NETWORKMANAGEMENT_SERVICE,
NETWORK_STATS_SERVICE,
@@ -2814,6 +2815,9 @@ public abstract class Context {
* <dt> {@link #CONNECTIVITY_SERVICE} ("connection")
* <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
* handling management of network connections.
+ * <dt> {@link #IPSEC_SERVICE} ("ipsec")
+ * <dd> A {@link android.net.IpSecManager IpSecManager} for managing IPSec on
+ * sockets and networks.
* <dt> {@link #WIFI_SERVICE} ("wifi")
* <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
* connectivity. On releases before NYC, it should only be obtained from an application
@@ -3154,6 +3158,15 @@ public abstract class Context {
public static final String CONNECTIVITY_SERVICE = "connectivity";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
+ * IPSec.
+ *
+ * @see #getSystemService
+ */
+ public static final String IPSEC_SERVICE = "ipsec";
+
+ /**
* Use with {@link #getSystemService} to retrieve a {@link
* android.os.IUpdateLock} for managing runtime sequences that
* must not be interrupted by headless OTA application or similar.
diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java
new file mode 100644
index 000000000000..c4e4e06be749
--- /dev/null
+++ b/core/java/android/content/pm/BaseParceledListSlice.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Transfer a large list of Parcelable objects across an IPC. Splits into
+ * multiple transactions if needed.
+ *
+ * Caveat: for efficiency and security, all elements must be the same concrete type.
+ * In order to avoid writing the class name of each object, we must ensure that
+ * each object is the same type, or else unparceling then reparceling the data may yield
+ * a different result if the class name encoded in the Parcelable is a Base type.
+ * See b/17671747.
+ *
+ * @hide
+ */
+abstract class BaseParceledListSlice<T> implements Parcelable {
+ private static String TAG = "ParceledListSlice";
+ private static boolean DEBUG = false;
+
+ /*
+ * TODO get this number from somewhere else. For now set it to a quarter of
+ * the 1MB limit.
+ */
+ private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
+
+ private final List<T> mList;
+
+ public BaseParceledListSlice(List<T> list) {
+ mList = list;
+ }
+
+ @SuppressWarnings("unchecked")
+ BaseParceledListSlice(Parcel p, ClassLoader loader) {
+ final int N = p.readInt();
+ mList = new ArrayList<T>(N);
+ if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
+ if (N <= 0) {
+ return;
+ }
+
+ Parcelable.Creator<?> creator = readParcelableCreator(p, loader);
+ Class<?> listElementClass = null;
+
+ int i = 0;
+ while (i < N) {
+ if (p.readInt() == 0) {
+ break;
+ }
+
+ final T parcelable = readCreator(creator, p, loader);
+ if (listElementClass == null) {
+ listElementClass = parcelable.getClass();
+ } else {
+ verifySameType(listElementClass, parcelable.getClass());
+ }
+
+ mList.add(parcelable);
+
+ if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
+ i++;
+ }
+ if (i >= N) {
+ return;
+ }
+ final IBinder retriever = p.readStrongBinder();
+ while (i < N) {
+ if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
+ Parcel data = Parcel.obtain();
+ Parcel reply = Parcel.obtain();
+ data.writeInt(i);
+ try {
+ retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
+ return;
+ }
+ while (i < N && reply.readInt() != 0) {
+ final T parcelable = reply.readCreator(creator, loader);
+ verifySameType(listElementClass, parcelable.getClass());
+
+ mList.add(parcelable);
+
+ if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
+ i++;
+ }
+ reply.recycle();
+ data.recycle();
+ }
+ }
+
+ private T readCreator(Parcelable.Creator<?> creator, Parcel p, ClassLoader loader) {
+ if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+ Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+ (Parcelable.ClassLoaderCreator<?>) creator;
+ return (T) classLoaderCreator.createFromParcel(p, loader);
+ }
+ return (T) creator.createFromParcel(p);
+ }
+
+ private static void verifySameType(final Class<?> expected, final Class<?> actual) {
+ if (!actual.equals(expected)) {
+ throw new IllegalArgumentException("Can't unparcel type "
+ + actual.getName() + " in list of type "
+ + expected.getName());
+ }
+ }
+
+ public List<T> getList() {
+ return mList;
+ }
+
+ /**
+ * Write this to another Parcel. Note that this discards the internal Parcel
+ * and should not be used anymore. This is so we can pass this to a Binder
+ * where we won't have a chance to call recycle on this.
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ final int N = mList.size();
+ final int callFlags = flags;
+ dest.writeInt(N);
+ if (DEBUG) Log.d(TAG, "Writing " + N + " items");
+ if (N > 0) {
+ final Class<?> listElementClass = mList.get(0).getClass();
+ writeParcelableCreator(mList.get(0), dest);
+ int i = 0;
+ while (i < N && dest.dataSize() < MAX_IPC_SIZE) {
+ dest.writeInt(1);
+
+ final T parcelable = mList.get(i);
+ verifySameType(listElementClass, parcelable.getClass());
+ writeElement(parcelable, dest, callFlags);
+
+ if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
+ i++;
+ }
+ if (i < N) {
+ dest.writeInt(0);
+ Binder retriever = new Binder() {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+ throws RemoteException {
+ if (code != FIRST_CALL_TRANSACTION) {
+ return super.onTransact(code, data, reply, flags);
+ }
+ int i = data.readInt();
+ if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
+ while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
+ reply.writeInt(1);
+
+ final T parcelable = mList.get(i);
+ verifySameType(listElementClass, parcelable.getClass());
+ writeElement(parcelable, reply, callFlags);
+
+ if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
+ i++;
+ }
+ if (i < N) {
+ if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
+ reply.writeInt(0);
+ }
+ return true;
+ }
+ };
+ if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
+ dest.writeStrongBinder(retriever);
+ }
+ }
+ }
+
+ protected abstract void writeElement(T parcelable, Parcel reply, int callFlags);
+
+ protected abstract void writeParcelableCreator(T parcelable, Parcel dest);
+
+ protected abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader);
+}
diff --git a/core/java/android/content/pm/InstantAppInfo.java b/core/java/android/content/pm/InstantAppInfo.java
index 898ee1101c07..67afc928fd78 100644
--- a/core/java/android/content/pm/InstantAppInfo.java
+++ b/core/java/android/content/pm/InstantAppInfo.java
@@ -75,7 +75,7 @@ public final class InstantAppInfo implements Parcelable {
}
/**
- * @return The pakcage name.
+ * @return The package name.
*/
public @NonNull String getPackageName() {
if (mApplicationInfo != null) {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 278a6d09d9fe..9d04cc9bff5e 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -95,6 +95,18 @@ public class PackageInstaller {
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_SESSION_DETAILS = "android.content.pm.action.SESSION_DETAILS";
+ /**
+ * Broadcast Action: Explicit broadcast sent to the last known default launcher when a session
+ * for a new install is committed. For managed profile, this is sent to the default launcher
+ * of the primary profile.
+ * <p>
+ * The associated session is defined in {@link #EXTRA_SESSION} and the user for which this
+ * session was created in {@link Intent#EXTRA_USER}.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_SESSION_COMMITTED =
+ "android.content.pm.action.SESSION_COMMITTED";
+
/** {@hide} */
public static final String
ACTION_CONFIRM_PERMISSIONS = "android.content.pm.action.CONFIRM_PERMISSIONS";
@@ -107,6 +119,13 @@ public class PackageInstaller {
public static final String EXTRA_SESSION_ID = "android.content.pm.extra.SESSION_ID";
/**
+ * {@link SessionInfo} that an operation is working with.
+ *
+ * @see Intent#getParcelableExtra(String)
+ */
+ public static final String EXTRA_SESSION = "android.content.pm.extra.SESSION";
+
+ /**
* Package name that an operation is working with.
*
* @see Intent#getStringExtra(String)
@@ -1184,6 +1203,8 @@ public class PackageInstaller {
/** {@hide} */
public int mode;
/** {@hide} */
+ public int installReason;
+ /** {@hide} */
public long sizeBytes;
/** {@hide} */
public String appPackageName;
@@ -1206,6 +1227,7 @@ public class PackageInstaller {
active = source.readInt() != 0;
mode = source.readInt();
+ installReason = source.readInt();
sizeBytes = source.readLong();
appPackageName = source.readString();
appIcon = source.readParcelable(null);
@@ -1256,6 +1278,15 @@ public class PackageInstaller {
return active;
}
+ /**
+ * Return the reason for installing this package.
+ *
+ * @see PackageManager#INSTALL_REASON_UNKNOWN
+ */
+ public int getInstallReason() {
+ return installReason;
+ }
+
/** {@hide} */
@Deprecated
public boolean isOpen() {
@@ -1324,6 +1355,7 @@ public class PackageInstaller {
dest.writeInt(active ? 1 : 0);
dest.writeInt(mode);
+ dest.writeInt(installReason);
dest.writeLong(sizeBytes);
dest.writeString(appPackageName);
dest.writeParcelable(appIcon, flags);
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index 945858e6d3c6..d12e8846aabb 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -16,14 +16,9 @@
package android.content.pm;
-import android.os.Binder;
-import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -31,171 +26,46 @@ import java.util.List;
* Transfer a large list of Parcelable objects across an IPC. Splits into
* multiple transactions if needed.
*
- * Caveat: for efficiency and security, all elements must be the same concrete type.
- * In order to avoid writing the class name of each object, we must ensure that
- * each object is the same type, or else unparceling then reparceling the data may yield
- * a different result if the class name encoded in the Parcelable is a Base type.
- * See b/17671747.
+ * @see BaseParceledListSlice
*
* @hide
*/
-public class ParceledListSlice<T extends Parcelable> implements Parcelable {
- private static String TAG = "ParceledListSlice";
- private static boolean DEBUG = false;
-
- /*
- * TODO get this number from somewhere else. For now set it to a quarter of
- * the 1MB limit.
- */
- private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
-
- private final List<T> mList;
-
- public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
- return new ParceledListSlice<T>(Collections.<T> emptyList());
- }
-
+public class ParceledListSlice<T extends Parcelable> extends BaseParceledListSlice<T> {
public ParceledListSlice(List<T> list) {
- mList = list;
- }
-
- @SuppressWarnings("unchecked")
- private ParceledListSlice(Parcel p, ClassLoader loader) {
- final int N = p.readInt();
- mList = new ArrayList<T>(N);
- if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
- if (N <= 0) {
- return;
- }
-
- Parcelable.Creator<?> creator = p.readParcelableCreator(loader);
- Class<?> listElementClass = null;
-
- int i = 0;
- while (i < N) {
- if (p.readInt() == 0) {
- break;
- }
-
- final T parcelable = p.readCreator(creator, loader);
- if (listElementClass == null) {
- listElementClass = parcelable.getClass();
- } else {
- verifySameType(listElementClass, parcelable.getClass());
- }
-
- mList.add(parcelable);
-
- if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
- i++;
- }
- if (i >= N) {
- return;
- }
- final IBinder retriever = p.readStrongBinder();
- while (i < N) {
- if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
- Parcel data = Parcel.obtain();
- Parcel reply = Parcel.obtain();
- data.writeInt(i);
- try {
- retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
- } catch (RemoteException e) {
- Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
- return;
- }
- while (i < N && reply.readInt() != 0) {
- final T parcelable = reply.readCreator(creator, loader);
- verifySameType(listElementClass, parcelable.getClass());
-
- mList.add(parcelable);
-
- if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
- i++;
- }
- reply.recycle();
- data.recycle();
- }
+ super(list);
}
- private static void verifySameType(final Class<?> expected, final Class<?> actual) {
- if (!actual.equals(expected)) {
- throw new IllegalArgumentException("Can't unparcel type "
- + actual.getName() + " in list of type "
- + expected.getName());
- }
+ private ParceledListSlice(Parcel in, ClassLoader loader) {
+ super(in, loader);
}
- public List<T> getList() {
- return mList;
+ public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
+ return new ParceledListSlice<T>(Collections.<T> emptyList());
}
@Override
public int describeContents() {
int contents = 0;
- for (int i=0; i<mList.size(); i++) {
- contents |= mList.get(i).describeContents();
+ final List<T> list = getList();
+ for (int i=0; i<list.size(); i++) {
+ contents |= list.get(i).describeContents();
}
return contents;
}
- /**
- * Write this to another Parcel. Note that this discards the internal Parcel
- * and should not be used anymore. This is so we can pass this to a Binder
- * where we won't have a chance to call recycle on this.
- */
@Override
- public void writeToParcel(Parcel dest, int flags) {
- final int N = mList.size();
- final int callFlags = flags;
- dest.writeInt(N);
- if (DEBUG) Log.d(TAG, "Writing " + N + " items");
- if (N > 0) {
- final Class<?> listElementClass = mList.get(0).getClass();
- dest.writeParcelableCreator(mList.get(0));
- int i = 0;
- while (i < N && dest.dataSize() < MAX_IPC_SIZE) {
- dest.writeInt(1);
-
- final T parcelable = mList.get(i);
- verifySameType(listElementClass, parcelable.getClass());
- parcelable.writeToParcel(dest, callFlags);
-
- if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
- i++;
- }
- if (i < N) {
- dest.writeInt(0);
- Binder retriever = new Binder() {
- @Override
- protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
- throws RemoteException {
- if (code != FIRST_CALL_TRANSACTION) {
- return super.onTransact(code, data, reply, flags);
- }
- int i = data.readInt();
- if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
- while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
- reply.writeInt(1);
+ protected void writeElement(T parcelable, Parcel dest, int callFlags) {
+ parcelable.writeToParcel(dest, callFlags);
+ }
- final T parcelable = mList.get(i);
- verifySameType(listElementClass, parcelable.getClass());
- parcelable.writeToParcel(reply, callFlags);
+ @Override
+ protected void writeParcelableCreator(T parcelable, Parcel dest) {
+ dest.writeParcelableCreator((Parcelable) parcelable);
+ }
- if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
- i++;
- }
- if (i < N) {
- if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
- reply.writeInt(0);
- }
- return true;
- }
- };
- if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
- dest.writeStrongBinder(retriever);
- }
- }
+ @Override
+ protected Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
+ return from.readParcelableCreator(loader);
}
@SuppressWarnings("unchecked")
@@ -210,6 +80,7 @@ public class ParceledListSlice<T extends Parcelable> implements Parcelable {
return new ParceledListSlice(in, loader);
}
+ @Override
public ParceledListSlice[] newArray(int size) {
return new ParceledListSlice[size];
}
diff --git a/core/java/android/content/pm/ResolveInfo.java b/core/java/android/content/pm/ResolveInfo.java
index 50f2d5371019..650b4c008dcc 100644
--- a/core/java/android/content/pm/ResolveInfo.java
+++ b/core/java/android/content/pm/ResolveInfo.java
@@ -69,6 +69,11 @@ public class ResolveInfo implements Parcelable {
public AuxiliaryResolveInfo auxiliaryInfo;
/**
+ * Whether or not an instant app is available for the resolved intent.
+ */
+ public boolean instantAppAvailable;
+
+ /**
* The IntentFilter that was matched for this ResolveInfo.
*/
public IntentFilter filter;
@@ -325,6 +330,7 @@ public class ResolveInfo implements Parcelable {
system = orig.system;
targetUserId = orig.targetUserId;
handleAllWebDataURI = orig.handleAllWebDataURI;
+ instantAppAvailable = orig.instantAppAvailable;
}
public String toString() {
@@ -388,6 +394,7 @@ public class ResolveInfo implements Parcelable {
dest.writeInt(noResourceId ? 1 : 0);
dest.writeInt(iconResourceId);
dest.writeInt(handleAllWebDataURI ? 1 : 0);
+ dest.writeInt(instantAppAvailable ? 1 : 0);
}
public static final Creator<ResolveInfo> CREATOR
@@ -435,6 +442,7 @@ public class ResolveInfo implements Parcelable {
noResourceId = source.readInt() != 0;
iconResourceId = source.readInt();
handleAllWebDataURI = source.readInt() != 0;
+ instantAppAvailable = source.readInt() != 0;
}
public static class DisplayNameComparator
diff --git a/core/java/android/content/pm/StringParceledListSlice.aidl b/core/java/android/content/pm/StringParceledListSlice.aidl
new file mode 100644
index 000000000000..345f3a7b5e3e
--- /dev/null
+++ b/core/java/android/content/pm/StringParceledListSlice.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable StringParceledListSlice;
diff --git a/core/java/android/content/pm/StringParceledListSlice.java b/core/java/android/content/pm/StringParceledListSlice.java
new file mode 100644
index 000000000000..95407449a018
--- /dev/null
+++ b/core/java/android/content/pm/StringParceledListSlice.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Transfer a large list of Parcelable objects across an IPC. Splits into
+ * multiple transactions if needed.
+ *
+ * @see BaseParceledListSlice
+ *
+ * @hide
+ */
+public class StringParceledListSlice extends BaseParceledListSlice<String> {
+ public StringParceledListSlice(List<String> list) {
+ super(list);
+ }
+
+ private StringParceledListSlice(Parcel in, ClassLoader loader) {
+ super(in, loader);
+ }
+
+ public static StringParceledListSlice emptyList() {
+ return new StringParceledListSlice(Collections.<String> emptyList());
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ protected void writeElement(String parcelable, Parcel reply, int callFlags) {
+ reply.writeString(parcelable);
+ }
+
+ @Override
+ protected void writeParcelableCreator(String parcelable, Parcel dest) {
+ return;
+ }
+
+ @Override
+ protected Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
+ return Parcel.STRING_CREATOR;
+ }
+
+ @SuppressWarnings("unchecked")
+ public static final Parcelable.ClassLoaderCreator<StringParceledListSlice> CREATOR =
+ new Parcelable.ClassLoaderCreator<StringParceledListSlice>() {
+ public StringParceledListSlice createFromParcel(Parcel in) {
+ return new StringParceledListSlice(in, null);
+ }
+
+ @Override
+ public StringParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
+ return new StringParceledListSlice(in, loader);
+ }
+
+ @Override
+ public StringParceledListSlice[] newArray(int size) {
+ return new StringParceledListSlice[size];
+ }
+ };
+}
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
new file mode 100644
index 000000000000..da5cb37961ab
--- /dev/null
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.annotation.StringDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
+ * RFC 4301.
+ */
+public final class IpSecAlgorithm implements Parcelable {
+
+ /**
+ * AES-CBC Encryption/Ciphering Algorithm.
+ *
+ * <p>Valid lengths for this key are {128, 192, 256}.
+ */
+ public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+
+ /**
+ * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new
+ * applications and is provided for legacy compatibility with 3gpp infrastructure.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
+ */
+ public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+
+ /**
+ * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in
+ * new applications and is provided for legacy compatibility with 3gpp infrastructure.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+
+ /**
+ * SHA256 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+
+ /**
+ * SHA384 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ /**
+ * SHA512 HMAC Authentication/Integrity Algorithm
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+
+ /** @hide */
+ @StringDef({
+ ALGO_CRYPT_AES_CBC,
+ ALGO_AUTH_HMAC_MD5,
+ ALGO_AUTH_HMAC_SHA1,
+ ALGO_AUTH_HMAC_SHA256,
+ ALGO_AUTH_HMAC_SHA512
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AlgorithmName {}
+
+ private final String mName;
+ private final byte[] mKey;
+ private final int mTruncLenBits;
+
+ /**
+ * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
+ * algorithm
+ *
+ * @param algorithm type for IpSec.
+ * @param key non-null Key padded to a multiple of 8 bits.
+ */
+ public IpSecAlgorithm(String algorithm, byte[] key) {
+ this(algorithm, key, key.length * 8);
+ }
+
+ /**
+ * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
+ * algorithm
+ *
+ * @param algoName precise name of the algorithm to be used.
+ * @param key non-null Key padded to a multiple of 8 bits.
+ * @param truncLenBits the number of bits of output hash to use; only meaningful for
+ * Authentication.
+ */
+ public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) {
+ if (!isTruncationLengthValid(algoName, truncLenBits)) {
+ throw new IllegalArgumentException("Unknown algorithm or invalid length");
+ }
+ mName = algoName;
+ mKey = key.clone();
+ mTruncLenBits = Math.min(truncLenBits, key.length * 8);
+ }
+
+ /** Retrieve the algorithm name */
+ public String getName() {
+ return mName;
+ }
+
+ /** Retrieve the key for this algorithm */
+ public byte[] getKey() {
+ return mKey.clone();
+ }
+
+ /**
+ * Retrieve the truncation length, in bits, for the key in this algo. By default this will be
+ * the length in bits of the key.
+ */
+ public int getTruncationLengthBits() {
+ return mTruncLenBits;
+ }
+
+ /* Parcelable Implementation */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName);
+ out.writeByteArray(mKey);
+ out.writeInt(mTruncLenBits);
+ }
+
+ /** Parcelable Creator */
+ public static final Parcelable.Creator<IpSecAlgorithm> CREATOR =
+ new Parcelable.Creator<IpSecAlgorithm>() {
+ public IpSecAlgorithm createFromParcel(Parcel in) {
+ return new IpSecAlgorithm(in);
+ }
+
+ public IpSecAlgorithm[] newArray(int size) {
+ return new IpSecAlgorithm[size];
+ }
+ };
+
+ private IpSecAlgorithm(Parcel in) {
+ mName = in.readString();
+ mKey = in.createByteArray();
+ mTruncLenBits = in.readInt();
+ }
+
+ private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
+ switch (algo) {
+ case ALGO_AUTH_HMAC_MD5:
+ return (truncLenBits >= 96 && truncLenBits <= 128);
+ case ALGO_AUTH_HMAC_SHA1:
+ return (truncLenBits >= 96 && truncLenBits <= 160);
+ case ALGO_AUTH_HMAC_SHA256:
+ return (truncLenBits >= 96 && truncLenBits <= 256);
+ case ALGO_AUTH_HMAC_SHA384:
+ return (truncLenBits >= 192 && truncLenBits <= 384);
+ case ALGO_AUTH_HMAC_SHA512:
+ return (truncLenBits >= 256 && truncLenBits <= 512);
+ default:
+ return false;
+ }
+ }
+};
diff --git a/core/java/android/net/IpSecConfig.aidl b/core/java/android/net/IpSecConfig.aidl
new file mode 100644
index 000000000000..eaefca74d3a0
--- /dev/null
+++ b/core/java/android/net/IpSecConfig.aidl
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+/** @hide */
+parcelable IpSecConfig;
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
new file mode 100644
index 000000000000..b58bf421a86a
--- /dev/null
+++ b/core/java/android/net/IpSecConfig.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/** @hide */
+public final class IpSecConfig implements Parcelable {
+ private static final String TAG = IpSecConfig.class.getSimpleName();
+
+ //MODE_TRANSPORT or MODE_TUNNEL
+ int mode;
+
+ // For tunnel mode
+ InetAddress localAddress;
+
+ InetAddress remoteAddress;
+
+ // Limit selection by network interface
+ Network network;
+
+ public static class Flow {
+ // Minimum requirements for identifying a transform
+ // SPI identifying the IPsec flow in packet processing
+ // and a remote IP address
+ int spi;
+
+ // Encryption Algorithm
+ IpSecAlgorithm encryptionAlgo;
+
+ // Authentication Algorithm
+ IpSecAlgorithm authenticationAlgo;
+ }
+
+ Flow[] flow = new Flow[2];
+
+ // For tunnel mode IPv4 UDP Encapsulation
+ // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
+ int encapType;
+ int encapLocalPort;
+ int encapRemotePort;
+
+ // An optional protocol to match with the selector
+ int selectorProto;
+
+ // A bitmask of FEATURE_* indicating which of the fields
+ // of this class are valid.
+ long features;
+
+ // An interval, in seconds between the NattKeepalive packets
+ int nattKeepaliveInterval;
+
+ public InetAddress getLocalIp() {
+ return localAddress;
+ }
+
+ public int getSpi(int direction) {
+ return flow[direction].spi;
+ }
+
+ public InetAddress getRemoteIp() {
+ return remoteAddress;
+ }
+
+ public IpSecAlgorithm getEncryptionAlgo(int direction) {
+ return flow[direction].encryptionAlgo;
+ }
+
+ public IpSecAlgorithm getAuthenticationAlgo(int direction) {
+ return flow[direction].authenticationAlgo;
+ }
+
+ Network getNetwork() {
+ return network;
+ }
+
+ public int getEncapType() {
+ return encapType;
+ }
+
+ public int getEncapLocalPort() {
+ return encapLocalPort;
+ }
+
+ public int getEncapRemotePort() {
+ return encapRemotePort;
+ }
+
+ public int getSelectorProto() {
+ return selectorProto;
+ }
+
+ int getNattKeepaliveInterval() {
+ return nattKeepaliveInterval;
+ }
+
+ public boolean hasProperty(int featureBits) {
+ return (features & featureBits) == featureBits;
+ }
+
+ // Parcelable Methods
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(features);
+ // TODO: Use a byte array or other better method for storing IPs that can also include scope
+ out.writeString((localAddress != null) ? localAddress.getHostAddress() : null);
+ // TODO: Use a byte array or other better method for storing IPs that can also include scope
+ out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null);
+ out.writeParcelable(network, flags);
+ out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags);
+ out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags);
+ out.writeInt(encapType);
+ out.writeInt(encapLocalPort);
+ out.writeInt(encapRemotePort);
+ out.writeInt(selectorProto);
+ }
+
+ // Package Private: Used by the IpSecTransform.Builder;
+ // there should be no public constructor for this object
+ IpSecConfig() {
+ flow[IpSecTransform.DIRECTION_IN].spi = 0;
+ flow[IpSecTransform.DIRECTION_OUT].spi = 0;
+ nattKeepaliveInterval = 0; //FIXME constant
+ }
+
+ private static InetAddress readInetAddressFromParcel(Parcel in) {
+ String addrString = in.readString();
+ if (addrString == null) {
+ return null;
+ }
+ try {
+ return InetAddress.getByName(addrString);
+ } catch (UnknownHostException e) {
+ Log.wtf(TAG, "Invalid IpAddress " + addrString);
+ return null;
+ }
+ }
+
+ private IpSecConfig(Parcel in) {
+ features = in.readLong();
+ localAddress = readInetAddressFromParcel(in);
+ remoteAddress = readInetAddressFromParcel(in);
+ network = (Network) in.readParcelable(Network.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_IN].spi = in.readInt();
+ flow[IpSecTransform.DIRECTION_IN].encryptionAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_IN].authenticationAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt();
+ flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ encapType = in.readInt();
+ encapLocalPort = in.readInt();
+ encapRemotePort = in.readInt();
+ selectorProto = in.readInt();
+ }
+
+ public static final Parcelable.Creator<IpSecConfig> CREATOR =
+ new Parcelable.Creator<IpSecConfig>() {
+ public IpSecConfig createFromParcel(Parcel in) {
+ return new IpSecConfig(in);
+ }
+
+ public IpSecConfig[] newArray(int size) {
+ return new IpSecConfig[size];
+ }
+ };
+}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
new file mode 100644
index 000000000000..2c544e9b9bfe
--- /dev/null
+++ b/core/java/android/net/IpSecManager.java
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.INetworkManagementService;
+import android.os.ParcelFileDescriptor;
+import android.util.AndroidException;
+import dalvik.system.CloseGuard;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Socket;
+
+/**
+ * This class contains methods for managing IPsec sessions, which will perform kernel-space
+ * encryption and decryption of socket or Network traffic.
+ *
+ * <p>An IpSecManager may be obtained by calling {@link
+ * android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
+ * android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
+ */
+public final class IpSecManager {
+ private static final String TAG = "IpSecManager";
+
+ /**
+ * Indicates that the combination of remote InetAddress and SPI was non-unique for a given
+ * request. If encountered, selection of a new SPI is required before a transform may be
+ * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
+ * or reserved using reserveSecurityParameterIndex.
+ */
+ public static final class SpiUnavailableException extends AndroidException {
+ private final int mSpi;
+
+ /**
+ * Construct an exception indicating that a transform with the given SPI is already in use
+ * or otherwise unavailable.
+ *
+ * @param msg Description indicating the colliding SPI
+ * @param spi the SPI that could not be used due to a collision
+ */
+ SpiUnavailableException(String msg, int spi) {
+ super(msg + "(spi: " + spi + ")");
+ mSpi = spi;
+ }
+
+ /** Retrieve the SPI that caused a collision */
+ public int getSpi() {
+ return mSpi;
+ }
+ }
+
+ /**
+ * Indicates that the requested system resource for IPsec, such as a socket or other system
+ * resource is unavailable. If this exception is thrown, try releasing allocated objects of the
+ * type requested.
+ */
+ public static final class ResourceUnavailableException extends AndroidException {
+
+ ResourceUnavailableException(String msg) {
+ super(msg);
+ }
+ }
+
+ private final Context mContext;
+ private final INetworkManagementService mService;
+
+ public static final class SecurityParameterIndex implements AutoCloseable {
+ private final Context mContext;
+ private final InetAddress mDestinationAddress;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private int mSpi;
+
+ /** Return the underlying SPI held by this object */
+ public int getSpi() {
+ return mSpi;
+ }
+
+ private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi)
+ throws ResourceUnavailableException, SpiUnavailableException {
+ mContext = context;
+ mDestinationAddress = destinationAddress;
+ mSpi = spi;
+ mCloseGuard.open("open");
+ }
+
+ /**
+ * Release an SPI that was previously reserved.
+ *
+ * <p>Release an SPI for use by other users in the system. This will fail if the SPI is
+ * currently in use by an IpSecTransform.
+ *
+ * @param destinationAddress SPIs must be unique for each combination of SPI and destination
+ * address. Thus, the destinationAddress to which the SPI will communicate must be
+ * supplied.
+ * @param spi the previously reserved SPI to be freed.
+ */
+ @Override
+ public void close() {
+ mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ }
+ }
+
+ /**
+ * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
+ *
+ * <p>No IPsec packet may contain an SPI of 0.
+ */
+ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
+
+ /**
+ * Reserve an SPI for traffic bound towards the specified destination address.
+ *
+ * <p>If successful, this SPI is guaranteed available until released by a call to {@link
+ * SecurityParameterIndex#close()}.
+ *
+ * @param destinationAddress SPIs must be unique for each combination of SPI and destination
+ * address.
+ * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
+ * @return the reserved SecurityParameterIndex
+ * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
+ * for this user
+ * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
+ */
+ public SecurityParameterIndex reserveSecurityParameterIndex(
+ InetAddress destinationAddress, int requestedSpi)
+ throws SpiUnavailableException, ResourceUnavailableException {
+ return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi);
+ }
+
+ /**
+ * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * address associated with that transform will throw an IOException. In addition, if the
+ * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
+ * send() or receive() until the transform is removed from the socket by calling {@link
+ * #removeTransportModeTransform(Socket, IpSecTransform)};
+ *
+ * @param socket a stream socket
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
+ }
+
+ /**
+ * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * address associated with that transform will throw an IOException. In addition, if the
+ * IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
+ * send() or receive() until the transform is removed from the socket by calling {@link
+ * #removeTransportModeTransform(DatagramSocket, IpSecTransform)};
+ *
+ * @param socket a datagram socket
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
+ }
+
+ /* Call down to activate a transform */
+ private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+
+ /**
+ * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
+ * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to
+ * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic).
+ * Applications should probably not use this API directly. Instead, they should use {@link
+ * VpnService} to provide VPN capability in a more generic fashion.
+ *
+ * @param net a {@link Network} that will be tunneled via IP Sec.
+ * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
+ * @hide
+ */
+ @SystemApi
+ public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
+
+ /**
+ * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @param socket a socket that previously had a transform applied to it.
+ * @param transform the IPsec Transform that was previously applied to the given socket
+ */
+ public void removeTransportModeTransform(Socket socket, IpSecTransform transform) {
+ removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
+ }
+
+ /**
+ * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @param socket a socket that previously had a transform applied to it.
+ * @param transform the IPsec Transform that was previously applied to the given socket
+ */
+ public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) {
+ removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
+ }
+
+ /* Call down to activate a transform */
+ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+
+ /**
+ * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
+ * cleanup if a tunneled Network experiences a change in default route. The Network will drop
+ * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
+ * lost, all traffic will drop.
+ *
+ * @param net a network that currently has transform applied to it.
+ * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
+ * network
+ * @hide
+ */
+ @SystemApi
+ public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
+
+ /**
+ * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for
+ * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic.
+ *
+ * <p>The socket provided by this class cannot be re-bound or closed via the inner
+ * FileDescriptor. Instead, disposing of this socket requires a call to close().
+ */
+ public static final class UdpEncapsulationSocket implements AutoCloseable {
+ private final FileDescriptor mFd;
+ private final Context mContext;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private UdpEncapsulationSocket(Context context, int port)
+ throws ResourceUnavailableException {
+ mContext = context;
+ mCloseGuard.open("constructor");
+ // TODO: go down to the kernel and get a socket on the specified
+ mFd = new FileDescriptor();
+ }
+
+ private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException {
+ mContext = context;
+ mCloseGuard.open("constructor");
+ // TODO: go get a random socket on a random port
+ mFd = new FileDescriptor();
+ }
+
+ /** Access the inner UDP Encapsulation Socket */
+ public FileDescriptor getSocket() {
+ return mFd;
+ }
+
+ /** Retrieve the port number of the inner encapsulation socket */
+ public int getPort() {
+ return 0; // TODO get the port number from the Socket;
+ }
+
+ @Override
+ /**
+ * Release the resources that have been reserved for this Socket.
+ *
+ * <p>This method closes the underlying socket, reducing a user's allocated sockets in the
+ * system. This must be done as part of cleanup following use of a socket. Failure to do so
+ * will cause the socket to count against a total allocation limit for IpSec and eventually
+ * fail due to resource limits.
+ *
+ * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
+ */
+ public void close() {
+ // TODO: Go close the socket
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ }
+ };
+
+ /**
+ * Open a socket that is bound to a free UDP port on the system.
+ *
+ * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
+ * the caller. This provides safe access to a socket on a port that can later be used as a UDP
+ * Encapsulation port.
+ *
+ * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
+ * socket port. Explicitly opening this port is only necessary if communication is desired on
+ * that port.
+ *
+ * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this
+ * method will bind to the specified port or fail. To retrieve the port number, call {@link
+ * android.system.Os#getsockname(FileDescriptor)}.
+ * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime
+ * of the object.
+ */
+ // Returning a socket in this fashion that has been created and bound by the system
+ // is the only safe way to ensure that a socket is both accessible to the user and
+ // safely usable for Encapsulation without allowing a user to possibly unbind from/close
+ // the port, which could potentially impact the traffic of the next user who binds to that
+ // socket.
+ public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
+ throws IOException, ResourceUnavailableException {
+ // Temporary code
+ return new UdpEncapsulationSocket(mContext, port);
+ }
+
+ /**
+ * Open a socket that is bound to a port selected by the system.
+ *
+ * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
+ * the caller. This provides safe access to a socket on a port that can later be used as a UDP
+ * Encapsulation port.
+ *
+ * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
+ * socket port. Explicitly opening this port is only necessary if communication is desired on
+ * that port.
+ *
+ * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port
+ */
+ // Returning a socket in this fashion that has been created and bound by the system
+ // is the only safe way to ensure that a socket is both accessible to the user and
+ // safely usable for Encapsulation without allowing a user to possibly unbind from/close
+ // the port, which could potentially impact the traffic of the next user who binds to that
+ // socket.
+ public UdpEncapsulationSocket openUdpEncapsulationSocket()
+ throws IOException, ResourceUnavailableException {
+ // Temporary code
+ return new UdpEncapsulationSocket(mContext);
+ }
+
+ /**
+ * Retrieve an instance of an IpSecManager within you application context
+ *
+ * @param context the application context for this manager
+ * @hide
+ */
+ public IpSecManager(Context context, INetworkManagementService service) {
+ mContext = checkNotNull(context, "missing context");
+ mService = checkNotNull(service, "missing service");
+ }
+}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
new file mode 100644
index 000000000000..d6dd28bec390
--- /dev/null
+++ b/core/java/android/net/IpSecTransform.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.net;
+
+import android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.system.ErrnoException;
+import android.util.Log;
+import dalvik.system.CloseGuard;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+
+/**
+ * This class represents an IpSecTransform, which encapsulates both properties and state of IPsec.
+ *
+ * <p>IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout
+ * the lifetime of the underlying transform. If a transform object leaves scope, the underlying
+ * transform may be disabled automatically, with likely undesirable results.
+ *
+ * <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array
+ * of traffic or may represent a transport mode transform operating on a Socket or Sockets.
+ */
+public final class IpSecTransform implements AutoCloseable {
+ private static final String TAG = "IpSecTransform";
+
+ /**
+ * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
+ * to traffic towards the host.
+ */
+ public static final int DIRECTION_IN = 0;
+
+ /**
+ * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
+ * to traffic from the host.
+ */
+ public static final int DIRECTION_OUT = 1;
+
+ /** @hide */
+ @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TransformDirection {}
+
+ /** @hide */
+ private static final int MODE_TUNNEL = 0;
+
+ /** @hide */
+ private static final int MODE_TRANSPORT = 1;
+
+ /** @hide */
+ public static final int ENCAP_NONE = 0;
+
+ /**
+ * IpSec traffic will be encapsulated within UDP as per <a
+ * href="https://tools.ietf.org/html/rfc3948">RFC3498</a>.
+ *
+ * @hide
+ */
+ public static final int ENCAP_ESPINUDP = 1;
+
+ /**
+ * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad
+ * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP.
+ *
+ * @hide
+ */
+ public static final int ENCAP_ESPINUDP_NONIKE = 2;
+
+ /** @hide */
+ @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NONIKE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EncapType {}
+
+ /**
+ * Sentinel for an invalid transform (means that this transform is inactive).
+ *
+ * @hide
+ */
+ public static final int INVALID_TRANSFORM_ID = -1;
+
+ private IpSecTransform(Context context, IpSecConfig config) {
+ mContext = context;
+ mConfig = config;
+ mTransformId = INVALID_TRANSFORM_ID;
+ }
+
+ private IpSecTransform activate()
+ throws IOException, IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException {
+ int transformId;
+ synchronized (this) {
+ //try {
+ transformId = INVALID_TRANSFORM_ID;
+ //} catch (RemoteException e) {
+ // throw e.rethrowFromSystemServer();
+ //}
+
+ if (transformId < 0) {
+ throw new ErrnoException("addTransform", -transformId).rethrowAsIOException();
+ }
+
+ startKeepalive(mContext); // Will silently fail if not required
+ mTransformId = transformId;
+ Log.d(TAG, "Added Transform with Id " + transformId);
+ }
+ mCloseGuard.open("build");
+
+ return this;
+ }
+
+ /**
+ * Deactivate an IpSecTransform and free all resources for that transform that are managed by
+ * the system for this Transform.
+ *
+ * <p>Deactivating a transform while it is still applied to any Socket will result in sockets
+ * refusing to send or receive data. This method will silently succeed if the specified
+ * transform has already been removed; thus, it is always safe to attempt cleanup when a
+ * transform is no longer needed.
+ */
+ public void close() {
+ Log.d(TAG, "Removing Transform with Id " + mTransformId);
+
+ // Always safe to attempt cleanup
+ if (mTransformId == INVALID_TRANSFORM_ID) {
+ return;
+ }
+ //try {
+ stopKeepalive();
+ //} catch (RemoteException e) {
+ // transform.setTransformId(transformId);
+ // throw e.rethrowFromSystemServer();
+ //} finally {
+ mTransformId = INVALID_TRANSFORM_ID;
+ //}
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /* Package */
+ IpSecConfig getConfig() {
+ return mConfig;
+ }
+
+ private final IpSecConfig mConfig;
+ private int mTransformId;
+ private final Context mContext;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private ConnectivityManager.PacketKeepalive mKeepalive;
+ private int mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+ private Object mKeepaliveSyncLock = new Object();
+ private ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback =
+ new ConnectivityManager.PacketKeepaliveCallback() {
+
+ @Override
+ public void onStarted() {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = ConnectivityManager.PacketKeepalive.SUCCESS;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onStopped() {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onError(int error) {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = error;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+ };
+
+ /* Package */
+ void startKeepalive(Context c) {
+ if (mConfig.getNattKeepaliveInterval() == 0) {
+ return;
+ }
+
+ ConnectivityManager cm =
+ (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (mKeepalive != null) {
+ Log.e(TAG, "Keepalive already started for this IpSecTransform.");
+ return;
+ }
+
+ synchronized (mKeepaliveSyncLock) {
+ mKeepalive =
+ cm.startNattKeepalive(
+ mConfig.getNetwork(),
+ mConfig.getNattKeepaliveInterval(),
+ mKeepaliveCallback,
+ mConfig.getLocalIp(),
+ mConfig.getEncapLocalPort(),
+ mConfig.getRemoteIp());
+ try {
+ mKeepaliveSyncLock.wait(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (mKeepaliveStatus != ConnectivityManager.PacketKeepalive.SUCCESS) {
+ throw new UnsupportedOperationException("Packet Keepalive cannot be started");
+ }
+ }
+
+ /* Package */
+ void stopKeepalive() {
+ if (mKeepalive == null) {
+ return;
+ }
+ mKeepalive.stop();
+ synchronized (mKeepaliveSyncLock) {
+ if (mKeepaliveStatus == ConnectivityManager.PacketKeepalive.SUCCESS) {
+ try {
+ mKeepaliveSyncLock.wait(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ /* Package */
+ void setTransformId(int transformId) {
+ mTransformId = transformId;
+ }
+
+ /* Package */
+ int getTransformId() {
+ return mTransformId;
+ }
+
+ /**
+ * Builder object to facilitate the creation of IpSecTransform objects.
+ *
+ * <p>Apply additional properties to the transform and then call a build() method to return an
+ * IpSecTransform object.
+ *
+ * @see Builder#buildTransportModeTransform(InetAddress)
+ */
+ public static class Builder {
+ private Context mContext;
+ private IpSecConfig mConfig;
+
+ /**
+ * Add an encryption algorithm to the transform for the given direction.
+ *
+ * <p>If encryption is set for a given direction without also providing an SPI for that
+ * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
+ */
+ public IpSecTransform.Builder setEncryption(
+ @TransformDirection int direction, IpSecAlgorithm algo) {
+ mConfig.flow[direction].encryptionAlgo = algo;
+ return this;
+ }
+
+ /**
+ * Add an authentication/integrity algorithm to the transform.
+ *
+ * <p>If authentication is set for a given direction without also providing an SPI for that
+ * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
+ */
+ public IpSecTransform.Builder setAuthentication(
+ @TransformDirection int direction, IpSecAlgorithm algo) {
+ mConfig.flow[direction].authenticationAlgo = algo;
+ return this;
+ }
+
+ /**
+ * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
+ * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
+ * given destination address.
+ *
+ * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
+ * possible. Random number generation is a reasonable approach to selecting an SPI. For
+ * outbound SPIs, they must be reserved by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+ * fail to build.
+ *
+ * <p>Unless an SPI is set for a given direction, traffic in that direction will be
+ * sent/received without any IPsec applied.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param spi a unique 32-bit integer to identify transformed traffic
+ */
+ public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) {
+ mConfig.flow[direction].spi = spi;
+ return this;
+ }
+
+ /**
+ * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
+ * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
+ * given destination address.
+ *
+ * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
+ * possible. Random number generation is a reasonable approach to selecting an SPI. For
+ * outbound SPIs, they must be reserved by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+ * fail to activate.
+ *
+ * <p>Unless an SPI is set for a given direction, traffic in that direction will be
+ * sent/received without any IPsec applied.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
+ * traffic
+ */
+ public IpSecTransform.Builder setSpi(
+ @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
+ mConfig.flow[direction].spi = spi.getSpi();
+ return this;
+ }
+
+ /**
+ * Specify the network on which this transform will emit its traffic; (otherwise it will
+ * emit on the default network).
+ *
+ * <p>Restricts the transformed traffic to a particular {@link Network}. This is required in
+ * tunnel mode.
+ *
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform.Builder setUnderlyingNetwork(Network net) {
+ mConfig.network = net;
+ return this;
+ }
+
+ /**
+ * Add UDP encapsulation to an IPv4 transform
+ *
+ * <p>This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for
+ * details on how UDP should be applied to IPsec.
+ *
+ * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and
+ * receiving encapsulating traffic.
+ * @param remotePort the UDP port number of the remote that will send and receive
+ * encapsulated traffic. In the case of IKE, this is likely port 4500.
+ */
+ public IpSecTransform.Builder setIpv4Encapsulation(
+ IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
+ // TODO: check encap type is valid.
+ mConfig.encapType = ENCAP_ESPINUDP;
+ mConfig.encapLocalPort = localSocket.getPort(); // TODO: plug in the encap socket
+ mConfig.encapRemotePort = remotePort;
+ return this;
+ }
+
+ // TODO: Decrease the minimum keepalive to maybe 10?
+ // TODO: Probably a better exception to throw for NATTKeepalive failure
+ // TODO: Specify the needed NATT keepalive permission.
+ /**
+ * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded
+ * request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot
+ * be activated, then the transform will fail to activate and throw an IOException.
+ *
+ * @param intervalSeconds the maximum number of seconds between keepalive packets, no less
+ * than 20s and no more than 3600s.
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) {
+ mConfig.nattKeepaliveInterval = intervalSeconds;
+ return this;
+ }
+
+ /**
+ * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform.
+ * Some parameters have interdependencies that are checked at build time. If a well-formed
+ * transform cannot be created from the supplied parameters, this method will throw an
+ * Exception.
+ *
+ * <p>Upon a successful return from this call, the provided IpSecTransform will be active
+ * and may be applied to sockets. If too many IpSecTransform objects are active for a given
+ * user this operation will fail and throw ResourceUnavailableException. To avoid these
+ * exceptions, unused Transform objects must be cleaned up by calling {@link
+ * IpSecTransform#close()} when they are no longer needed.
+ *
+ * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this
+ * socket will cause the transform to be applied.
+ * <p>Note that an active transform will not impact any network traffic until it has
+ * been applied to one or more Sockets. Calling this method is a necessary precondition
+ * for applying it to a socket, but is not sufficient to actually apply IPsec.
+ * @throws IllegalArgumentException indicating that a particular combination of transform
+ * properties is invalid.
+ * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms
+ * may be allocated
+ * @throws SpiUnavailableException if the SPI collides with an existing transform
+ * (unlikely).
+ * @throws ResourceUnavailableException if the current user currently has exceeded the
+ * number of allowed active transforms.
+ */
+ public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress)
+ throws IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException, IOException {
+ //FIXME: argument validation here
+ //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
+ mConfig.mode = MODE_TRANSPORT;
+ mConfig.remoteAddress = remoteAddress;
+ return new IpSecTransform(mContext, mConfig).activate();
+ }
+
+ /**
+ * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some
+ * parameters have interdependencies that are checked at build time.
+ *
+ * @param localAddress the {@link InetAddress} that provides the local endpoint for this
+ * IPsec tunnel. This is almost certainly an address belonging to the {@link Network}
+ * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}.
+ * @param remoteAddress the {@link InetAddress} representing the remote endpoint of this
+ * IPsec tunnel.
+ * @throws IllegalArgumentException indicating that a particular combination of transform
+ * properties is invalid.
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform buildTunnelModeTransform(
+ InetAddress localAddress, InetAddress remoteAddress) {
+ //FIXME: argument validation here
+ //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
+ mConfig.localAddress = localAddress;
+ mConfig.remoteAddress = remoteAddress;
+ mConfig.mode = MODE_TUNNEL;
+ return new IpSecTransform(mContext, mConfig);
+ }
+
+ /**
+ * Create a new IpSecTransform.Builder to construct an IpSecTransform
+ *
+ * @param context current Context
+ */
+ public Builder(Context context) {
+ mContext = context;
+ mConfig = new IpSecConfig();
+ }
+ }
+}
diff --git a/core/java/android/net/NetworkPolicyManager.java b/core/java/android/net/NetworkPolicyManager.java
index 1b715af0da29..43fab037f254 100644
--- a/core/java/android/net/NetworkPolicyManager.java
+++ b/core/java/android/net/NetworkPolicyManager.java
@@ -19,6 +19,7 @@ package android.net;
import static android.content.pm.PackageManager.GET_SIGNATURES;
import static android.net.NetworkPolicy.CYCLE_NONE;
+import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
@@ -381,4 +382,20 @@ public class NetworkPolicyManager {
string.append(")");
return string.toString();
}
+
+ /**
+ * Returns true if {@param procState} is considered foreground and as such will be allowed
+ * to access network when the device is idle or in battery saver mode. Otherwise, false.
+ */
+ public static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
+ return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ }
+
+ /**
+ * Returns true if {@param procState} is considered foreground and as such will be allowed
+ * to access network when the device is in data saver mode. Otherwise, false.
+ */
+ public static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) {
+ return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
+ }
}
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 815d4807a39e..f0bea5b8e0ad 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -265,8 +265,8 @@ public class NetworkScoreManager {
* the {@link #ACTION_CHANGE_ACTIVE} broadcast, or using a custom configuration activity.
*
* @return true if the operation succeeded, or false if the new package is not a valid scorer.
- * @throws SecurityException if the caller does not hold the
- * {@link android.Manifest.permission#SCORE_NETWORKS} permission.
+ * @throws SecurityException if the caller is not a system process or does not hold the
+ * {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission
* @hide
*/
@SystemApi
diff --git a/core/java/android/os/BatteryManager.java b/core/java/android/os/BatteryManager.java
index 9ffe2fe7a709..734d89eb72af 100644
--- a/core/java/android/os/BatteryManager.java
+++ b/core/java/android/os/BatteryManager.java
@@ -211,7 +211,7 @@ public class BatteryManager {
/**
* Battery charge status, from a BATTERY_STATUS_* value.
*/
- public static final int BATTERY_PROPERTY_BATTERY_STATUS = 6;
+ public static final int BATTERY_PROPERTY_STATUS = 6;
private final IBatteryStats mBatteryStats;
private final IBatteryPropertiesRegistrar mBatteryPropertiesRegistrar;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index ff86ff3ff076..c4a5be7f1ea6 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1121,7 +1121,7 @@ public final class Settings {
public static final String ACTION_ZEN_MODE_SETTINGS = "android.settings.ZEN_MODE_SETTINGS";
/**
- * Activity Action: Show Zen Mode priority configuration settings.
+ * Activity Action: Show Zen Mode (aka Do Not Disturb) priority configuration settings.
*/
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_ZEN_MODE_PRIORITY_SETTINGS
diff --git a/core/java/android/service/notification/ConditionProviderService.java b/core/java/android/service/notification/ConditionProviderService.java
index c8358a6c4677..3e992ec36426 100644
--- a/core/java/android/service/notification/ConditionProviderService.java
+++ b/core/java/android/service/notification/ConditionProviderService.java
@@ -127,7 +127,7 @@ public abstract class ConditionProviderService extends Service {
}
/**
- * Request that the provider be rebound, after a previous call to (@link requestUnbind).
+ * Request that the provider be rebound, after a previous call to (@link #requestUnbind).
*
* <p>This method will fail for providers that have not been granted the permission by the user.
*/
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 8a83b7aa8373..70e0461ce73f 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -148,7 +148,7 @@ public abstract class NotificationListenerService extends Service {
// Notification cancellation reasons
- /** Notification was canceled by the status bar reporting a click. */
+ /** Notification was canceled by the status bar reporting a notification click. */
public static final int REASON_DELEGATE_CLICK = 1;
/** Notification was canceled by the status bar reporting a user dismissal. */
public static final int REASON_DELEGATE_CANCEL = 2;
@@ -636,7 +636,7 @@ public abstract class NotificationListenerService extends Service {
* <p>The service should wait for the {@link #onListenerConnected()} event
* before performing this operation.
*
- * @return An array of active notifications, sorted in natural order.
+ * @return An array of snoozed notifications, sorted in natural order.
*/
public final StatusBarNotification[] getSnoozedNotifications() {
try {
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java
index 85bccf746305..6a24aa454550 100644
--- a/core/java/android/service/notification/StatusBarNotification.java
+++ b/core/java/android/service/notification/StatusBarNotification.java
@@ -67,6 +67,9 @@ public class StatusBarNotification implements Parcelable {
this.groupKey = groupKey();
}
+ /**
+ * @deprecated Non-system apps should not need to create StatusBarNotifications.
+ */
@Deprecated
public StatusBarNotification(String pkg, String opPkg, int id, String tag, int uid,
int initialPid, int score, Notification notification, UserHandle user,
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index b718696b2202..0ac16c1fa023 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -95,6 +95,11 @@ public class SurfaceControl {
IBinder displayToken, int mode);
private static native void nativeDeferTransactionUntil(long nativeObject,
IBinder handle, long frame);
+ private static native void nativeDeferTransactionUntilSurface(long nativeObject,
+ long surfaceObject, long frame);
+ private static native void nativeReparentChildren(long nativeObject,
+ IBinder handle);
+ private static native void nativeSeverChildren(long nativeObject);
private static native void nativeSetOverrideScalingMode(long nativeObject,
int scalingMode);
private static native IBinder nativeGetHandle(long nativeObject);
@@ -421,6 +426,18 @@ public class SurfaceControl {
nativeDeferTransactionUntil(mNativeObject, handle, frame);
}
+ public void deferTransactionUntil(Surface barrier, long frame) {
+ nativeDeferTransactionUntilSurface(mNativeObject, barrier.mNativeObject, frame);
+ }
+
+ public void reparentChildren(IBinder newParentHandle) {
+ nativeReparentChildren(mNativeObject, newParentHandle);
+ }
+
+ public void detachChildren() {
+ nativeSeverChildren(mNativeObject);
+ }
+
public void setOverrideScalingMode(int scalingMode) {
checkNotReleased();
nativeSetOverrideScalingMode(mNativeObject, scalingMode);
diff --git a/core/java/android/view/SurfaceSession.java b/core/java/android/view/SurfaceSession.java
index 3cf5af484625..b5912bc1e1c8 100644
--- a/core/java/android/view/SurfaceSession.java
+++ b/core/java/android/view/SurfaceSession.java
@@ -27,6 +27,7 @@ public final class SurfaceSession {
private long mNativeClient; // SurfaceComposerClient*
private static native long nativeCreate();
+ private static native long nativeCreateScoped(long surfacePtr);
private static native void nativeDestroy(long ptr);
private static native void nativeKill(long ptr);
@@ -35,6 +36,10 @@ public final class SurfaceSession {
mNativeClient = nativeCreate();
}
+ public SurfaceSession(Surface root) {
+ mNativeClient = nativeCreateScoped(root.mNativeObject);
+ }
+
/* no user serviceable parts here ... */
@Override
protected void finalize() throws Throwable {
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index d2577d48c3d1..64306338311b 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -16,6 +16,10 @@
package android.view;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_MEDIA_OVERLAY_SUBLAYER;
+import static android.view.WindowManagerPolicy.APPLICATION_PANEL_SUBLAYER;
+
import android.content.Context;
import android.content.res.CompatibilityInfo.Translator;
import android.content.res.Configuration;
@@ -26,16 +30,12 @@ import android.graphics.Rect;
import android.graphics.Region;
import android.os.Handler;
import android.os.Message;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
-import com.android.internal.view.BaseIWindow;
import com.android.internal.view.SurfaceCallbackHelper;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.concurrent.locks.ReentrantLock;
@@ -92,8 +92,8 @@ import java.util.concurrent.locks.ReentrantLock;
* positioned asynchronously.</p>
*/
public class SurfaceView extends View {
- static private final String TAG = "SurfaceView";
- static private final boolean DEBUG = false;
+ private static final String TAG = "SurfaceView";
+ private static final boolean DEBUG = false;
final ArrayList<SurfaceHolder.Callback> mCallbacks
= new ArrayList<SurfaceHolder.Callback>();
@@ -102,28 +102,23 @@ public class SurfaceView extends View {
final ReentrantLock mSurfaceLock = new ReentrantLock();
final Surface mSurface = new Surface(); // Current surface in use
- final Surface mNewSurface = new Surface(); // New surface we are switching to
boolean mDrawingStopped = true;
+ // We use this to track if the application has produced a frame
+ // in to the Surface. Up until that point, we should be careful not to punch
+ // holes.
+ boolean mDrawFinished = false;
+
+ final Rect mScreenRect = new Rect();
+ SurfaceSession mSurfaceSession;
- final WindowManager.LayoutParams mLayout
- = new WindowManager.LayoutParams();
- IWindowSession mSession;
- MyWindow mWindow;
- final Rect mVisibleInsets = new Rect();
- final Rect mWinFrame = new Rect();
- final Rect mOverscanInsets = new Rect();
- final Rect mContentInsets = new Rect();
- final Rect mStableInsets = new Rect();
- final Rect mOutsets = new Rect();
- final Rect mBackdropFrame = new Rect();
+ SurfaceControl mSurfaceControl;
final Rect mTmpRect = new Rect();
final Configuration mConfiguration = new Configuration();
static final int KEEP_SCREEN_ON_MSG = 1;
- static final int GET_NEW_SURFACE_MSG = 2;
- static final int UPDATE_WINDOW_MSG = 3;
+ static final int DRAW_FINISHED_MSG = 2;
- int mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ int mSubLayer = APPLICATION_MEDIA_SUBLAYER;
boolean mIsCreating = false;
private volatile boolean mRtHandlingPositionUpdates = false;
@@ -135,11 +130,9 @@ public class SurfaceView extends View {
case KEEP_SCREEN_ON_MSG: {
setKeepScreenOn(msg.arg1 != 0);
} break;
- case GET_NEW_SURFACE_MSG: {
- handleGetNewSurface();
- } break;
- case UPDATE_WINDOW_MSG: {
- updateWindow();
+ case DRAW_FINISHED_MSG: {
+ mDrawFinished = true;
+ invalidate();
} break;
}
}
@@ -149,7 +142,7 @@ public class SurfaceView extends View {
= new ViewTreeObserver.OnScrollChangedListener() {
@Override
public void onScrollChanged() {
- updateWindow();
+ updateSurface();
}
};
@@ -159,13 +152,14 @@ public class SurfaceView extends View {
public boolean onPreDraw() {
// reposition ourselves where the surface is
mHaveFrame = getWidth() > 0 && getHeight() > 0;
- updateWindow();
+ updateSurface();
return true;
}
};
boolean mRequestedVisible = false;
boolean mWindowVisibility = false;
+ boolean mLastWindowVisibility = false;
boolean mViewVisibility = false;
int mRequestedWidth = -1;
int mRequestedHeight = -1;
@@ -181,19 +175,17 @@ public class SurfaceView extends View {
boolean mVisible = false;
int mWindowSpaceLeft = -1;
int mWindowSpaceTop = -1;
- int mWindowSpaceWidth = -1;
- int mWindowSpaceHeight = -1;
+ int mSurfaceWidth = -1;
+ int mSurfaceHeight = -1;
int mFormat = -1;
final Rect mSurfaceFrame = new Rect();
int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
- boolean mUpdateWindowNeeded;
- boolean mReportDrawNeeded;
private Translator mTranslator;
- private int mWindowInsetLeft;
- private int mWindowInsetTop;
private boolean mGlobalListenersAdded;
+ private int mSurfaceFlags = SurfaceControl.HIDDEN;
+
public SurfaceView(Context context) {
this(context, null);
}
@@ -227,11 +219,8 @@ public class SurfaceView extends View {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mParent.requestTransparentRegion(this);
- mSession = getWindowSession();
- mLayout.token = getWindowToken();
- mLayout.setTitle("SurfaceView - " + getViewRootImpl().getTitle());
- mLayout.packageName = mContext.getOpPackageName();
mViewVisibility = getVisibility() == VISIBLE;
+ mRequestedVisible = mViewVisibility && mWindowVisibility;
if (!mGlobalListenersAdded) {
ViewTreeObserver observer = getViewTreeObserver();
@@ -246,7 +235,7 @@ public class SurfaceView extends View {
super.onWindowVisibilityChanged(visibility);
mWindowVisibility = visibility == VISIBLE;
mRequestedVisible = mWindowVisibility && mViewVisibility;
- updateWindow();
+ updateSurface();
}
@Override
@@ -264,7 +253,7 @@ public class SurfaceView extends View {
requestLayout();
}
mRequestedVisible = newRequestedVisible;
- updateWindow();
+ updateSurface();
}
@Override
@@ -277,19 +266,14 @@ public class SurfaceView extends View {
}
mRequestedVisible = false;
- updateWindow();
- mHaveFrame = false;
- if (mWindow != null) {
- try {
- mSession.remove(mWindow);
- } catch (RemoteException ex) {
- // Not much we can do here...
- }
- mWindow = null;
+
+ updateSurface();
+ if (mSurfaceControl != null) {
+ mSurfaceControl.destroy();
}
- mSession = null;
- mLayout.token = null;
+ mSurfaceControl = null;
+ mHaveFrame = false;
super.onDetachedFromWindow();
}
@@ -308,13 +292,13 @@ public class SurfaceView extends View {
@Override
protected boolean setFrame(int left, int top, int right, int bottom) {
boolean result = super.setFrame(left, top, right, bottom);
- updateWindow();
+ updateSurface();
return result;
}
@Override
public boolean gatherTransparentRegion(Region region) {
- if (mWindowType == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+ if (isAboveParent()) {
return super.gatherTransparentRegion(region);
}
@@ -341,7 +325,7 @@ public class SurfaceView extends View {
@Override
public void draw(Canvas canvas) {
- if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
+ if (mDrawFinished && !isAboveParent()) {
// draw() is not called when SKIP_DRAW is set
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == 0) {
// punch a whole in the view-hierarchy below us
@@ -353,8 +337,8 @@ public class SurfaceView extends View {
@Override
protected void dispatchDraw(Canvas canvas) {
- if (mWindowType != WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
- // if SKIP_DRAW is cleared, draw() has already punched a hole
+ if (mDrawFinished && !isAboveParent()) {
+ // draw() is not called when SKIP_DRAW is set
if ((mPrivateFlags & PFLAG_SKIP_DRAW) == PFLAG_SKIP_DRAW) {
// punch a whole in the view-hierarchy below us
canvas.drawColor(0, PorterDuff.Mode.CLEAR);
@@ -375,9 +359,8 @@ public class SurfaceView extends View {
* <p>Calling this overrides any previous call to {@link #setZOrderOnTop}.
*/
public void setZOrderMediaOverlay(boolean isMediaOverlay) {
- mWindowType = isMediaOverlay
- ? WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY
- : WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
+ mSubLayer = isMediaOverlay
+ ? APPLICATION_MEDIA_OVERLAY_SUBLAYER : APPLICATION_MEDIA_SUBLAYER;
}
/**
@@ -395,12 +378,9 @@ public class SurfaceView extends View {
*/
public void setZOrderOnTop(boolean onTop) {
if (onTop) {
- mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_PANEL;
- // ensures the surface is placed below the IME
- mLayout.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mSubLayer = APPLICATION_PANEL_SUBLAYER;
} else {
- mWindowType = WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA;
- mLayout.flags &= ~WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+ mSubLayer = APPLICATION_MEDIA_SUBLAYER;
}
}
@@ -418,31 +398,23 @@ public class SurfaceView extends View {
*/
public void setSecure(boolean isSecure) {
if (isSecure) {
- mLayout.flags |= WindowManager.LayoutParams.FLAG_SECURE;
+ mSurfaceFlags |= SurfaceControl.SECURE;
} else {
- mLayout.flags &= ~WindowManager.LayoutParams.FLAG_SECURE;
+ mSurfaceFlags &= ~SurfaceControl.SECURE;
}
}
- /**
- * Hack to allow special layering of windows. The type is one of the
- * types in WindowManager.LayoutParams. This is a hack so:
- * @hide
- */
- public void setWindowType(int type) {
- mWindowType = type;
- }
-
/** @hide */
- protected void updateWindow() {
+ protected void updateSurface() {
if (!mHaveFrame) {
return;
}
ViewRootImpl viewRoot = getViewRootImpl();
- if (viewRoot != null) {
- mTranslator = viewRoot.mTranslator;
+ if (viewRoot == null || viewRoot.mSurface == null || !viewRoot.mSurface.isValid()) {
+ return;
}
+ mTranslator = viewRoot.mTranslator;
if (mTranslator != null) {
mSurface.setCompatibilityTranslator(mTranslator);
}
@@ -452,17 +424,15 @@ public class SurfaceView extends View {
int myHeight = mRequestedHeight;
if (myHeight <= 0) myHeight = getHeight();
- final boolean creating = mWindow == null;
final boolean formatChanged = mFormat != mRequestedFormat;
- final boolean sizeChanged = mWindowSpaceWidth != myWidth || mWindowSpaceHeight != myHeight;
+ final boolean creating = (mSurfaceControl == null || formatChanged)
+ && mRequestedVisible;
+ final boolean sizeChanged = mSurfaceWidth != myWidth || mSurfaceHeight != myHeight;
final boolean visibleChanged = mVisible != mRequestedVisible;
- final boolean layoutSizeChanged = getWidth() != mLayout.width
- || getHeight() != mLayout.height;
-
+ final boolean windowVisibleChanged = mWindowVisibility != mLastWindowVisibility;
boolean redrawNeeded = false;
- if (creating || formatChanged || sizeChanged || visibleChanged
- || mUpdateWindowNeeded || mReportDrawNeeded) {
+ if (creating || formatChanged || sizeChanged || visibleChanged || windowVisibleChanged) {
getLocationInWindow(mLocation);
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
@@ -476,93 +446,74 @@ public class SurfaceView extends View {
final boolean visible = mVisible = mRequestedVisible;
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
- mWindowSpaceWidth = myWidth;
- mWindowSpaceHeight = myHeight;
+ mSurfaceWidth = myWidth;
+ mSurfaceHeight = myHeight;
mFormat = mRequestedFormat;
+ mLastWindowVisibility = mWindowVisibility;
- // Scaling/Translate window's layout here because mLayout is not used elsewhere.
-
- // Places the window relative
- mLayout.x = mWindowSpaceLeft;
- mLayout.y = mWindowSpaceTop;
- mLayout.width = getWidth();
- mLayout.height = getHeight();
+ mScreenRect.left = mWindowSpaceLeft;
+ mScreenRect.top = mWindowSpaceTop;
+ mScreenRect.right = mWindowSpaceLeft + getWidth();
+ mScreenRect.bottom = mWindowSpaceTop + getHeight();
if (mTranslator != null) {
- mTranslator.translateLayoutParamsInAppWindowToScreen(mLayout);
+ mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
- mLayout.format = mRequestedFormat;
- mLayout.flags |=WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
- | WindowManager.LayoutParams.FLAG_SCALED
- | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
- ;
- if (!creating && !sizeChanged) {
- mLayout.privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
- } else {
- mLayout.privateFlags &=
- ~WindowManager.LayoutParams.PRIVATE_FLAG_PRESERVE_GEOMETRY;
+ if (creating) {
+ mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
+ mSurfaceControl = new SurfaceControl(mSurfaceSession,
+ "SurfaceView - " + viewRoot.getTitle().toString(),
+ mSurfaceWidth, mSurfaceHeight, mFormat,
+ mSurfaceFlags);
}
- if (!getContext().getResources().getCompatibilityInfo().supportsScreen()) {
- mLayout.privateFlags |=
- WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
- }
- mLayout.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION
- | WindowManager.LayoutParams.PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME;
-
- if (mWindow == null) {
- Display display = getDisplay();
- mWindow = new MyWindow(this);
- mLayout.type = mWindowType;
- mLayout.gravity = Gravity.START|Gravity.TOP;
- mSession.addToDisplayWithoutInputChannel(mWindow, mWindow.mSeq, mLayout,
- mVisible ? VISIBLE : GONE, display.getDisplayId(), mContentInsets,
- mStableInsets);
- }
-
- boolean realSizeChanged;
- boolean reportDrawNeeded;
-
- int relayoutResult;
+ boolean realSizeChanged = false;
mSurfaceLock.lock();
try {
- mUpdateWindowNeeded = false;
- reportDrawNeeded = mReportDrawNeeded;
- mReportDrawNeeded = false;
mDrawingStopped = !visible;
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
+ "Cur surface: " + mSurface);
- relayoutResult = mSession.relayout(
- mWindow, mWindow.mSeq, mLayout, mWindowSpaceWidth, mWindowSpaceHeight,
- visible ? VISIBLE : GONE,
- WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY,
- mWinFrame, mOverscanInsets, mContentInsets,
- mVisibleInsets, mStableInsets, mOutsets, mBackdropFrame,
- mConfiguration, mNewSurface);
- if ((relayoutResult & WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME) != 0) {
- reportDrawNeeded = true;
+ SurfaceControl.openTransaction();
+ try {
+ mSurfaceControl.setLayer(mSubLayer);
+ if (mViewVisibility) {
+ mSurfaceControl.show();
+ } else {
+ mSurfaceControl.hide();
+ }
+
+ // While creating the surface, we will set it's initial
+ // geometry. Outside of that though, we should generally
+ // leave it to the RenderThread.
+ if (creating || !mRtHandlingPositionUpdates) {
+ mSurfaceControl.setPosition(mScreenRect.left, mScreenRect.top);
+ mSurfaceControl.setMatrix(mScreenRect.width() / (float) mSurfaceWidth,
+ 0.0f, 0.0f,
+ mScreenRect.height() / (float) mSurfaceHeight);
+ }
+ if (sizeChanged) {
+ mSurfaceControl.setSize(mSurfaceWidth, mSurfaceHeight);
+ }
+ } finally {
+ SurfaceControl.closeTransaction();
}
- if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " "
- + "New surface: " + mNewSurface
- + ", vis=" + visible + ", frame=" + mWinFrame);
+ if (sizeChanged || creating) {
+ redrawNeeded = true;
+ }
mSurfaceFrame.left = 0;
mSurfaceFrame.top = 0;
if (mTranslator == null) {
- mSurfaceFrame.right = mWinFrame.width();
- mSurfaceFrame.bottom = mWinFrame.height();
+ mSurfaceFrame.right = mSurfaceWidth;
+ mSurfaceFrame.bottom = mSurfaceHeight;
} else {
float appInvertedScale = mTranslator.applicationInvertedScale;
- mSurfaceFrame.right = (int) (mWinFrame.width() * appInvertedScale + 0.5f);
- mSurfaceFrame.bottom = (int) (mWinFrame.height() * appInvertedScale + 0.5f);
+ mSurfaceFrame.right = (int) (mSurfaceWidth * appInvertedScale + 0.5f);
+ mSurfaceFrame.bottom = (int) (mSurfaceHeight * appInvertedScale + 0.5f);
}
final int surfaceWidth = mSurfaceFrame.right;
@@ -576,12 +527,11 @@ public class SurfaceView extends View {
}
try {
- redrawNeeded |= creating | reportDrawNeeded;
+ redrawNeeded |= visible && !mDrawFinished;
SurfaceHolder.Callback callbacks[] = null;
- final boolean surfaceChanged = (relayoutResult
- & WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED) != 0;
+ final boolean surfaceChanged = creating;
if (mSurfaceCreated && (surfaceChanged || (!visible && visibleChanged))) {
mSurfaceCreated = false;
if (mSurface.isValid()) {
@@ -608,7 +558,10 @@ public class SurfaceView extends View {
}
}
- mSurface.transferFrom(mNewSurface);
+ if (creating) {
+ mSurface.copyFrom(mSurfaceControl);
+ }
+
if (visible && mSurface.isValid()) {
if (!mSurfaceCreated && (surfaceChanged || visibleChanged)) {
mSurfaceCreated = true;
@@ -641,53 +594,57 @@ public class SurfaceView extends View {
callbacks = getSurfaceCallbacks();
}
SurfaceCallbackHelper sch =
- new SurfaceCallbackHelper(mSession, mWindow);
+ new SurfaceCallbackHelper(this::onDrawFinished);
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
}
}
} finally {
mIsCreating = false;
- mSession.performDeferredDestroy(mWindow);
+ if (mSurfaceControl != null && !mSurfaceCreated) {
+ mSurfaceControl.destroy();
+ mSurfaceControl = null;
+ }
}
- } catch (RemoteException ex) {
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
if (DEBUG) Log.v(
- TAG, "Layout: x=" + mLayout.x + " y=" + mLayout.y +
- " w=" + mLayout.width + " h=" + mLayout.height +
- ", frame=" + mSurfaceFrame);
+ TAG, "Layout: x=" + mScreenRect.left + " y=" + mScreenRect.top
+ + " w=" + mScreenRect.width() + " h=" + mScreenRect.height()
+ + ", frame=" + mSurfaceFrame);
} else {
// Calculate the window position in case RT loses the window
// and we need to fallback to a UI-thread driven position update
getLocationInWindow(mLocation);
final boolean positionChanged = mWindowSpaceLeft != mLocation[0]
|| mWindowSpaceTop != mLocation[1];
+ final boolean layoutSizeChanged = getWidth() != mScreenRect.width()
+ || getHeight() != mScreenRect.height();
if (positionChanged || layoutSizeChanged) { // Only the position has changed
mWindowSpaceLeft = mLocation[0];
mWindowSpaceTop = mLocation[1];
- // For our size changed check, we keep mLayout.width and mLayout.height
+ // For our size changed check, we keep mScreenRect.width() and mScreenRect.height()
// in view local space.
- mLocation[0] = mLayout.width = getWidth();
- mLocation[1] = mLayout.height = getHeight();
+ mLocation[0] = getWidth();
+ mLocation[1] = getHeight();
transformFromViewToWindowSpace(mLocation);
- mTmpRect.set(mWindowSpaceLeft, mWindowSpaceTop,
+ mScreenRect.set(mWindowSpaceLeft, mWindowSpaceTop,
mLocation[0], mLocation[1]);
if (mTranslator != null) {
- mTranslator.translateRectInAppWindowToScreen(mTmpRect);
+ mTranslator.translateRectInAppWindowToScreen(mScreenRect);
}
if (!isHardwareAccelerated() || !mRtHandlingPositionUpdates) {
try {
- if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition UI, " +
+ if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition UI, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
- mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom));
- mSession.repositionChild(mWindow, mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom, -1, mTmpRect);
- } catch (RemoteException ex) {
+ mScreenRect.left, mScreenRect.top,
+ mScreenRect.right, mScreenRect.bottom));
+ setParentSpaceRectangle(mScreenRect, -1);
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
}
@@ -695,18 +652,40 @@ public class SurfaceView extends View {
}
}
+ private void onDrawFinished() {
+ if (DEBUG) {
+ Log.i(TAG, System.identityHashCode(this) + " "
+ + "finishedDrawing");
+ }
+ mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
+ }
+
+ private void setParentSpaceRectangle(Rect position, long frameNumber) {
+ ViewRootImpl viewRoot = getViewRootImpl();
+
+ SurfaceControl.openTransaction();
+ try {
+ if (frameNumber > 0) {
+ mSurfaceControl.deferTransactionUntil(viewRoot.mSurface, frameNumber);
+ }
+ mSurfaceControl.setPosition(position.left, position.top);
+ mSurfaceControl.setMatrix(position.width() / (float) mSurfaceWidth,
+ 0.0f, 0.0f,
+ position.height() / (float) mSurfaceHeight);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+
private Rect mRTLastReportedPosition = new Rect();
/**
* Called by native by a Rendering Worker thread to update the window position
* @hide
*/
- public final void updateWindowPosition_renderWorker(long frameNumber,
+ public final void updateSurfacePosition_renderWorker(long frameNumber,
int left, int top, int right, int bottom) {
- IWindowSession session = mSession;
- MyWindow window = mWindow;
- if (session == null || window == null) {
- // Guess we got detached, that sucks
+ if (mSurfaceControl == null) {
return;
}
// TODO: This is teensy bit racey in that a brand new SurfaceView moving on
@@ -726,35 +705,29 @@ public class SurfaceView extends View {
}
try {
if (DEBUG) {
- Log.d(TAG, String.format("%d updateWindowPosition RenderWorker, frameNr = %d, " +
+ Log.d(TAG, String.format("%d updateSurfacePosition RenderWorker, frameNr = %d, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
frameNumber, left, top, right, bottom));
}
- // Just using mRTLastReportedPosition as a dummy rect here
- session.repositionChild(window, left, top, right, bottom,
- frameNumber,
- mRTLastReportedPosition);
- // Now overwrite mRTLastReportedPosition with our values
mRTLastReportedPosition.set(left, top, right, bottom);
- } catch (RemoteException ex) {
+ setParentSpaceRectangle(mRTLastReportedPosition, frameNumber);
+ // Now overwrite mRTLastReportedPosition with our values
+ } catch (Exception ex) {
Log.e(TAG, "Exception from repositionChild", ex);
}
}
/**
- * Called by native on RenderThread to notify that the window is no longer in the
+ * Called by native on RenderThread to notify that the view is no longer in the
* draw tree. UI thread is blocked at this point.
* @hide
*/
- public final void windowPositionLost_uiRtSync(long frameNumber) {
+ public final void surfacePositionLost_uiRtSync(long frameNumber) {
if (DEBUG) {
Log.d(TAG, String.format("%d windowPositionLost, frameNr = %d",
System.identityHashCode(this), frameNumber));
}
- IWindowSession session = mSession;
- MyWindow window = mWindow;
- if (session == null || window == null) {
- // We got detached prior to receiving this, abort
+ if (mSurfaceControl == null) {
return;
}
if (mRtHandlingPositionUpdates) {
@@ -763,19 +736,14 @@ public class SurfaceView extends View {
// safely access other member variables at this time.
// So do what the UI thread would have done if RT wasn't handling position
// updates.
- mTmpRect.set(mLayout.x, mLayout.y,
- mLayout.x + mLayout.width,
- mLayout.y + mLayout.height);
-
- if (!mTmpRect.isEmpty() && !mTmpRect.equals(mRTLastReportedPosition)) {
+ if (!mScreenRect.isEmpty() && !mScreenRect.equals(mRTLastReportedPosition)) {
try {
- if (DEBUG) Log.d(TAG, String.format("%d updateWindowPosition, " +
+ if (DEBUG) Log.d(TAG, String.format("%d updateSurfacePosition, " +
"postion = [%d, %d, %d, %d]", System.identityHashCode(this),
- mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom));
- session.repositionChild(window, mTmpRect.left, mTmpRect.top,
- mTmpRect.right, mTmpRect.bottom, frameNumber, mWinFrame);
- } catch (RemoteException ex) {
+ mScreenRect.left, mScreenRect.top,
+ mScreenRect.right, mScreenRect.bottom));
+ setParentSpaceRectangle(mScreenRect, frameNumber);
+ } catch (Exception ex) {
Log.e(TAG, "Exception from relayout", ex);
}
}
@@ -792,10 +760,6 @@ public class SurfaceView extends View {
return callbacks;
}
- void handleGetNewSurface() {
- updateWindow();
- }
-
/**
* Check to see if the surface has fixed size dimensions or if the surface's
* dimensions are dimensions are dependent on its current layout.
@@ -807,65 +771,8 @@ public class SurfaceView extends View {
return (mRequestedWidth != -1 || mRequestedHeight != -1);
}
- private static class MyWindow extends BaseIWindow {
- private final WeakReference<SurfaceView> mSurfaceView;
-
- public MyWindow(SurfaceView surfaceView) {
- mSurfaceView = new WeakReference<SurfaceView>(surfaceView);
- }
-
- @Override
- public void resized(Rect frame, Rect overscanInsets, Rect contentInsets,
- Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
- Configuration newConfig, Rect backDropRect, boolean forceLayout,
- boolean alwaysConsumeNavBar, int displayId) {
- SurfaceView surfaceView = mSurfaceView.get();
- if (surfaceView != null) {
- if (DEBUG) Log.v(TAG, surfaceView + " got resized: w=" + frame.width()
- + " h=" + frame.height() + ", cur w=" + mCurWidth + " h=" + mCurHeight);
- surfaceView.mSurfaceLock.lock();
- try {
- if (reportDraw) {
- surfaceView.mUpdateWindowNeeded = true;
- surfaceView.mReportDrawNeeded = true;
- surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
- } else if (surfaceView.mWinFrame.width() != frame.width()
- || surfaceView.mWinFrame.height() != frame.height()
- || forceLayout) {
- surfaceView.mUpdateWindowNeeded = true;
- surfaceView.mHandler.sendEmptyMessage(UPDATE_WINDOW_MSG);
- }
- } finally {
- surfaceView.mSurfaceLock.unlock();
- }
- }
- }
-
- @Override
- public void dispatchAppVisibility(boolean visible) {
- // The point of SurfaceView is to let the app control the surface.
- }
-
- @Override
- public void dispatchGetNewSurface() {
- SurfaceView surfaceView = mSurfaceView.get();
- if (surfaceView != null) {
- Message msg = surfaceView.mHandler.obtainMessage(GET_NEW_SURFACE_MSG);
- surfaceView.mHandler.sendMessage(msg);
- }
- }
-
- @Override
- public void windowFocusChanged(boolean hasFocus, boolean touchEnabled) {
- Log.w("SurfaceView", "Unexpected focus in surface: focus=" + hasFocus + ", touchEnabled=" + touchEnabled);
- }
-
- @Override
- public void executeCommand(String command, String parameters, ParcelFileDescriptor out) {
- }
-
- int mCurWidth = -1;
- int mCurHeight = -1;
+ private boolean isAboveParent() {
+ return mSubLayer >= 0;
}
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
@@ -913,15 +820,14 @@ public class SurfaceView extends View {
@Override
public void setFormat(int format) {
-
// for backward compatibility reason, OPAQUE always
// means 565 for SurfaceView
if (format == PixelFormat.OPAQUE)
format = PixelFormat.RGB_565;
mRequestedFormat = format;
- if (mWindow != null) {
- updateWindow();
+ if (mSurfaceControl != null) {
+ updateSurface();
}
}
@@ -982,10 +888,10 @@ public class SurfaceView extends View {
mSurfaceLock.lock();
if (DEBUG) Log.i(TAG, System.identityHashCode(this) + " " + "Locking canvas... stopped="
- + mDrawingStopped + ", win=" + mWindow);
+ + mDrawingStopped + ", surfaceControl=" + mSurfaceControl);
Canvas c = null;
- if (!mDrawingStopped && mWindow != null) {
+ if (!mDrawingStopped && mSurfaceControl != null) {
try {
if (hardware) {
c = mSurface.lockHardwareCanvas();
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 20d960fff661..f9863b0a6761 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2632,6 +2632,14 @@ public final class ViewRootImpl implements ViewParent,
}
}
+ private void onDrawFinished() {
+ try {
+ mWindowSession.finishDrawing(mWindow);
+ } catch (RemoteException e) {
+ // Have fun!
+ }
+ }
+
private void performDraw() {
if (mAttachInfo.mDisplayState == Display.STATE_OFF && !mReportNextDraw) {
return;
@@ -2682,7 +2690,7 @@ public final class ViewRootImpl implements ViewParent,
}
if (mSurfaceHolder != null && mSurface.isValid()) {
- SurfaceCallbackHelper sch = new SurfaceCallbackHelper(mWindowSession, mWindow);
+ SurfaceCallbackHelper sch = new SurfaceCallbackHelper(this::onDrawFinished);
SurfaceHolder.Callback callbacks[] = mSurfaceHolder.getCallbacks();
sch.dispatchSurfaceRedrawNeededAsync(mSurfaceHolder, callbacks);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index adc6f725f42e..493774038e4e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10335,7 +10335,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
Selection.setSelection((Spannable) text, start, end);
// Make sure selection mode is engaged.
if (mEditor != null) {
- mEditor.startSelectionActionModeAsync();
+ mEditor.startSelectionActionMode();
}
return true;
}
diff --git a/core/java/android/widget/TimePickerClockDelegate.java b/core/java/android/widget/TimePickerClockDelegate.java
index 3a0906393b97..94bd342c9b9b 100644
--- a/core/java/android/widget/TimePickerClockDelegate.java
+++ b/core/java/android/widget/TimePickerClockDelegate.java
@@ -813,8 +813,12 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
private final OnValueSelectedListener mOnValueSelectedListener = new OnValueSelectedListener() {
@Override
public void onValueSelected(int pickerType, int newValue, boolean autoAdvance) {
+ boolean valueChanged = false;
switch (pickerType) {
case RadialTimePickerView.HOURS:
+ if (getHour() != newValue) {
+ valueChanged = true;
+ }
final boolean isTransition = mAllowAutoAdvance && autoAdvance;
setHourInternal(newValue, FROM_RADIAL_PICKER, !isTransition);
if (isTransition) {
@@ -825,11 +829,14 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate {
}
break;
case RadialTimePickerView.MINUTES:
+ if (getMinute() != newValue) {
+ valueChanged = true;
+ }
setMinuteInternal(newValue, FROM_RADIAL_PICKER);
break;
}
- if (mOnTimeChangedListener != null) {
+ if (mOnTimeChangedListener != null && valueChanged) {
mOnTimeChangedListener.onTimeChanged(mDelegator, getHour(), getMinute());
}
}
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
new file mode 100644
index 000000000000..c840f26a0d53
--- /dev/null
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.internal.notification;
+
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.provider.Settings;
+
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+// Manages the NotificationChannels used by the frameworks itself.
+public class SystemNotificationChannels {
+ public static String VIRTUAL_KEYBOARD = "VIRTUAL_KEYBOARD";
+ public static String PHYSICAL_KEYBOARD = "PHYSICAL_KEYBOARD";
+ public static String SECURITY = "SECURITY";
+ public static String CAR_MODE = "CAR_MODE";
+ public static String ACCOUNT = "ACCOUNT";
+ public static String DEVELOPER = "DEVELOPER";
+ public static String UPDATES = "UPDATES";
+ public static String NETWORK_STATUS = "NETWORK_STATUS";
+ public static String NETWORK_ALERTS = "NETWORK_ALERTS";
+ public static String VPN = "VPN";
+ public static String DEVICE_ADMIN = "DEVICE_ADMIN";
+ public static String ALERTS = "ALERTS";
+ public static String RETAIL_MODE = "RETAIL_MODE";
+ public static String USB = "USB";
+
+ public static void createAll(Context context) {
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+ List<NotificationChannel> channelsList = new ArrayList<NotificationChannel>();
+ channelsList.add(new NotificationChannel(
+ VIRTUAL_KEYBOARD,
+ context.getString(R.string.notification_channel_virtual_keyboard),
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel physicalKeyboardChannel = new NotificationChannel(
+ PHYSICAL_KEYBOARD,
+ context.getString(R.string.notification_channel_physical_keyboard),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ physicalKeyboardChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(physicalKeyboardChannel);
+
+ channelsList.add(new NotificationChannel(
+ SECURITY,
+ context.getString(R.string.notification_channel_security),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ CAR_MODE,
+ context.getString(R.string.notification_channel_car_mode),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ DEVELOPER,
+ context.getString(R.string.notification_channel_developer),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ UPDATES,
+ context.getString(R.string.notification_channel_updates),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ NETWORK_STATUS,
+ context.getString(R.string.notification_channel_network_status),
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel networkAlertsChannel = new NotificationChannel(
+ NETWORK_ALERTS,
+ context.getString(R.string.notification_channel_network_alerts),
+ NotificationManager.IMPORTANCE_HIGH);
+ networkAlertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(networkAlertsChannel);
+
+ channelsList.add(new NotificationChannel(
+ VPN,
+ context.getString(R.string.notification_channel_vpn),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ DEVICE_ADMIN,
+ context.getString(R.string.notification_channel_device_admin),
+ NotificationManager.IMPORTANCE_LOW));
+
+ final NotificationChannel alertsChannel = new NotificationChannel(
+ ALERTS,
+ context.getString(R.string.notification_channel_alerts),
+ NotificationManager.IMPORTANCE_DEFAULT);
+ alertsChannel.setSound(Settings.System.DEFAULT_NOTIFICATION_URI,
+ Notification.AUDIO_ATTRIBUTES_DEFAULT);
+ channelsList.add(alertsChannel);
+
+ channelsList.add(new NotificationChannel(
+ RETAIL_MODE,
+ context.getString(R.string.notification_channel_retail_mode),
+ NotificationManager.IMPORTANCE_LOW));
+
+ channelsList.add(new NotificationChannel(
+ USB,
+ context.getString(R.string.notification_channel_usb),
+ NotificationManager.IMPORTANCE_MIN));
+
+ nm.createNotificationChannels(channelsList);
+ createAccountChannelForPackage(context.getPackageName(), context);
+ }
+
+ public static void createAccountChannelForPackage(String pkg, Context context) {
+ final NotificationManager nm = context.getSystemService(NotificationManager.class);
+ nm.createNotificationChannelsForPackage(pkg, Arrays.asList(new NotificationChannel(
+ ACCOUNT,
+ context.getString(R.string.notification_channel_account),
+ NotificationManager.IMPORTANCE_LOW)));
+ }
+
+ private SystemNotificationChannels() {}
+}
diff --git a/core/java/com/android/internal/util/ParcelableString.java b/core/java/com/android/internal/util/ParcelableString.java
deleted file mode 100644
index 6bd856f5521d..000000000000
--- a/core/java/com/android/internal/util/ParcelableString.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Helper class to adapt a simple String to cases where a Parcelable is expected.
- * @hide
- */
-public class ParcelableString implements Parcelable {
- public String string;
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public void writeToParcel(Parcel out, int flags) {
- out.writeString(string);
- }
-
- public static final Parcelable.Creator<ParcelableString> CREATOR =
- new Parcelable.Creator<ParcelableString>() {
- @Override
- public ParcelableString createFromParcel(Parcel in) {
- ParcelableString ret = new ParcelableString();
- ret.string = in.readString();
- return ret;
- }
- @Override
- public ParcelableString[] newArray(int size) {
- return new ParcelableString[size];
- }
- };
-} \ No newline at end of file
diff --git a/core/java/com/android/internal/view/SurfaceCallbackHelper.java b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
index 5b6a82cf1c43..507b673ec279 100644
--- a/core/java/com/android/internal/view/SurfaceCallbackHelper.java
+++ b/core/java/com/android/internal/view/SurfaceCallbackHelper.java
@@ -17,14 +17,11 @@
package com.android.internal.view;
import android.os.RemoteException;
-import android.view.IWindow;
-import android.view.IWindowSession;
import android.view.Surface;
import android.view.SurfaceHolder;
public class SurfaceCallbackHelper {
- IWindowSession mSession;
- IWindow.Stub mWindow;
+ Runnable mRunnable;
int mFinishDrawingCollected = 0;
int mFinishDrawingExpected = 0;
@@ -37,26 +34,18 @@ public class SurfaceCallbackHelper {
if (mFinishDrawingCollected < mFinishDrawingExpected) {
return;
}
- try {
- mSession.finishDrawing(mWindow);
- } catch (RemoteException e) {
- }
+ mRunnable.run();
}
}
};
- public SurfaceCallbackHelper(IWindowSession session,
- IWindow.Stub window) {
- mSession = session;
- mWindow = window;
+ public SurfaceCallbackHelper(Runnable callbacksCollected) {
+ mRunnable = callbacksCollected;
}
public void dispatchSurfaceRedrawNeededAsync(SurfaceHolder holder, SurfaceHolder.Callback callbacks[]) {
if (callbacks == null || callbacks.length == 0) {
- try {
- mSession.finishDrawing(mWindow);
- } catch (RemoteException e) {
- }
+ mRunnable.run();
return;
}
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 69e974c672d0..1de0af6f31df 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -388,14 +388,22 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey
final boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
mLastPosition = nextMenuPosition;
- final int[] tempLocation = new int[2];
-
- // This popup menu will be positioned relative to the top-left edge
- // of the view representing its parent menu.
- parentView.getLocationInWindow(tempLocation);
- final int parentOffsetLeft = parentInfo.window.getHorizontalOffset() + tempLocation[0];
- final int parentOffsetTop = parentInfo.window.getVerticalOffset() + tempLocation[1];
-
+ // A popup anchored to mAnchorView with (0,0) offset would be shown at this position.
+ final int[] offsetOrigin = new int[2];
+ mAnchorView.getLocationOnScreen(offsetOrigin);
+ offsetOrigin[1] += mAnchorView.getHeight();
+
+ final int[] parentViewScreenLocation = new int[2];
+ parentView.getLocationOnScreen(parentViewScreenLocation);
+
+ // Translate the parent view location into the offset coordinate space.
+ // If used as horizontal/vertical offsets, these values would position the submenu
+ // at the exact same position as the parent item.
+ final int parentOffsetLeft = parentViewScreenLocation[0] - offsetOrigin[0];
+ final int parentOffsetTop = parentViewScreenLocation[1] - offsetOrigin[1];
+
+ // Adjust the horizontal offset to display the submenu to the right or to the left
+ // of the parent item.
// By now, mDropDownGravity is the resolved absolute gravity, so
// this should work in both LTR and RTL.
final int x;
@@ -412,11 +420,10 @@ final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKey
x = parentOffsetLeft - menuWidth;
}
}
-
popupWindow.setHorizontalOffset(x);
- final int y = parentOffsetTop;
- popupWindow.setVerticalOffset(y);
+ // Use the same vertical offset as the parent item.
+ popupWindow.setVerticalOffset(parentOffsetTop);
} else {
if (mHasXOffset) {
popupWindow.setHorizontalOffset(mXOffset);
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 3ca455dc24cf..c348cc581c81 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -643,7 +643,7 @@ static jobject Bitmap_copy(JNIEnv* env, jobject, jlong srcHandle,
if (!bitmap.get()) {
return NULL;
}
- return createBitmap(env, bitmap.release(), kBitmapCreateFlag_None);
+ return createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(isMutable));
}
SkColorType dstCT = GraphicsJNI::legacyBitmapConfigToColorType(dstConfigHandle);
@@ -1306,7 +1306,7 @@ static jobject Bitmap_copyPreserveInternalConfig(JNIEnv* env, jobject, jlong bit
doThrowRE(env, "Could not copy a hardware bitmap.");
return NULL;
}
- return createBitmap(env, allocator.getStorageObjAndReset(), kBitmapCreateFlag_None);
+ return createBitmap(env, allocator.getStorageObjAndReset(), getPremulBitmapCreateFlags(false));
}
static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphicBuffer) {
@@ -1316,7 +1316,7 @@ static jobject Bitmap_createHardwareBitmap(JNIEnv* env, jobject, jobject graphic
ALOGW("failed to create hardware bitmap from graphic buffer");
return NULL;
}
- return bitmap::createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_None);
+ return bitmap::createBitmap(env, bitmap.release(), getPremulBitmapCreateFlags(false));
}
static jobject Bitmap_createGraphicBufferHandle(JNIEnv* env, jobject, jlong bitmapPtr) {
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index c7998a169225..1c6ead0f1086 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -111,11 +111,12 @@ void android_view_InputChannel_setDisposeCallback(JNIEnv* env, jobject inputChan
}
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
- NativeInputChannel* nativeInputChannel) {
+ std::unique_ptr<NativeInputChannel> nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
- android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
+ android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
+ nativeInputChannel.release());
}
return inputChannelObj;
}
@@ -143,13 +144,13 @@ static jobjectArray android_view_InputChannel_nativeOpenInputChannelPair(JNIEnv*
}
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(serverChannel));
+ std::make_unique<NativeInputChannel>(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(clientChannel));
+ std::make_unique<NativeInputChannel>(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index f221392f16bd..edcbb3f783c3 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -627,9 +627,9 @@ static const JNINativeMethod gMethods[] = {
int register_android_view_RenderNode(JNIEnv* env) {
jclass clazz = FindClassOrDie(env, "android/view/SurfaceView");
gSurfaceViewPositionUpdateMethod = GetMethodIDOrDie(env, clazz,
- "updateWindowPosition_renderWorker", "(JIIII)V");
+ "updateSurfacePosition_renderWorker", "(JIIII)V");
gSurfaceViewPositionLostMethod = GetMethodIDOrDie(env, clazz,
- "windowPositionLost_uiRtSync", "(J)V");
+ "surfacePositionLost_uiRtSync", "(J)V");
return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index a81901df9a1b..be86f5c6b8ab 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -693,7 +693,6 @@ static jboolean nativeGetAnimationFrameStats(JNIEnv* env, jclass clazz, jobject
return JNI_TRUE;
}
-
static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeObject,
jobject handleObject, jlong frameNumber) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -702,6 +701,27 @@ static void nativeDeferTransactionUntil(JNIEnv* env, jclass clazz, jlong nativeO
ctrl->deferTransactionUntil(handle, frameNumber);
}
+static void nativeDeferTransactionUntilSurface(JNIEnv* env, jclass clazz, jlong nativeObject,
+ jobject surfaceObject, jlong frameNumber) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ sp<Surface> barrier = reinterpret_cast<Surface *>(surfaceObject);
+
+ ctrl->deferTransactionUntil(barrier, frameNumber);
+}
+
+static void nativeReparentChildren(JNIEnv* env, jclass clazz, jlong nativeObject,
+ jobject newParentObject) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ sp<IBinder> handle = ibinderForJavaObject(env, newParentObject);
+
+ ctrl->reparentChildren(handle);
+}
+
+static void nativeSeverChildren(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ ctrl->detachChildren();
+}
+
static void nativeSetOverrideScalingMode(JNIEnv* env, jclass clazz, jlong nativeObject,
jint scalingMode) {
auto ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
@@ -824,6 +844,12 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetDisplayPowerMode },
{"nativeDeferTransactionUntil", "(JLandroid/os/IBinder;J)V",
(void*)nativeDeferTransactionUntil },
+ {"nativeDeferTransactionUntilSurface", "(JJJ)V",
+ (void*)nativeDeferTransactionUntilSurface },
+ {"nativeReparentChildren", "(JLandroid/os/IBinder;)V",
+ (void*)nativeReparentChildren } ,
+ {"nativeSeverChildren", "(J)V",
+ (void*)nativeSeverChildren } ,
{"nativeSetOverrideScalingMode", "(JI)V",
(void*)nativeSetOverrideScalingMode },
{"nativeGetHandle", "(J)Landroid/os/IBinder;",
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index dad6958560c0..508d89795569 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -24,6 +24,7 @@
#include <utils/RefBase.h>
#include <gui/SurfaceComposerClient.h>
+#include <gui/Surface.h>
namespace android {
@@ -45,6 +46,13 @@ static jlong nativeCreate(JNIEnv* env, jclass clazz) {
return reinterpret_cast<jlong>(client);
}
+static jlong nativeCreateScoped(JNIEnv* env, jclass clazz, jlong surfaceObject) {
+ Surface *parent = reinterpret_cast<Surface*>(surfaceObject);
+ SurfaceComposerClient* client = new SurfaceComposerClient(parent->getIGraphicBufferProducer());
+ client->incStrong((void*)nativeCreate);
+ return reinterpret_cast<jlong>(client);
+}
+
static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
client->decStrong((void*)nativeCreate);
@@ -55,11 +63,12 @@ static void nativeKill(JNIEnv* env, jclass clazz, jlong ptr) {
client->dispose();
}
-
static const JNINativeMethod gMethods[] = {
/* name, signature, funcPtr */
{ "nativeCreate", "()J",
(void*)nativeCreate },
+ { "nativeCreateScoped", "(J)J",
+ (void*)nativeCreateScoped },
{ "nativeDestroy", "(J)V",
(void*)nativeDestroy },
{ "nativeKill", "(J)V",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 054fad2f0bca..aea7a5d9beec 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -522,6 +522,8 @@
<protected-broadcast android:name="android.app.action.APPLICATION_DELEGATION_SCOPES_CHANGED" />
<protected-broadcast android:name="com.android.server.wm.ACTION_REVOKE_SYSTEM_ALERT_WINDOW_PERMISSION" />
+ <protected-broadcast android:name="android.content.pm.action.SESSION_COMMITTED" />
+
<!-- ====================================================================== -->
<!-- RUNTIME PERMISSIONS -->
<!-- ====================================================================== -->
@@ -895,6 +897,17 @@
android:description="@string/permdesc_processOutgoingCalls"
android:protectionLevel="dangerous" />
+
+ <!-- Allows the app to answer an incoming phone call.
+ <p>Protection level: dangerous
+ -->
+ <permission android:name="android.permission.ANSWER_PHONE_CALLS"
+ android:permissionGroup="android.permission-group.PHONE"
+ android:label="@string/permlab_answerPhoneCalls"
+ android:description="@string/permdesc_answerPhoneCalls"
+ android:protectionLevel="dangerous" />
+
+
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
<!-- ====================================================================== -->
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index be7760398062..e8169f853121 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -3148,19 +3148,19 @@
If both layout_marginHorizontal and any of layout_marginLeft,
layout_marginRight, layout_marginStart, and layout_marginEnd are
also specified, the layout_marginHorizontal value will take precedence over the
- edge-specific values. Also, layout_margin will always take precendent over
+ edge-specific values. Also, layout_margin will always take precedence over
any of these values, including layout_marginHorizontal.
This space is outside this view's bounds.
Margin values should be positive.-->
<attr name="layout_marginHorizontal" format="dimension" />
- <!-- Specifies extra space on the tyop and bottom sides of this view.
+ <!-- Specifies extra space on the top and bottom sides of this view.
Specifying layout_marginVertical is equivalent to specifying
layout_marginTop and layout_marginBottom with that same value.
If both layout_marginVertical and either/both layout_marginTop and
layout_marginBottom are also specified, the layout_marginVertical value
will take precedence over the edge-specific values.
- Also, layout_margin will always take precendent over
- any of these values, including layout_marginHorizontal.
+ Also, layout_margin will always take precedence over
+ any of these values, including layout_marginVertical.
This space is outside this view's bounds.
Margin values should be positive.-->
<attr name="layout_marginVertical" format="dimension" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b0c532ca72a9..ea0666413f88 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -587,6 +587,48 @@
<!-- Text shown in place of notification contents when the notification is hidden by policy on a secure lockscreen -->
<string name="notification_hidden_by_policy_text">Contents hidden by policy</string>
+ <!-- Text shown when viewing channel settings for notifications related to the virtual keyboard -->
+ <string name="notification_channel_virtual_keyboard">Virtual keyboard</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to the hardware keyboard -->
+ <string name="notification_channel_physical_keyboard">Physical keyboard</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to security -->
+ <string name="notification_channel_security">Security</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to car mode -->
+ <string name="notification_channel_car_mode">Car mode</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to account status -->
+ <string name="notification_channel_account">Account status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to developers -->
+ <string name="notification_channel_developer">Developer messages</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to system updates -->
+ <string name="notification_channel_updates">Updates</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to network status -->
+ <string name="notification_channel_network_status">Network status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to network alerts -->
+ <string name="notification_channel_network_alerts">Network alerts</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to vpn status -->
+ <string name="notification_channel_vpn">VPN status</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to remote device administration -->
+ <string name="notification_channel_device_admin">Device administration</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to important alerts -->
+ <string name="notification_channel_alerts">Alerts</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to being in retail mode -->
+ <string name="notification_channel_retail_mode">Retail demo</string>
+
+ <!-- Text shown when viewing channel settings for notifications related to a usb connection -->
+ <string name="notification_channel_usb">USB connection</string>
+
<!-- Displayed to the user to tell them that they have started up the phone in "safe mode" -->
<string name="safeMode">Safe mode</string>
@@ -728,6 +770,11 @@
the call to a different number or abort the call altogether.</string>
<!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permlab_answerPhoneCalls">answer phone calls</string>
+ <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
+ <string name="permdesc_answerPhoneCalls">Allows the app to answer an incoming phone call.</string>
+
+ <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permlab_receiveSms">receive text messages (SMS)</string>
<!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
<string name="permdesc_receiveSms">Allows the app to receive and process SMS
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 15abf74ef38c..3ba6a274ee8a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2887,4 +2887,21 @@
<!-- Colon separated list of package names that should be granted Notification Listener access -->
<java-symbol type="string" name="config_defaultListenerAccessPackages" />
+
+ <!-- system notification channels -->
+ <java-symbol type="string" name="notification_channel_virtual_keyboard" />
+ <java-symbol type="string" name="notification_channel_physical_keyboard" />
+ <java-symbol type="string" name="notification_channel_security" />
+ <java-symbol type="string" name="notification_channel_car_mode" />
+ <java-symbol type="string" name="notification_channel_account" />
+ <java-symbol type="string" name="notification_channel_developer" />
+ <java-symbol type="string" name="notification_channel_updates" />
+ <java-symbol type="string" name="notification_channel_network_status" />
+ <java-symbol type="string" name="notification_channel_network_alerts" />
+ <java-symbol type="string" name="notification_channel_vpn" />
+ <java-symbol type="string" name="notification_channel_device_admin" />
+ <java-symbol type="string" name="notification_channel_alerts" />
+ <java-symbol type="string" name="notification_channel_retail_mode" />
+ <java-symbol type="string" name="notification_channel_usb" />
+
</resources>
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
index e5a92bf23bdc..5dd3c2ce6b5d 100644
--- a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -91,6 +91,28 @@ public class ParceledListSliceTest extends TestCase {
}
}
+ public void testStringList() throws Exception {
+ final int objectCount = 400;
+ List<String> list = new ArrayList<String>();
+ for (long i = 0; i < objectCount; i++) {
+ list.add(Long.toString(i * (6 - i)));
+ }
+
+ StringParceledListSlice slice;
+ Parcel parcel = Parcel.obtain();
+ try {
+ parcel.writeParcelable(new StringParceledListSlice(list), 0);
+ parcel.setDataPosition(0);
+ slice = parcel.readParcelable(getClass().getClassLoader());
+ } finally {
+ parcel.recycle();
+ }
+
+ assertNotNull(slice);
+ assertNotNull(slice.getList());
+ assertEquals(list, slice.getList());
+ }
+
/**
* Test that only homogeneous elements may be unparceled.
*/
diff --git a/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java b/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java
index 685a9980fdc4..c2dbfd365964 100644
--- a/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java
+++ b/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java
@@ -38,11 +38,11 @@ public class BitmapTest extends TestCase {
assertEquals("rowbytes", 400, bm1.getRowBytes());
assertEquals("rowbytes", 200, bm2.getRowBytes());
- assertEquals("rowbytes", 200, bm3.getRowBytes());
-
+ assertEquals("rowbytes", 400, bm3.getRowBytes());
+
assertEquals("byteCount", 80000, bm1.getByteCount());
assertEquals("byteCount", 40000, bm2.getByteCount());
- assertEquals("byteCount", 40000, bm3.getByteCount());
+ assertEquals("byteCount", 80000, bm3.getByteCount());
assertEquals("height", 200, bm1.getHeight());
assertEquals("height", 200, bm2.getHeight());
@@ -51,10 +51,10 @@ public class BitmapTest extends TestCase {
assertTrue("hasAlpha", bm1.hasAlpha());
assertFalse("hasAlpha", bm2.hasAlpha());
assertTrue("hasAlpha", bm3.hasAlpha());
-
+
assertTrue("getConfig", bm1.getConfig() == Bitmap.Config.ARGB_8888);
assertTrue("getConfig", bm2.getConfig() == Bitmap.Config.RGB_565);
- assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_4444);
+ assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_8888);
}
@SmallTest
@@ -181,12 +181,12 @@ public class BitmapTest extends TestCase {
for (int i = 0; i < 256; i++) {
colors[i] = (i << 24) | (0xFF << 16) | (0x80 << 8) | 0;
}
-
+
Bitmap.Config config = Bitmap.Config.ARGB_8888;
// create a bitmap with the color array specified
Bitmap bm1 = Bitmap.createBitmap(colors, 16, 16, config);
-
+
// create a bitmap with no colors, but then call setPixels
Bitmap bm2 = Bitmap.createBitmap(16, 16, config);
bm2.setPixels(colors, 0, 16, 0, 0, 16, 16);
@@ -197,32 +197,32 @@ public class BitmapTest extends TestCase {
int c0 = colors[i];
int c1 = bm1.getPixel(i % 16, i / 16);
int c2 = bm2.getPixel(i % 16, i / 16);
-
+
// these two should always be identical
assertEquals("getPixel", c1, c2);
-
+
// comparing the original (c0) with the returned color is tricky,
// since it gets premultiplied during the set(), and unpremultiplied
// by the get().
int a0 = Color.alpha(c0);
int a1 = Color.alpha(c1);
assertEquals("alpha", a0, a1);
-
+
int r0 = Color.red(c0);
int r1 = Color.red(c1);
int rr = computePrePostMul(a0, r0);
assertTrue("red", Math.abs(rr - r1) <= tolerance);
-
+
int g0 = Color.green(c0);
int g1 = Color.green(c1);
int gg = computePrePostMul(a0, g0);
assertTrue("green", Math.abs(gg - g1) <= tolerance);
-
+
int b0 = Color.blue(c0);
int b1 = Color.blue(c1);
int bb = computePrePostMul(a0, b0);
assertTrue("blue", Math.abs(bb - b1) <= tolerance);
-
+
if (false) {
int cc = Color.argb(a0, rr, gg, bb);
android.util.Log.d("skia", "original " + Integer.toHexString(c0) +
@@ -231,4 +231,16 @@ public class BitmapTest extends TestCase {
}
}
}
+
+ @SmallTest
+ public void testCreateHardwareBitmapFromGraphicBuffer() {
+ GraphicBuffer buffer = GraphicBuffer.create(10, 10, PixelFormat.RGBA_8888,
+ GraphicBuffer.USAGE_HW_TEXTURE | GraphicBuffer.USAGE_SOFTWARE_MASK);
+ Canvas canvas = buffer.lockCanvas();
+ canvas.drawColor(Color.YELLOW);
+ buffer.unlockCanvasAndPost(canvas);
+ Bitmap hardwareBitmap = Bitmap.createHardwareBitmap(buffer);
+ assertTrue(hardwareBitmap.isPremultiplied());
+ assertFalse(hardwareBitmap.isMutable());
+ }
}
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index deea9726403f..b68543146a51 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -15,7 +15,7 @@
*/
package android.security;
-import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
/**
* Caller is required to ensure that {@link KeyStore#unlock
@@ -39,8 +39,8 @@ interface IKeyChainService {
// APIs used by Settings
boolean deleteCaCertificate(String alias);
boolean reset();
- ParceledListSlice getUserCaAliases();
- ParceledListSlice getSystemCaAliases();
+ StringParceledListSlice getUserCaAliases();
+ StringParceledListSlice getSystemCaAliases();
boolean containsCaAlias(String alias);
byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 7cab11a4cf81..c57b1b38bf7b 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -73,6 +73,24 @@ void SkiaCanvas::reset(SkCanvas* skiaCanvas) {
// Canvas state operations: Replace Bitmap
// ----------------------------------------------------------------------------
+class ClipCopier : public SkCanvas::ClipVisitor {
+public:
+ explicit ClipCopier(SkCanvas* dstCanvas) : m_dstCanvas(dstCanvas) {}
+
+ virtual void clipRect(const SkRect& rect, SkClipOp op, bool antialias) {
+ m_dstCanvas->clipRect(rect, op, antialias);
+ }
+ virtual void clipRRect(const SkRRect& rrect, SkClipOp op, bool antialias) {
+ m_dstCanvas->clipRRect(rrect, op, antialias);
+ }
+ virtual void clipPath(const SkPath& path, SkClipOp op, bool antialias) {
+ m_dstCanvas->clipPath(path, op, antialias);
+ }
+
+private:
+ SkCanvas* m_dstCanvas;
+};
+
void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
SkCanvas* newCanvas = new SkCanvas(bitmap);
@@ -80,9 +98,8 @@ void SkiaCanvas::setBitmap(const SkBitmap& bitmap) {
// Copy the canvas matrix & clip state.
newCanvas->setMatrix(mCanvas->getTotalMatrix());
- SkRegion rgn;
- mCanvas->temporary_internal_getRgnClip(&rgn);
- newCanvas->clipRegion(rgn, SkClipOp::kIntersect);
+ ClipCopier copier(newCanvas);
+ mCanvas->replayClips(&copier);
}
// deletes the previously owned canvas (if any)
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 1ebbe855a43f..fb37f9f62d14 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -1251,6 +1251,11 @@ public class MediaPlayer extends PlayerBase
public void prepare() throws IOException, IllegalStateException {
_prepare();
scanInternalSubtitleTracks();
+
+ // DrmInfo, if any, has been resolved by now.
+ synchronized (mDrmLock) {
+ mDrmInfoResolved = true;
+ }
}
private native void _prepare() throws IOException, IllegalStateException;
@@ -3149,12 +3154,6 @@ public class MediaPlayer extends PlayerBase
sendMessage(msg2);
}
- // MEDIA_DRM_INFO is fired (if available) before MEDIA_PREPARED.
- // An empty mDrmInfo indicates prepared is done but the source is not DRM protected.
- // Setting this before the callback so onPreparedListener can call getDrmInfo to
- // get the right state
- mDrmInfoResolved = true;
-
OnPreparedListener onPreparedListener = mOnPreparedListener;
if (onPreparedListener != null)
onPreparedListener.onPrepared(mMediaPlayer);
@@ -3166,12 +3165,14 @@ public class MediaPlayer extends PlayerBase
if (msg.obj == null) {
Log.w(TAG, "MEDIA_DRM_INFO msg.obj=NULL");
} else if (msg.obj instanceof Parcel) {
- Parcel parcel = (Parcel)msg.obj;
- DrmInfo drmInfo = new DrmInfo(parcel);
+ // The parcel was parsed already in postEventFromNative
+ DrmInfo drmInfo = null;
OnDrmInfoHandlerDelegate onDrmInfoHandlerDelegate;
synchronized (mDrmLock) {
- mDrmInfo = drmInfo.makeCopy();
+ if (mOnDrmInfoHandlerDelegate != null && mDrmInfo != null) {
+ drmInfo = mDrmInfo.makeCopy();
+ }
// local copy while keeping the lock
onDrmInfoHandlerDelegate = mOnDrmInfoHandlerDelegate;
}
@@ -3366,10 +3367,43 @@ public class MediaPlayer extends PlayerBase
return;
}
- if (what == MEDIA_INFO && arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
- // this acquires the wakelock if needed, and sets the client side state
- mp.start();
+ switch (what) {
+ case MEDIA_INFO:
+ if (arg1 == MEDIA_INFO_STARTED_AS_NEXT) {
+ // this acquires the wakelock if needed, and sets the client side state
+ mp.start();
+ }
+ break;
+
+ case MEDIA_DRM_INFO:
+ // We need to derive mDrmInfo before prepare() returns so processing it here
+ // before the notification is sent to EventHandler below. EventHandler runs in the
+ // notification looper so its handleMessage might process the event after prepare()
+ // has returned.
+ Log.v(TAG, "postEventFromNative MEDIA_DRM_INFO");
+ if (obj instanceof Parcel) {
+ Parcel parcel = (Parcel)obj;
+ DrmInfo drmInfo = new DrmInfo(parcel);
+ synchronized (mp.mDrmLock) {
+ mp.mDrmInfo = drmInfo;
+ }
+ } else {
+ Log.w(TAG, "MEDIA_DRM_INFO msg.obj of unexpected type " + obj);
+ }
+ break;
+
+ case MEDIA_PREPARED:
+ // By this time, we've learned about DrmInfo's presence or absence. This is meant
+ // mainly for prepareAsync() use case. For prepare(), this still can run to a race
+ // condition b/c MediaPlayerNative releases the prepare() lock before calling notify
+ // so we also set mDrmInfoResolved in prepare().
+ synchronized (mp.mDrmLock) {
+ mp.mDrmInfoResolved = true;
+ }
+ break;
+
}
+
if (mp.mEventHandler != null) {
Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj);
mp.mEventHandler.sendMessage(m);
@@ -4093,16 +4127,16 @@ public class MediaPlayer extends PlayerBase
* If the device has not been provisioned before, this call also provisions the device
* which involves accessing the provisioning server and can take a variable time to
* complete depending on the network connectivity.
- * If OnDrmPreparedListener is registered, prepareDrm() runs in non-blocking
+ * If {@code OnDrmPreparedListener} is registered, prepareDrm() runs in non-blocking
* mode by launching the provisioning in the background and returning. The listener
* will be called when provisioning and preperation has finished. If a
- * OnDrmPreparedListener is not registered, prepareDrm() waits till provisioning
+ * {@code OnDrmPreparedListener} is not registered, prepareDrm() waits till provisioning
* and preperation has finished, i.e., runs in blocking mode.
* <p>
- * If OnDrmPreparedListener is registered, it is called to indicated the DRM session
- * being ready regardless of blocking or non-blocking mode. The application should
- * not make any assumption about its call sequence (e.g., before or after prepareDrm
- * returns) or the thread context that will execute the listener.
+ * If {@code OnDrmPreparedListener} is registered, it is called to indicate the DRM
+ * session being ready. The application should not make any assumption about its call
+ * sequence (e.g., before or after prepareDrm returns), or the thread context that will
+ * execute the listener (unless the listener is registered with a handler thread).
* <p>
*
* @param uuid The UUID of the crypto scheme.
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 1b53d72d6e55..6e15d8da0033 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -70,9 +70,79 @@ public final class TvContract {
private static final String PATH_PROGRAM = "program";
private static final String PATH_RECORDED_PROGRAM = "recorded_program";
private static final String PATH_PREVIEW_PROGRAM = "preview_program";
+ private static final String PATH_WATCH_NEXT_PROGRAM = "watch_next_program";
private static final String PATH_PASSTHROUGH = "passthrough";
/**
+ * Activity Action: sent by an application telling the system to set the given channel as
+ * browsable. This is only relevant to channels with {@link Channels#TYPE_PREVIEW} type.
+ *
+ * <p>The intent must contain the following bundle parameters:
+ * <ul>
+ * <li>{@link #EXTRA_CHANNEL_ID}: ID for the {@link Channels#TYPE_PREVIEW} channel as a long
+ * integer.</li>
+ * <li>{@link #EXTRA_PACKAGE_NAME}: the package name of the requesting application.</li>
+ * </ul>
+ */
+ public static final String ACTION_MAKE_CHANNEL_BROWSABLE =
+ "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its preview
+ * program's browsable state is disabled, i.e., it will no longer be shown to users, which, for
+ * example, might be a result of users' interaction with UI. The input is expected to delete the
+ * preview program from the content provider.
+ *
+ * <p>The intent must contain the following bundle parameter:
+ * <ul>
+ * <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the disabled preview program ID.</li>
+ * </ul>
+ */
+ public static final String ACTION_PREVIEW_PROGRAM_BROWSABLE_DISABLED =
+ "android.media.tv.action.PREVIEW_PROGRAM_BROWSABLE_DISABLED";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its "watch next"
+ * program's browsable state is disabled, i.e., it will no longer be shown to users, which, for
+ * example, might be a result of users' interaction with UI. The input is expected to delete the
+ * "watch next" program from the content provider.
+ *
+ * <p>The intent must contain the following bundle parameter:
+ * <ul>
+ * <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the disabled "watch next" program ID.</li>
+ * </ul>
+ */
+ public static final String ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED =
+ "android.media.tv.action.WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED";
+
+ /**
+ * Broadcast Action: sent by the system to tell the target TV input that one of its existing
+ * preview programs is added to the watch next programs table by user.
+ *
+ * <p>The intent must contain the following bundle parameters:
+ * <ul>
+ * <li>{@link #EXTRA_PREVIEW_PROGRAM_ID}: the ID of the existing preview program.</li>
+ * <li>{@link #EXTRA_WATCH_NEXT_PROGRAM_ID}: the ID of the new watch next program.</li>
+ * </ul>
+ */
+ public static final String ACTION_PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT =
+ "android.media.tv.action.PREVIEW_PROGRAM_ADDED_TO_WATCH_NEXT";
+
+ /** The key for a bundle parameter containing a channel ID as a long integer */
+ public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
+
+ /** The key for a bundle parameter containing a package name as a string. */
+ public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
+
+ /** The key for a bundle parameter containing a program ID as a long integer. */
+ public static final String EXTRA_PREVIEW_PROGRAM_ID =
+ "android.media.tv.extra.PREVIEW_PROGRAM_ID";
+
+ /** The key for a bundle parameter containing a watch next program ID as a long integer. */
+ public static final String EXTRA_WATCH_NEXT_PROGRAM_ID =
+ "android.media.tv.extra.WATCH_NEXT_PROGRAM_ID";
+
+ /**
* The method name to get existing columns in the given table of the specified content provider.
*
* <p>The method caller must provide the following parameter:
@@ -421,6 +491,15 @@ public final class TvContract {
}
/**
+ * Builds a URI that points to a specific watch next program.
+ *
+ * @param watchNextProgramId The ID of the watch next program to point to.
+ */
+ public static final Uri buildWatchNextProgramUri(long watchNextProgramId) {
+ return ContentUris.withAppendedId(WatchNextPrograms.CONTENT_URI, watchNextProgramId);
+ }
+
+ /**
* Builds a URI that points to a specific program the user watched.
*
* @param watchedProgramId The ID of the watched program to point to.
@@ -492,17 +571,6 @@ public final class TvContract {
*/
public interface BaseProgramColumns extends BaseTvColumns {
/**
- * The ID of the TV channel that provides this TV program.
- *
- * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
- *
- * <p>This is a required field.
- *
- * <p>Type: INTEGER (long)
- */
- public static final String COLUMN_CHANNEL_ID = "channel_id";
-
- /**
* The title of this TV program.
*
* <p>If this program is an episodic TV show, it is recommended that the title is the series
@@ -766,6 +834,591 @@ public final class TvContract {
public static final String COLUMN_VERSION_NUMBER = "version_number";
}
+ /**
+ * Common base for the tables of preview programs.
+ */
+ public interface BasePreviewProgramColumns extends BaseProgramColumns {
+
+ /** @hide */
+ @StringDef({
+ TYPE_MOVIE,
+ TYPE_TV_SERIES,
+ TYPE_TV_SEASON,
+ TYPE_TV_EPISODE,
+ TYPE_CLIP,
+ TYPE_EVENT,
+ TYPE_CHANNEL,
+ TYPE_TRACK,
+ TYPE_ALBUM,
+ TYPE_ARTIST,
+ TYPE_PLAYLIST,
+ TYPE_STATION,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Type {}
+
+ /**
+ * The program type for movie.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_MOVIE = "TYPE_MOVIE";
+
+ /**
+ * The program type for TV series.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_SERIES = "TYPE_TV_SERIES";
+
+ /**
+ * The program type for TV season.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_SEASON = "TYPE_TV_SEASON";
+
+ /**
+ * The program type for TV episode.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+
+ /**
+ * The program type for clip.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_CLIP = "TYPE_CLIP";
+
+ /**
+ * The program type for event.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_EVENT = "TYPE_EVENT";
+
+ /**
+ * The program type for channel.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_CHANNEL = "TYPE_CHANNEL";
+
+ /**
+ * The program type for track.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_TRACK = "TYPE_TRACK";
+
+ /**
+ * The program type for album.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_ALBUM = "TYPE_ALBUM";
+
+ /**
+ * The program type for artist.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_ARTIST = "TYPE_ARTIST";
+
+ /**
+ * The program type for playlist.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+
+ /**
+ * The program type for station.
+ *
+ * @see #COLUMN_TYPE
+ */
+ public static final String TYPE_STATION = "TYPE_STATION";
+
+ /** @hide */
+ @StringDef({
+ ASPECT_RATIO_16_9,
+ ASPECT_RATIO_3_2,
+ ASPECT_RATIO_1_1,
+ ASPECT_RATIO_2_3,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AspectRatio {}
+
+ /**
+ * The aspect ratio for 16:9.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
+
+ /**
+ * The aspect ratio for 3:2.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
+
+ /**
+ * The aspect ratio for 1:1.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
+
+ /**
+ * The aspect ratio for 2:3.
+ *
+ * @see #COLUMN_POSTER_ART_ASPECT_RATIO
+ * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
+ */
+ public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
+
+ /** @hide */
+ @StringDef({
+ AVAILABILITY_AVAILABLE,
+ AVAILABILITY_FREE_WITH_SUBSCRIPTION,
+ AVAILABILITY_PAID_CONTENT,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Availability {}
+
+ /**
+ * The availability for "available to this user".
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
+
+ /**
+ * The availability for "free with subscription".
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
+ "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
+
+ /**
+ * The availability for "paid content, either to-own or rental
+ * (user has not purchased/rented).
+ *
+ * @see #COLUMN_AVAILABILITY
+ */
+ public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
+
+ /** @hide */
+ @StringDef({
+ INTERACTION_TYPE_LISTENS,
+ INTERACTION_TYPE_FOLLOWERS,
+ INTERACTION_TYPE_FANS,
+ INTERACTION_TYPE_LIKES,
+ INTERACTION_TYPE_THUMBS,
+ INTERACTION_TYPE_VIEWS,
+ INTERACTION_TYPE_VIEWERS,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface InteractionType {}
+
+ /**
+ * The interaction type for "listens".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
+
+ /**
+ * The interaction type for "followers".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
+
+ /**
+ * The interaction type for "fans".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
+
+ /**
+ * The interaction type for "likes".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
+
+ /**
+ * The interaction type for "thumbs".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
+
+ /**
+ * The interaction type for "views".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
+
+ /**
+ * The interaction type for "viewers".
+ *
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
+
+ /** @hide */
+ @StringDef({
+ REVIEW_RATING_STYLE_STARS,
+ REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
+ REVIEW_RATING_STYLE_PERCENTAGE,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ReviewRatingStyle {}
+
+ /**
+ * The review rating style for five star rating.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
+
+ /**
+ * The review rating style for thumbs-up and thumbs-down rating.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
+ "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
+
+ /**
+ * The review rating style for 0 to 100 point system.
+ *
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String REVIEW_RATING_STYLE_PERCENTAGE =
+ "REVIEW_RATING_STYLE_PERCENTAGE";
+
+ /**
+ * The type of this program content.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #TYPE_MOVIE},
+ * {@link #TYPE_TV_SERIES},
+ * {@link #TYPE_TV_SEASON},
+ * {@link #TYPE_TV_EPISODE},
+ * {@link #TYPE_CLIP},
+ * {@link #TYPE_EVENT},
+ * {@link #TYPE_CHANNEL},
+ * {@link #TYPE_TRACK},
+ * {@link #TYPE_ALBUM},
+ * {@link #TYPE_ARTIST},
+ * {@link #TYPE_PLAYLIST}, and
+ * {@link #TYPE_STATION}.
+ *
+ * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
+ * channel.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_TYPE = "type";
+
+ /**
+ * The aspect ratio of the poster art for this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #ASPECT_RATIO_16_9},
+ * {@link #ASPECT_RATIO_3_2},
+ * {@link #ASPECT_RATIO_1_1}, and
+ * {@link #ASPECT_RATIO_2_3}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
+
+ /**
+ * The aspect ratio of the thumbnail for this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #ASPECT_RATIO_16_9},
+ * {@link #ASPECT_RATIO_3_2},
+ * {@link #ASPECT_RATIO_1_1}, and
+ * {@link #ASPECT_RATIO_2_3}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
+
+ /**
+ * The URI for the logo of this TV program.
+ *
+ * <p>This is a small badge shown on top of the poster art or thumbnail representing the
+ * source of the content.
+ *
+ * <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
+ */
+ public static final String COLUMN_LOGO_URI = "logo_uri";
+
+ /**
+ * The availability of this TV program.
+ *
+ * <p>The value should match one of the followings:
+ * {@link #AVAILABILITY_AVAILABLE},
+ * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
+ * {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_AVAILABILITY = "availability";
+
+ /**
+ * The starting price of this TV program.
+ *
+ * <p>This indicates the lowest regular acquisition cost of the content. It is only used
+ * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_OFFER_PRICE
+ */
+ public static final String COLUMN_STARTING_PRICE = "starting_price";
+
+ /**
+ * The offer price of this TV program.
+ *
+ * <p>This is the promotional cost of the content. It is only used if the availability of
+ * the program is {@link #AVAILABILITY_PAID_CONTENT}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_STARTING_PRICE
+ */
+ public static final String COLUMN_OFFER_PRICE = "offer_price";
+
+ /**
+ * The release date of this TV program.
+ *
+ * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_RELEASE_DATE = "release_date";
+
+ /**
+ * The count of the items included in this TV program.
+ *
+ * <p>This is only relevant if the program represents a collection of items such as series,
+ * episodes, or music tracks.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_ITEM_COUNT = "item_count";
+
+ /**
+ * The flag indicating whether this TV program is live or not.
+ *
+ * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
+ * of 0 indicates that the content is off the air and does not need to be consumed at the
+ * present time. If not specified, the value is set to 0 (not live) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_LIVE = "live";
+
+ /**
+ * The internal ID used by individual TV input services.
+ *
+ * <p>This is internal to the provider that inserted it, and should not be decoded by other
+ * apps.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
+
+ /**
+ * The URI for the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}. 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
+ */
+ public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
+
+ /**
+ * The last playback position (in milliseconds) of the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
+ "last_playback_position_millis";
+
+ /**
+ * The duration (in milliseconds) of the preview video.
+ *
+ * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: INTEGER
+ */
+ public static final String COLUMN_DURATION_MILLIS = "duration_millis";
+
+ /**
+ * The intent URI which is launched when the preview video is selected.
+ *
+ * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
+ * and converted back to the original intent with {@link Intent#parseUri}. The intent is
+ * launched when the user selects the preview video item.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_APP_LINK_INTENT_URI =
+ "app_link_intent_uri";
+
+ /**
+ * The flag indicating whether this program is transient or not.
+ *
+ * <p>A value of 1 indicates that the channel will be automatically removed by the system on
+ * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
+ * specified, this value is set to 0 (not transient) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ * @see Channels#COLUMN_TRANSIENT
+ * @hide
+ */
+ @SystemApi
+ public static final String COLUMN_TRANSIENT = "transient";
+
+ /**
+ * The type of interaction for this TV program.
+ *
+ * <p> The value should match one of the followings:
+ * {@link #INTERACTION_TYPE_LISTENS},
+ * {@link #INTERACTION_TYPE_FOLLOWERS},
+ * {@link #INTERACTION_TYPE_FANS},
+ * {@link #INTERACTION_TYPE_LIKES},
+ * {@link #INTERACTION_TYPE_THUMBS},
+ * {@link #INTERACTION_TYPE_VIEWS}, and
+ * {@link #INTERACTION_TYPE_VIEWERS}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_INTERACTION_COUNT
+ */
+ public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
+
+ /**
+ * The interaction count for this program.
+ *
+ * <p>This indicates the number of times interaction has happened.
+ *
+ * <p>Type: INTEGER (long)
+ * @see #COLUMN_INTERACTION_TYPE
+ */
+ public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
+
+ /**
+ * The author or artist of this content.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_AUTHOR = "author";
+
+ /**
+ * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
+ *
+ * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
+ * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_REVIEW_RATING
+ */
+ public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
+
+ /**
+ * The review rating score for this program.
+ *
+ * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
+ * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
+ * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
+ * the value should be two integers, one for thumbs-up count and the other for thumbs-down
+ * count, with a comma between them. (e.g. "200,40") If the style is
+ * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
+ * 100. (e.g. "99.9")
+ *
+ * <p>Type: TEXT
+ * @see #COLUMN_REVIEW_RATING_STYLE
+ */
+ public static final String COLUMN_REVIEW_RATING = "review_rating";
+
+ /**
+ * The flag indicating whether this TV program is browsable or not.
+ *
+ * <p>This column can only be set by applications having proper system permission. For
+ * other applications, this is a read-only column.
+ *
+ * <p>A value of 1 indicates that the program is browsable and can be shown to users in
+ * the UI. A value of 0 indicates that the program should be hidden from users and the
+ * application who changes this value to 0 should send
+ * {@link #ACTION_WATCH_NEXT_PROGRAM_BROWSABLE_DISABLED} to the owner of the program
+ * to notify this change.
+ *
+ * <p>This value is set to 1 (browsable) by default.
+ *
+ * <p>Type: INTEGER (boolean)
+ */
+ public static final String COLUMN_BROWSABLE = "browsable";
+
+ /**
+ * The content ID of this TV program.
+ *
+ * <p>A public ID of the content which allows the application to apply the same operation to
+ * all the program copies in different channels.
+ *
+ * <p>Can be empty.
+ *
+ * <p>Type: TEXT
+ */
+ public static final String COLUMN_CONTENT_ID = "content_id";
+
+ }
+
/** Column definitions for the TV channels table. */
public static final class Channels implements BaseTvColumns {
@@ -1279,14 +1932,15 @@ public final class TvContract {
/**
* The flag indicating whether this TV channel is browsable or not.
*
+ * <p>This column can only be set by applications having proper system permission. For
+ * other applications, this is a read-only column.
+ *
* <p>A value of 1 indicates the channel is included in the channel list that applications
* use to browse channels, a value of 0 indicates the channel is not included in the list.
* If not specified, this value is set to 0 (not browsable) by default.
*
* <p>Type: INTEGER (boolean)
- * @hide
*/
- @SystemApi
public static final String COLUMN_BROWSABLE = "browsable";
/**
@@ -1587,6 +2241,17 @@ public final class TvContract {
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/program";
/**
+ * The ID of the TV channel that provides this TV program.
+ *
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+ /**
* The season number of this TV program for episodic TV shows.
*
* <p>Can be empty.
@@ -1890,6 +2555,17 @@ public final class TvContract {
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/recorded_program";
/**
+ * The ID of the TV channel that provides this recorded program.
+ *
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
+ *
+ * <p>This is a required field.
+ *
+ * <p>Type: INTEGER (long)
+ */
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
+
+ /**
* The ID of the TV input service that is associated with this recorded program.
*
* <p>Use {@link #buildInputId} to build the ID.
@@ -1988,7 +2664,7 @@ public final class TvContract {
/**
* Column definitions for the preview TV programs table.
*/
- public static final class PreviewPrograms implements BaseProgramColumns {
+ public static final class PreviewPrograms implements BasePreviewProgramColumns {
/** The content:// style URI for this table. */
public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
@@ -2000,631 +2676,132 @@ public final class TvContract {
/** The MIME type of a single preview TV program. */
public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/preview_program";
- /** @hide */
- @StringDef({
- TYPE_MOVIE,
- TYPE_TV_SERIES,
- TYPE_TV_SEASON,
- TYPE_TV_EPISODE,
- TYPE_CLIP,
- TYPE_EVENT,
- TYPE_CHANNEL,
- TYPE_TRACK,
- TYPE_ALBUM,
- TYPE_ARTIST,
- TYPE_PLAYLIST,
- TYPE_STATION,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Type {}
-
- /**
- * The program type for movie.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_MOVIE = "TYPE_MOVIE";
-
/**
- * The program type for TV series.
+ * The ID of the TV channel that provides this TV program.
*
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TV_SERIES = "TYPE_TV_SERIES";
-
- /**
- * The program type for TV season.
+ * <p>This is a part of the channel URI and matches to {@link BaseColumns#_ID}.
*
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TV_SEASON = "TYPE_TV_SEASON";
-
- /**
- * The program type for TV episode.
+ * <p>This is a required field.
*
- * @see #COLUMN_TYPE
+ * <p>Type: INTEGER (long)
*/
- public static final String TYPE_TV_EPISODE = "TYPE_TV_EPISODE";
+ public static final String COLUMN_CHANNEL_ID = "channel_id";
/**
- * The program type for clip.
+ * The weight of the preview program within the channel.
*
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_CLIP = "TYPE_CLIP";
-
- /**
- * The program type for event.
+ * <p>The UI may choose to show this item in a different position in the channel row.
+ * A larger weight value means the program is more important than other programs having
+ * smaller weight values. The value is relevant for the preview programs in the same
+ * channel. This is only relevant to {@link Channels#TYPE_PREVIEW}.
*
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_EVENT = "TYPE_EVENT";
-
- /**
- * The program type for channel.
+ * <p>Can be empty.
*
- * @see #COLUMN_TYPE
+ * <p>Type: INTEGER
*/
- public static final String TYPE_CHANNEL = "TYPE_CHANNEL";
+ public static final String COLUMN_WEIGHT = "weight";
- /**
- * The program type for track.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_TRACK = "TYPE_TRACK";
+ private PreviewPrograms() {}
+ }
- /**
- * The program type for album.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_ALBUM = "TYPE_ALBUM";
+ /**
+ * Column definitions for the "watch next" TV programs table.
+ */
+ public static final class WatchNextPrograms implements BasePreviewProgramColumns {
- /**
- * The program type for artist.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_ARTIST = "TYPE_ARTIST";
+ /** The content:// style URI for this table. */
+ public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
+ + PATH_WATCH_NEXT_PROGRAM);
- /**
- * The program type for playlist.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_PLAYLIST = "TYPE_PLAYLIST";
+ /** The MIME type of a directory of "watch next" TV programs. */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/watch_next_program";
- /**
- * The program type for station.
- *
- * @see #COLUMN_TYPE
- */
- public static final String TYPE_STATION = "TYPE_STATION";
+ /** The MIME type of a single preview TV program. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/watch_next_program";
/** @hide */
@StringDef({
WATCH_NEXT_TYPE_CONTINUE,
WATCH_NEXT_TYPE_NEXT,
WATCH_NEXT_TYPE_NEW,
+ WATCH_NEXT_TYPE_WATCHLIST,
})
@Retention(RetentionPolicy.SOURCE)
public @interface WatchNextType {}
/**
- * The watch next type for CONTINUE.
+ * The watch next type for CONTINUE. Use this type when the user has already watched more
+ * than 1 minute of this content.
*
* @see #COLUMN_WATCH_NEXT_TYPE
*/
public static final String WATCH_NEXT_TYPE_CONTINUE = "WATCH_NEXT_TYPE_CONTINUE";
/**
- * The watch next type for NEXT.
+ * The watch next type for NEXT. Use this type when the user has watched one or more
+ * complete episodes from some episodic content, but there remains more than one episode
+ * remaining or there is one last episode remaining, but it is not “new” in that it was
+ * released before the user started watching the show.
*
* @see #COLUMN_WATCH_NEXT_TYPE
*/
public static final String WATCH_NEXT_TYPE_NEXT = "WATCH_NEXT_TYPE_NEXT";
/**
- * The watch next type for NEW.
+ * The watch next type for NEW. Use this type when the user had watched all of the available
+ * episodes from some episodic content, but a new episode became available since the user
+ * started watching the first episode and now there is exactly one unwatched episode. This
+ * could also work for recorded events in a series e.g. soccer matches or football games.
*
* @see #COLUMN_WATCH_NEXT_TYPE
*/
public static final String WATCH_NEXT_TYPE_NEW = "WATCH_NEXT_TYPE_NEW";
- /** @hide */
- @StringDef({
- ASPECT_RATIO_16_9,
- ASPECT_RATIO_3_2,
- ASPECT_RATIO_1_1,
- ASPECT_RATIO_2_3,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface AspectRatio {}
-
- /**
- * The aspect ratio for 16:9.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_16_9 = "ASPECT_RATIO_16_9";
-
- /**
- * The aspect ratio for 3:2.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_3_2 = "ASPECT_RATIO_3_2";
-
- /**
- * The aspect ratio for 1:1.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_1_1 = "ASPECT_RATIO_1_1";
-
- /**
- * The aspect ratio for 2:3.
- *
- * @see #COLUMN_POSTER_ART_ASPECT_RATIO
- * @see #COLUMN_THUMBNAIL_ASPECT_RATIO
- */
- public static final String ASPECT_RATIO_2_3 = "ASPECT_RATIO_2_3";
-
- /** @hide */
- @StringDef({
- AVAILABILITY_AVAILABLE,
- AVAILABILITY_FREE_WITH_SUBSCRIPTION,
- AVAILABILITY_PAID_CONTENT,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface Availability {}
-
- /**
- * The availability for "available to this user".
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_AVAILABLE = "AVAILABILITY_AVAILABLE";
-
- /**
- * The availability for "free with subscription".
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_FREE_WITH_SUBSCRIPTION =
- "AVAILABILITY_FREE_WITH_SUBSCRIPTION";
-
- /**
- * The availability for "paid content, either to-own or rental
- * (user has not purchased/rented).
- *
- * @see #COLUMN_AVAILABILITY
- */
- public static final String AVAILABILITY_PAID_CONTENT = "AVAILABILITY_PAID_CONTENT";
-
- /** @hide */
- @StringDef({
- INTERACTION_TYPE_LISTENS,
- INTERACTION_TYPE_FOLLOWERS,
- INTERACTION_TYPE_FANS,
- INTERACTION_TYPE_LIKES,
- INTERACTION_TYPE_THUMBS,
- INTERACTION_TYPE_VIEWS,
- INTERACTION_TYPE_VIEWERS,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface InteractionType {}
-
- /**
- * The interaction type for "listens".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_LISTENS = "INTERACTION_TYPE_LISTENS";
-
- /**
- * The interaction type for "followers".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_FOLLOWERS = "INTERACTION_TYPE_FOLLOWERS";
-
- /**
- * The interaction type for "fans".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_FANS = "INTERACTION_TYPE_FANS";
-
- /**
- * The interaction type for "likes".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_LIKES = "INTERACTION_TYPE_LIKES";
-
- /**
- * The interaction type for "thumbs".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_THUMBS = "INTERACTION_TYPE_THUMBS";
-
- /**
- * The interaction type for "views".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_VIEWS = "INTERACTION_TYPE_VIEWS";
-
- /**
- * The interaction type for "viewers".
- *
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String INTERACTION_TYPE_VIEWERS = "INTERACTION_TYPE_VIEWERS";
-
- /** @hide */
- @StringDef({
- REVIEW_RATING_STYLE_STARS,
- REVIEW_RATING_STYLE_THUMBS_UP_DOWN,
- REVIEW_RATING_STYLE_PERCENTAGE,
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ReviewRatingStyle {}
-
- /**
- * The review rating style for five star rating.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_STARS = "REVIEW_RATING_STYLE_STARS";
-
- /**
- * The review rating style for thumbs-up and thumbs-down rating.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_THUMBS_UP_DOWN =
- "REVIEW_RATING_STYLE_THUMBS_UP_DOWN";
-
- /**
- * The review rating style for 0 to 100 point system.
- *
- * @see #COLUMN_REVIEW_RATING_STYLE
- */
- public static final String REVIEW_RATING_STYLE_PERCENTAGE =
- "REVIEW_RATING_STYLE_PERCENTAGE";
-
/**
- * The type of this program content.
- *
- * <p>The value should match one of the followings:
- * {@link #TYPE_MOVIE},
- * {@link #TYPE_TV_SERIES},
- * {@link #TYPE_TV_SEASON},
- * {@link #TYPE_TV_EPISODE},
- * {@link #TYPE_CLIP},
- * {@link #TYPE_EVENT},
- * {@link #TYPE_CHANNEL},
- * {@link #TYPE_TRACK},
- * {@link #TYPE_ALBUM},
- * {@link #TYPE_ARTIST},
- * {@link #TYPE_PLAYLIST}, and
- * {@link #TYPE_STATION}.
+ * The watch next type for WATCHLIST. Use this type when the user has elected to explicitly
+ * add a movie, event or series to a “watchlist” as a manual way of curating what they
+ * want to watch next.
*
- * <p>This is a required field if the program is from a {@link Channels#TYPE_PREVIEW}
- * channel.
- *
- * <p>Type: TEXT
+ * @see #COLUMN_WATCH_NEXT_TYPE
*/
- public static final String COLUMN_TYPE = "type";
+ public static final String WATCH_NEXT_TYPE_WATCHLIST = "WATCH_NEXT_TYPE_WATCHLIST";
/**
* The "watch next" type of this program content.
*
* <p>The value should match one of the followings:
* {@link #WATCH_NEXT_TYPE_CONTINUE},
- * {@link #WATCH_NEXT_TYPE_NEXT}, and
- * {@link #WATCH_NEXT_TYPE_NEW}.
+ * {@link #WATCH_NEXT_TYPE_NEXT},
+ * {@link #WATCH_NEXT_TYPE_NEW}, and
+ * {@link #WATCH_NEXT_TYPE_WATCHLIST}.
*
- * <p>Can be empty.
+ * <p>This is a required field.
*
* <p>Type: TEXT
*/
public static final String COLUMN_WATCH_NEXT_TYPE = "watch_next_type";
/**
- * The aspect ratio of the poster art for this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #ASPECT_RATIO_16_9},
- * {@link #ASPECT_RATIO_3_2},
- * {@link #ASPECT_RATIO_1_1}, and
- * {@link #ASPECT_RATIO_2_3}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_POSTER_ART_ASPECT_RATIO = "poster_art_aspect_ratio";
-
- /**
- * The aspect ratio of the thumbnail for this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #ASPECT_RATIO_16_9},
- * {@link #ASPECT_RATIO_3_2},
- * {@link #ASPECT_RATIO_1_1}, and
- * {@link #ASPECT_RATIO_2_3}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_THUMBNAIL_ASPECT_RATIO = "poster_thumbnail_aspect_ratio";
-
- /**
- * The URI for the logo of this TV program.
- *
- * <p>This is a small badge shown on top of the poster art or thumbnail representing the
- * source of the content.
- *
- * <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
- */
- public static final String COLUMN_LOGO_URI = "logo_uri";
-
- /**
- * The availability of this TV program.
- *
- * <p>The value should match one of the followings:
- * {@link #AVAILABILITY_AVAILABLE},
- * {@link #AVAILABILITY_FREE_WITH_SUBSCRIPTION}, and
- * {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_AVAILABILITY = "availability";
-
- /**
- * The starting price of this TV program.
- *
- * <p>This indicates the lowest regular acquisition cost of the content. It is only used
- * if the availability of the program is {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_OFFER_PRICE
- */
- public static final String COLUMN_STARTING_PRICE = "starting_price";
-
- /**
- * The offer price of this TV program.
- *
- * <p>This is the promotional cost of the content. It is only used if the availability of
- * the program is {@link #AVAILABILITY_PAID_CONTENT}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_STARTING_PRICE
- */
- public static final String COLUMN_OFFER_PRICE = "offer_price";
-
- /**
- * The release date of this TV program.
- *
- * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_RELEASE_DATE = "release_date";
-
- /**
- * The count of the items included in this TV program.
- *
- * <p>This is only relevant if the program represents a collection of items such as series,
- * episodes, or music tracks.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_ITEM_COUNT = "item_count";
-
- /**
- * The flag indicating whether this TV program is live or not.
- *
- * <p>A value of 1 indicates that the content is airing and should be consumed now, a value
- * of 0 indicates that the content is off the air and does not need to be consumed at the
- * present time. If not specified, the value is set to 0 (not live) by default.
- *
- * <p>Type: INTEGER (boolean)
- */
- public static final String COLUMN_LIVE = "live";
-
- /**
- * The internal ID used by individual TV input services.
- *
- * <p>This is internal to the provider that inserted it, and should not be decoded by other
- * apps.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_INTERNAL_PROVIDER_ID = "internal_provider_id";
-
- /**
- * The URI for the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}. The data in the column must be
- * a URL, or a URI in one of the following formats:
+ * The last UTC time that the user engaged in this TV program, in milliseconds since the
+ * epoch. This is a hint for the application that is used for ordering of "watch next"
+ * programs.
*
+ * <p>The meaning of the value varies depending on the {@link #COLUMN_WATCH_NEXT_TYPE}:
* <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>
+ * <li>{@link #WATCH_NEXT_TYPE_CONTINUE}: the date that the user was last watching the
+ * content.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_NEXT}: the date of the last episode watched.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_NEW}: the release date of the new episode.</li>
+ * <li>{@link #WATCH_NEXT_TYPE_WATCHLIST}: the date the item was added to the Watchlist.
+ * </li>
* </ul>
*
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_PREVIEW_VIDEO_URI = "preview_video_uri";
-
- /**
- * The last playback position (in milliseconds) of the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_LAST_PLAYBACK_POSITION_MILLIS =
- "last_playback_position_millis";
-
- /**
- * The duration (in milliseconds) of the preview video.
- *
- * <p>This is only relevant to {@link Channels#TYPE_PREVIEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_DURATION_MILLIS = "duration_millis";
-
- /**
- * The intent URI which is launched when the preview video is selected.
- *
- * <p>The URI is created using {@link Intent#toUri} with {@link Intent#URI_INTENT_SCHEME}
- * and converted back to the original intent with {@link Intent#parseUri}. The intent is
- * launched when the user selects the preview video item.
- *
- * <p>Can be empty.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_APP_LINK_INTENT_URI =
- "app_link_intent_uri";
-
- /**
- * The weight of the preview program within the channel.
- *
- * <p>The UI may choose to show this item in a different position in the channel row.
- * A larger weight value means the program is more important than other programs having
- * smaller weight values. The value is relevant for the preview programs in the same
- * channel. This is only relevant to {@link Channels#TYPE_PREVIEW}.
- *
- * <p>Can be empty.
- *
- * <p>Type: INTEGER
- */
- public static final String COLUMN_WEIGHT = "weight";
-
- /**
- * The flag indicating whether this program is transient or not.
- *
- * <p>A value of 1 indicates that the channel will be automatically removed by the system on
- * reboot, and a value of 0 indicates that the channel is persistent across reboot. If not
- * specified, this value is set to 0 (not transient) by default.
- *
- * <p>Type: INTEGER (boolean)
- * @see Channels#COLUMN_TRANSIENT
- * @hide
- */
- @SystemApi
- public static final String COLUMN_TRANSIENT = "transient";
-
- /**
- * The type of interaction for this TV program.
- *
- * <p> The value should match one of the followings:
- * {@link #INTERACTION_TYPE_LISTENS},
- * {@link #INTERACTION_TYPE_FOLLOWERS},
- * {@link #INTERACTION_TYPE_FANS},
- * {@link #INTERACTION_TYPE_LIKES},
- * {@link #INTERACTION_TYPE_THUMBS},
- * {@link #INTERACTION_TYPE_VIEWS}, and
- * {@link #INTERACTION_TYPE_VIEWERS}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_INTERACTION_COUNT
- */
- public static final String COLUMN_INTERACTION_TYPE = "interaction_type";
-
- /**
- * The interaction count for this program.
- *
- * <p>This indicates the number of times interaction has happened.
+ * <p>This is a required field.
*
* <p>Type: INTEGER (long)
- * @see #COLUMN_INTERACTION_TYPE
- */
- public static final String COLUMN_INTERACTION_COUNT = "interaction_count";
-
- /**
- * The author or artist of this content.
- *
- * <p>Type: TEXT
- */
- public static final String COLUMN_AUTHOR = "author";
-
- /**
- * The review rating score style used for {@link #COLUMN_REVIEW_RATING}.
- *
- * <p> The value should match one of the followings: {@link #REVIEW_RATING_STYLE_STARS},
- * {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN}, and {@link #REVIEW_RATING_STYLE_PERCENTAGE}.
- *
- * <p>Type: TEXT
- * @see #COLUMN_REVIEW_RATING
- */
- public static final String COLUMN_REVIEW_RATING_STYLE = "review_rating_style";
-
- /**
- * The review rating score for this program.
- *
- * <p>The format of the value is dependent on {@link #COLUMN_REVIEW_RATING_STYLE}. If the
- * style is {@link #REVIEW_RATING_STYLE_STARS}, the value should be a real number between
- * 0.0 and 5.0. (e.g. "4.5") If the style is {@link #REVIEW_RATING_STYLE_THUMBS_UP_DOWN},
- * the value should be two integers, one for thumbs-up count and the other for thumbs-down
- * count, with a comma between them. (e.g. "200,40") If the style is
- * {@link #REVIEW_RATING_STYLE_PERCENTAGE}, the value shoule be a real number between 0 and
- * 100. (e.g. "99.9")
- *
- * <p>Type: TEXT
- * @see #COLUMN_REVIEW_RATING_STYLE
*/
- public static final String COLUMN_REVIEW_RATING = "review_rating";
-
- /**
- * The flag indicating whether this TV program is browsable or not.
- *
- * <p>This column can only be set by system apps. For other applications, it is a read-only
- * column. Trying to modify it may cause {@link SecurityException}.
- *
- * <p>A value of 1 indicates that the program is browsable and can be shown to users in
- * the UI. A value of 0 indicates that the program should be hidden from users and the
- * application who changes this value to 0 should send
- * {@link TvInputManager#ACTION_PROGRAM_BROWSABLE_DISABLED} to the owner of the program
- * to notify this change.
- *
- * <p>This value is set to 1 (browsable) by default.
- *
- * <p>Type: INTEGER (boolean)
- */
- public static final String COLUMN_BROWSABLE = "browsable";
-
- private PreviewPrograms() {}
+ public static final String COLUMN_LAST_ENGAGEMENT_TIME_UTC_MILLIS =
+ "last_engagement_time_utc_millis";
}
/**
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index 4c2b031d8f04..1eae8db60833 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -324,40 +324,6 @@ public final class TvInputManager {
public static final String ACTION_VIEW_RECORDING_SCHEDULES =
"android.media.tv.action.VIEW_RECORDING_SCHEDULES";
- /**
- * Action sent by the system to tell the target TV input that one of its program's browsable
- * state is disabled, i.e., it will no longer be shown to users, which, for example, might
- * be a result of users' interaction with UI.
- *
- * <p>The intent must contain the following bundle parameter:
- * <ul>
- * <li>{@link #EXTRA_PROGRAM_ID} the program ID as a long integer.
- * </ul>
- */
- public static final String ACTION_PROGRAM_BROWSABLE_DISABLED =
- "android.media.tv.action.PROGRAM_BROWSABLE_DISABLED";
-
- /**
- * Action sent by an application telling the system to set the given channel as browsable.
- *
- * <p>The intent must contain the following bundle parameters:
- * <ul>
- * <li>{@link #EXTRA_CHANNEL_ID} the channel ID as a long integer.
- * <li>{@link #EXTRA_PACKAGE_NAME} the package name of the requesting application.
- * </ul>
- */
- public static final String ACTION_MAKE_CHANNEL_BROWSABLE
- = "android.media.tv.action.MAKE_CHANNEL_BROWSABLE";
-
- /** The key for a bundle parameter containing a channel ID as a long integer */
- public static final String EXTRA_CHANNEL_ID = "android.media.tv.extra.CHANNEL_ID";
-
- /** The key for a bundle parameter containing a package name as a string. */
- public static final String EXTRA_PACKAGE_NAME = "android.media.tv.extra.PACKAGE_NAME";
-
- /** The key for a bundle parameter containing a program ID as a long integer */
- public static final String EXTRA_PROGRAM_ID = "android.media.tv.extra.PROGRAM_ID";
-
private final ITvInputManager mService;
private final Object mLock = new Object();
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index aee9d38e0a27..e5af35711311 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -776,8 +776,8 @@ public class TvView extends ViewGroup {
mSurface = null;
mSurfaceView = new SurfaceView(getContext(), mAttrs, mDefStyleAttr) {
@Override
- protected void updateWindow() {
- super.updateWindow();
+ protected void updateSurface() {
+ super.updateSurface();
relayoutSessionOverlayView();
}};
// The surface view's content should be treated as secure all the time.
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index e2623d4fd9ee..1b1f28c37469 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -170,14 +170,20 @@ LIBANDROID {
ASensorEventQueue_getEvents;
ASensorEventQueue_hasEvents;
ASensorEventQueue_setEventRate;
+ ASensorManager_configureDirectReport; # introduced=26
ASensorManager_createEventQueue;
+ ASensorManager_createHardwareBufferDirectChannel; # introduced=26
+ ASensorManager_createSharedMemoryDirectChannel; # introduced=26
+ ASensorManager_destroyDirectChannel; # introduced=26
ASensorManager_destroyEventQueue;
ASensorManager_getDefaultSensor;
ASensorManager_getDefaultSensorEx; # introduced=21
ASensorManager_getInstance;
+ ASensorManager_getInstanceForPackage; # introduced=26
ASensorManager_getSensorList;
ASensor_getFifoMaxEventCount; # introduced=21
ASensor_getFifoReservedEventCount; # introduced=21
+ ASensor_getHighestDirectReportRateLevel; # introduced=26
ASensor_getMinDelay;
ASensor_getName;
ASensor_getReportingMode; # introduced=21
@@ -185,6 +191,7 @@ LIBANDROID {
ASensor_getStringType; # introduced=21
ASensor_getType;
ASensor_getVendor;
+ ASensor_isDirectChannelTypeSupported; # introduced=26
ASensor_isWakeUpSensor; # introduced=21
ASharedMemory_create; # introduced=26
ASharedMemory_getSize; # introduced=26
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 5cfe3004514c..c7bc885ea4b0 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -17,16 +17,17 @@
#define LOG_TAG "sensor"
#include <utils/Log.h>
+#include <android/hardware_buffer.h>
#include <android/looper.h>
#include <android/sensor.h>
-
-#include <utils/RefBase.h>
-#include <utils/Looper.h>
-#include <utils/Timers.h>
-
+#include <android/sharedmem.h>
+#include <cutils/native_handle.h>
#include <gui/Sensor.h>
#include <gui/SensorManager.h>
#include <gui/SensorEventQueue.h>
+#include <utils/Looper.h>
+#include <utils/RefBase.h>
+#include <utils/Timers.h>
#include <poll.h>
@@ -38,6 +39,22 @@ using android::String8;
using android::String16;
/*****************************************************************************/
+#define ERROR_INVALID_PARAMETER(message) ALOGE("%s: " message, __func__)
+
+// frequently used check
+#define RETURN_IF_MANAGER_IS_NULL(retval) do {\
+ if (manager == nullptr) { \
+ ERROR_INVALID_PARAMETER("manager cannot be NULL"); \
+ return retval; \
+ } \
+ } while (false)
+#define RETURN_IF_SENSOR_IS_NULL(retval) do {\
+ if (sensor == nullptr) { \
+ ERROR_INVALID_PARAMETER("sensor cannot be NULL"); \
+ return retval; \
+ } \
+ } while (false)
+
ASensorManager* ASensorManager_getInstance()
{
return ASensorManager_getInstanceForPackage(NULL);
@@ -103,6 +120,78 @@ int ASensorManager_destroyEventQueue(ASensorManager* manager,
return 0;
}
+int ASensorManager_createSharedMemoryDirectChannel(
+ ASensorManager *manager, int fd, size_t size) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ if (fd < 0) {
+ ERROR_INVALID_PARAMETER("fd is invalid.");
+ return android::BAD_VALUE;
+ }
+
+ if (size < sizeof(ASensorEvent)) {
+ ERROR_INVALID_PARAMETER("size has to be greater or equal to sizeof(ASensorEvent).");
+ }
+
+ native_handle_t *resourceHandle = native_handle_create(1 /* nFd */, 0 /* nInt */);
+ if (!resourceHandle) {
+ return android::NO_MEMORY;
+ }
+
+ resourceHandle->data[0] = fd;
+ int ret = static_cast<SensorManager *>(manager)->createDirectChannel(
+ size, ASENSOR_DIRECT_CHANNEL_TYPE_SHARED_MEMORY, resourceHandle);
+ native_handle_delete(resourceHandle);
+ return ret;
+}
+
+int ASensorManager_createHardwareBufferDirectChannel(
+ ASensorManager *manager, AHardwareBuffer const *buffer, size_t size) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ if (buffer == nullptr) {
+ ERROR_INVALID_PARAMETER("buffer cannot be NULL");
+ return android::BAD_VALUE;
+ }
+
+ if (size < sizeof(ASensorEvent)) {
+ ERROR_INVALID_PARAMETER("size has to be greater or equal to sizeof(ASensorEvent).");
+ }
+
+ const native_handle_t *resourceHandle = AHardwareBuffer_getNativeHandle(buffer);
+ if (!resourceHandle) {
+ return android::NO_MEMORY;
+ }
+
+ return static_cast<SensorManager *>(manager)->createDirectChannel(
+ size, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER, resourceHandle);
+}
+
+void ASensorManager_destroyDirectChannel(ASensorManager *manager, int channelId) {
+ RETURN_IF_MANAGER_IS_NULL(void());
+
+ static_cast<SensorManager *>(manager)->destroyDirectChannel(channelId);
+}
+
+int ASensorManager_configureDirectReport(
+ ASensorManager *manager, ASensor const *sensor, int channelId, int rate) {
+ RETURN_IF_MANAGER_IS_NULL(android::BAD_VALUE);
+
+ int sensorHandle;
+ if (sensor == nullptr) {
+ if (rate != ASENSOR_DIRECT_RATE_STOP) {
+ ERROR_INVALID_PARAMETER(
+ "sensor cannot be null when rate is not ASENSOR_DIRECT_RATE_STOP");
+ return android::BAD_VALUE;
+ }
+ sensorHandle = -1;
+ } else {
+ sensorHandle = static_cast<Sensor const *>(sensor)->getHandle();
+ }
+ return static_cast<SensorManager *>(manager)->configureDirectChannel(
+ channelId, sensorHandle, rate);
+}
+
/*****************************************************************************/
int ASensorEventQueue_registerSensor(ASensorEventQueue* queue, ASensor const* sensor,
@@ -211,3 +300,13 @@ bool ASensor_isWakeUpSensor(ASensor const* sensor)
{
return static_cast<Sensor const*>(sensor)->isWakeUpSensor();
}
+
+bool ASensor_isDirectChannelTypeSupported(ASensor const *sensor, int channelType) {
+ RETURN_IF_SENSOR_IS_NULL(false);
+ return static_cast<Sensor const *>(sensor)->isDirectChannelTypeSupported(channelType);
+}
+
+int ASensor_getHighestDirectReportRateLevel(ASensor const *sensor) {
+ RETURN_IF_SENSOR_IS_NULL(ASENSOR_DIRECT_RATE_STOP);
+ return static_cast<Sensor const *>(sensor)->getHighestDirectReportRateLevel();
+}
diff --git a/packages/SettingsLib/res/layout/drawer_category.xml b/packages/SettingsLib/res/layout/drawer_category.xml
deleted file mode 100644
index 72cfddb1a431..000000000000
--- a/packages/SettingsLib/res/layout/drawer_category.xml
+++ /dev/null
@@ -1,38 +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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:paddingTop="8dp"
- android:orientation="vertical">
-
- <View
- android:layout_width="match_parent"
- android:layout_height="1dp"
- android:background="?android:attr/listDivider" />
-
- <TextView
- style="@style/TextAppearanceSmall"
- android:id="@android:id/title"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:paddingTop="16dp"
- android:paddingBottom="16dp"
- android:paddingStart="16dp" />
-
-</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/drawer_item.xml b/packages/SettingsLib/res/layout/drawer_item.xml
deleted file mode 100644
index d492ddfee0fe..000000000000
--- a/packages/SettingsLib/res/layout/drawer_item.xml
+++ /dev/null
@@ -1,44 +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.
--->
-<LinearLayout
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/tile_item"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:minHeight="48dp"
- android:orientation="horizontal" >
-
- <ImageView
- android:id="@android:id/icon"
- android:layout_width="@dimen/drawer_icon_size"
- android:layout_height="@dimen/drawer_icon_size"
- android:layout_marginStart="@dimen/drawer_icon_margin"
- android:layout_marginEnd="@dimen/drawer_icon_margin"
- android:layout_marginTop="@dimen/drawer_item_top_bottom_margin"
- android:layout_marginBottom="@dimen/drawer_item_top_bottom_margin"
- android:scaleType="fitCenter"
- android:layout_gravity="center_vertical"
- android:tint="?android:attr/colorAccent"/>
-
- <TextView
- android:textAppearance="@style/TextAppearanceMedium"
- android:id="@android:id/title"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textColor="?android:attr/colorControlNormal" />
-
-</LinearLayout>
diff --git a/packages/SettingsLib/res/layout/drawer_spacer.xml b/packages/SettingsLib/res/layout/drawer_spacer.xml
deleted file mode 100644
index 98120cf904d0..000000000000
--- a/packages/SettingsLib/res/layout/drawer_spacer.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<!--
- Copyright (C) 2016 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<Space
- xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/spacer"
- android:layout_width="match_parent"
- android:layout_height="@dimen/drawer_spacer_height" />
diff --git a/packages/SettingsLib/res/layout/settings_with_drawer.xml b/packages/SettingsLib/res/layout/settings_with_drawer.xml
index b659cee03780..e9c175f6fed0 100644
--- a/packages/SettingsLib/res/layout/settings_with_drawer.xml
+++ b/packages/SettingsLib/res/layout/settings_with_drawer.xml
@@ -47,13 +47,4 @@
android:layout_height="fill_parent"
android:background="?android:attr/windowBackground" />
</LinearLayout>
- <!-- The navigation drawer -->
- <ListView android:id="@+id/left_drawer"
- android:layout_width="@dimen/drawer_width"
- android:layout_height="match_parent"
- android:layout_gravity="start"
- android:choiceMode="singleChoice"
- android:divider="@android:color/transparent"
- android:dividerHeight="0dp"
- android:background="?android:attr/colorBackground" />
</android.support.v4.widget.DrawerLayout>
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
index ee69b56ef472..64f21b50c0bc 100755
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -26,9 +26,6 @@
<!-- Whether to send a custom package name with the PSD.-->
<bool name="config_sendPackageName">false</bool>
- <!-- Whether to enable the left nav drawer in all Settings UI.-->
- <bool name="config_enable_nav_drawer">false</bool>
-
<!-- Name for the set of keys associating package names -->
<string name="config_helpPackageNameKey" translatable="false"></string>
diff --git a/packages/SettingsLib/res/values/dimens.xml b/packages/SettingsLib/res/values/dimens.xml
index aa3661707130..3322839ee213 100644
--- a/packages/SettingsLib/res/values/dimens.xml
+++ b/packages/SettingsLib/res/values/dimens.xml
@@ -51,12 +51,6 @@
<dimen name="usage_graph_dot_size">.75dp</dimen>
<dimen name="usage_graph_dot_interval">7dp</dimen>
- <dimen name="drawer_icon_size">24dp</dimen>
- <dimen name="normal_icon_size">24dp</dimen>
- <dimen name="drawer_icon_margin">24dp</dimen>
- <dimen name="drawer_width">300dp</dimen>
- <dimen name="drawer_item_top_bottom_margin">4dp</dimen>
- <dimen name="drawer_spacer_height">32dp</dimen>
<dimen name="battery_height">14.5dp</dimen>
<dimen name="battery_width">9.5dp</dimen>
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
index a8cab17b0fac..457ce76d79ac 100644
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
+++ b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
@@ -5,7 +5,7 @@
* 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
+ * 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,
@@ -18,7 +18,6 @@ package com.android.settingslib.drawer;
import android.annotation.LayoutRes;
import android.annotation.Nullable;
import android.app.Activity;
-import android.content.ActivityNotFoundException;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -29,20 +28,15 @@ import android.content.res.TypedArray;
import android.os.AsyncTask;
import android.os.Bundle;
import android.provider.Settings;
-import android.support.v4.widget.DrawerLayout;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
-import android.view.Gravity;
import android.view.LayoutInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager.LayoutParams;
-import android.widget.AdapterView;
import android.widget.FrameLayout;
-import android.widget.ListView;
import android.widget.Toolbar;
import com.android.settingslib.R;
@@ -67,10 +61,7 @@ public class SettingsDrawerActivity extends Activity {
private final PackageReceiver mPackageReceiver = new PackageReceiver();
private final List<CategoryListener> mCategoryListeners = new ArrayList<>();
- private SettingsDrawerAdapter mDrawerAdapter;
private FrameLayout mContentHeaderContainer;
- private DrawerLayout mDrawerLayout;
- private boolean mShowingMenu;
// Remove below after new IA
@Deprecated
@@ -94,122 +85,50 @@ public class SettingsDrawerActivity extends Activity {
}
super.setContentView(R.layout.settings_with_drawer);
mContentHeaderContainer = (FrameLayout) findViewById(R.id.content_header_container);
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- if (mDrawerLayout == null) {
- return;
- }
+
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
toolbar.setVisibility(View.GONE);
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- mDrawerLayout = null;
return;
}
- if (!isNavDrawerEnabled()) {
- setIsDrawerPresent(false);
- }
- if (!isDashboardFeatureEnabled()) {
- getDashboardCategories();
- }
setActionBar(toolbar);
- mDrawerAdapter = new SettingsDrawerAdapter(this);
- ListView listView = (ListView) findViewById(R.id.left_drawer);
- listView.setAdapter(mDrawerAdapter);
- listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
- public void onItemClick(android.widget.AdapterView<?> parent, View view, int position,
- long id) {
- onTileClicked(mDrawerAdapter.getTile(position));
- }
- });
- if (DEBUG_TIMING) Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
- + " ms");
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- if (mShowingMenu && mDrawerLayout != null && item.getItemId() == android.R.id.home
- && mDrawerAdapter.getCount() != 0) {
- openDrawer();
- return true;
+ if (DEBUG_TIMING) {
+ Log.d(TAG, "onCreate took " + (System.currentTimeMillis() - startTime)
+ + " ms");
}
- return super.onOptionsItemSelected(item);
}
@Override
public boolean onNavigateUp() {
- if (!isNavDrawerEnabled()) {
- finish();
- return true;
- }
- return super.onNavigateUp();
+ finish();
+ return true;
}
@Override
protected void onResume() {
super.onResume();
-
- if (mDrawerLayout != null) {
- final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
- filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
- filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
- filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
- filter.addDataScheme("package");
- registerReceiver(mPackageReceiver, filter);
-
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
- }
+ final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+ filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+ filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+ filter.addDataScheme("package");
+ registerReceiver(mPackageReceiver, filter);
+
+ new CategoriesUpdateTask().execute();
final Intent intent = getIntent();
- if (intent != null) {
- if (intent.hasExtra(EXTRA_SHOW_MENU)) {
- if (intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
- // Intent explicitly set to show menu.
- showMenuIcon();
- }
- } else if (isNavDrawerEnabled() && isTopLevelTile(intent)) {
- showMenuIcon();
- }
+ if (intent != null && intent.getBooleanExtra(EXTRA_SHOW_MENU, false)) {
+ // Intent explicitly set to show menu.
+ showMenuIcon();
}
}
@Override
protected void onPause() {
- if (mDrawerLayout != null) {
- unregisterReceiver(mPackageReceiver);
- }
-
+ unregisterReceiver(mPackageReceiver);
super.onPause();
}
- private boolean isTopLevelTile(Intent intent) {
- final ComponentName componentName = intent.getComponent();
- if (componentName == null) {
- return false;
- }
- if (isDashboardFeatureEnabled()) {
- final DashboardCategory homepageCategories = CategoryManager.get(this)
- .getTilesByCategory(this, CategoryKey.CATEGORY_HOMEPAGE, getSettingPkg());
- return homepageCategories ==
- null ? false : homepageCategories.containsComponent(componentName);
- } else {
- // Look for a tile that has the same component as incoming intent
- final List<DashboardCategory> categories = getDashboardCategories();
- for (DashboardCategory category : categories) {
- if (category.containsComponent(componentName)) {
- return true;
- }
- }
- if (DEBUG) {
- Log.d(TAG, "Intent is not for top level settings " + intent);
- }
- return false;
- }
- }
-
/**
* Gets the name of the intent action of the default setting app. Used to launch setting app
* when Settings Home is clicked.
@@ -226,30 +145,6 @@ public class SettingsDrawerActivity extends Activity {
mCategoryListeners.remove(listener);
}
- public void setIsDrawerPresent(boolean isPresent) {
- if (isPresent) {
- mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- updateDrawer();
- } else {
- if (mDrawerLayout != null) {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- mDrawerLayout = null;
- }
- }
- }
-
- public void openDrawer() {
- if (mDrawerLayout != null) {
- mDrawerLayout.openDrawer(Gravity.START);
- }
- }
-
- public void closeDrawer() {
- if (mDrawerLayout != null) {
- mDrawerLayout.closeDrawers();
- }
- }
-
public void setContentHeaderView(View headerView) {
mContentHeaderContainer.removeAllViews();
if (headerView != null) {
@@ -276,31 +171,8 @@ public class SettingsDrawerActivity extends Activity {
((ViewGroup) findViewById(R.id.content_frame)).addView(view, params);
}
- public void updateDrawer() {
- if (mDrawerLayout == null) {
- return;
- }
- // TODO: Do this in the background with some loading.
- if (isDashboardFeatureEnabled()) {
- mDrawerAdapter.updateHomepageCategories(getSettingPkg());
- } else {
- mDrawerAdapter.updateCategories();
- }
- if (mDrawerAdapter.getCount() != 0) {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
- } else {
- mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
- }
- }
-
public void showMenuIcon() {
getActionBar().setDisplayHomeAsUpEnabled(true);
- if (isNavDrawerEnabled()) {
- mShowingMenu = true;
- getActionBar().setHomeAsUpIndicator(R.drawable.ic_menu);
- getActionBar().setHomeActionContentDescription(
- R.string.content_description_menu_button);
- }
}
public List<DashboardCategory> getDashboardCategories() {
@@ -315,51 +187,12 @@ public class SettingsDrawerActivity extends Activity {
}
protected void onCategoriesChanged() {
- updateDrawer();
final int N = mCategoryListeners.size();
for (int i = 0; i < N; i++) {
mCategoryListeners.get(i).onCategoriesChanged();
}
}
- @Deprecated
- public boolean openTile(Tile tile) {
- closeDrawer();
- if (tile == null) {
- Intent intent = new Intent(getSettingAction()).addFlags(
- Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(intent);
- return true;
- }
- try {
- ProfileSelectDialog.updateUserHandlesIfNeeded(this /* context */, tile);
- int numUserHandles = tile.userHandle.size();
- if (numUserHandles > 1) {
- ProfileSelectDialog.show(getFragmentManager(), tile);
- return false;
- } else if (numUserHandles == 1) {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivityAsUser(tile.intent, tile.userHandle.get(0));
- } else {
- // Show menu on top level items.
- tile.intent.putExtra(EXTRA_SHOW_MENU, true);
- tile.intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
- startActivity(tile.intent);
- }
- } catch (ActivityNotFoundException e) {
- Log.w(TAG, "Couldn't find tile " + tile.intent, e);
- }
- return true;
- }
-
- protected void onTileClicked(Tile tile) {
- if (openTile(tile)) {
- finish();
- }
- }
-
public void onProfileTileOpen() {
finish();
}
@@ -375,8 +208,8 @@ public class SettingsDrawerActivity extends Activity {
sTileBlacklist.add(component);
}
pm.setComponentEnabledSetting(component, enabled
- ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+ ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+ : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);
}
}
@@ -385,11 +218,7 @@ public class SettingsDrawerActivity extends Activity {
* Updates dashboard categories. Only necessary to call this after setTileEnabled
*/
public void updateCategories() {
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
+ new CategoriesUpdateTask().execute();
}
public String getSettingPkg() {
@@ -400,42 +229,6 @@ public class SettingsDrawerActivity extends Activity {
void onCategoriesChanged();
}
- /**
- * @deprecated remove after new IA
- */
- @Deprecated
- private class CategoriesUpdater extends AsyncTask<Void, Void, List<DashboardCategory>> {
- @Override
- protected List<DashboardCategory> doInBackground(Void... params) {
- if (sConfigTracker.applyNewConfig(getResources())) {
- sTileCache.clear();
- }
- return TileUtils.getCategories(SettingsDrawerActivity.this, sTileCache);
- }
-
- @Override
- protected void onPreExecute() {
- if (sConfigTracker == null || sTileCache == null) {
- getDashboardCategories();
- }
- }
-
- @Override
- protected void onPostExecute(List<DashboardCategory> dashboardCategories) {
- for (int i = 0; i < dashboardCategories.size(); i++) {
- DashboardCategory category = dashboardCategories.get(i);
- for (int j = 0; j < category.tiles.size(); j++) {
- Tile tile = category.tiles.get(j);
- if (sTileBlacklist.contains(tile.intent.getComponent())) {
- category.tiles.remove(j--);
- }
- }
- }
- sDashboardCategories = dashboardCategories;
- onCategoriesChanged();
- }
- }
-
private class CategoriesUpdateTask extends AsyncTask<Void, Void, Void> {
private final CategoryManager mCategoryManager;
@@ -457,25 +250,10 @@ public class SettingsDrawerActivity extends Activity {
}
}
- /**
- * @return {@code true} if IA (Information Architecture) is enabled.
- */
- protected boolean isDashboardFeatureEnabled() {
- return false;
- }
-
- boolean isNavDrawerEnabled() {
- return getResources().getBoolean(R.bool.config_enable_nav_drawer);
- }
-
private class PackageReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- if (isDashboardFeatureEnabled()) {
- new CategoriesUpdateTask().execute();
- } else {
- new CategoriesUpdater().execute();
- }
+ new CategoriesUpdateTask().execute();
}
}
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java b/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
deleted file mode 100644
index 75942f93b67b..000000000000
--- a/packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerAdapter.java
+++ /dev/null
@@ -1,147 +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 com.android.settingslib.drawer;
-
-import android.graphics.drawable.Icon;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.android.settingslib.R;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class SettingsDrawerAdapter extends BaseAdapter {
-
- private final ArrayList<Item> mItems = new ArrayList<>();
- private final SettingsDrawerActivity mActivity;
-
- public SettingsDrawerAdapter(SettingsDrawerActivity activity) {
- mActivity = activity;
- }
-
- /**
- * @deprecated Remove after new IA
- */
- @Deprecated
- void updateCategories() {
- List<DashboardCategory> categories = mActivity.getDashboardCategories();
- mItems.clear();
- // Spacer.
- mItems.add(null);
- Item tile = new Item();
- tile.label = mActivity.getString(R.string.home);
- tile.icon = Icon.createWithResource(mActivity, R.drawable.home);
- mItems.add(tile);
- for (int i = 0; i < categories.size(); i++) {
- Item category = new Item();
- category.icon = null;
- DashboardCategory dashboardCategory = categories.get(i);
- category.label = dashboardCategory.title;
- mItems.add(category);
- for (int j = 0; j < dashboardCategory.tiles.size(); j++) {
- tile = new Item();
- Tile dashboardTile = dashboardCategory.tiles.get(j);
- tile.label = dashboardTile.title;
- tile.icon = dashboardTile.icon;
- tile.tile = dashboardTile;
- mItems.add(tile);
- }
- }
- notifyDataSetChanged();
- }
-
- public void updateHomepageCategories(String settingPkg) {
- final DashboardCategory category = CategoryManager.get(mActivity)
- .getTilesByCategory(mActivity, CategoryKey.CATEGORY_HOMEPAGE, settingPkg);
- mItems.clear();
- // Spacer.
- mItems.add(null);
- Item tile = new Item();
- tile.label = mActivity.getString(R.string.home);
- tile.icon = Icon.createWithResource(mActivity, R.drawable.home);
- mItems.add(tile);
- for (int j = 0; j < category.tiles.size(); j++) {
- tile = new Item();
- Tile dashboardTile = category.tiles.get(j);
- tile.label = dashboardTile.title;
- tile.icon = dashboardTile.icon;
- tile.tile = dashboardTile;
- mItems.add(tile);
- }
- notifyDataSetChanged();
- }
-
- public Tile getTile(int position) {
- return mItems.get(position) != null ? mItems.get(position).tile : null;
- }
-
- @Override
- public int getCount() {
- return mItems.size();
- }
-
- @Override
- public Object getItem(int position) {
- return mItems.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return position;
- }
-
- @Override
- public boolean isEnabled(int position) {
- return mItems.get(position) != null && mItems.get(position).icon != null;
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- Item item = mItems.get(position);
- if (item == null) {
- if (convertView == null || convertView.getId() != R.id.spacer) {
- convertView = LayoutInflater.from(mActivity).inflate(R.layout.drawer_spacer,
- parent, false);
- }
- return convertView;
- }
- if (convertView != null && convertView.getId() == R.id.spacer) {
- convertView = null;
- }
- boolean isTile = item.icon != null;
- if (convertView == null || (isTile != (convertView.getId() == R.id.tile_item))) {
- convertView = LayoutInflater.from(mActivity).inflate(isTile ? R.layout.drawer_item
- : R.layout.drawer_category,
- parent, false);
- }
- if (isTile) {
- ((ImageView) convertView.findViewById(android.R.id.icon)).setImageIcon(item.icon);
- }
- ((TextView) convertView.findViewById(android.R.id.title)).setText(item.label);
- return convertView;
- }
-
- private static class Item {
- public Icon icon;
- public CharSequence label;
- public Tile tile;
- }
-}
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
index c3f2f736b441..752b5b0e152c 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/drawer/SettingsDrawerActivityTest.java
@@ -86,16 +86,6 @@ public class SettingsDrawerActivityTest {
.check(matches(isDisplayed()));
}
- @Test
- public void startActivity_shouldNotHaveNavDrawer() {
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- Activity activity = instrumentation.startActivitySync(
- new Intent(instrumentation.getTargetContext(), TestActivity.class));
-
- assertThat(((SettingsDrawerActivity) activity).isNavDrawerEnabled())
- .isFalse();
- }
-
/**
* Test Activity in this test.
*
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index f31555327b01..e8df38bb964b 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -167,7 +167,7 @@ class BluetoothManagerService extends IBluetoothManager.Stub {
}
public String toString() {
- return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) +
+ return android.text.format.DateFormat.format("MM-dd HH:mm:ss ", mTimestamp) +
(mEnable ? " Enabled " : " Disabled ") + " by " + mPackageName;
}
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index b95ed08eeb27..69e481fc9e1c 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -28,6 +28,7 @@ import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController;
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;
import com.android.internal.inputmethod.InputMethodUtils;
import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.HandlerCaller;
import com.android.internal.os.SomeArgs;
import com.android.internal.os.TransferPipe;
@@ -1262,13 +1263,14 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
Bundle extras = new Bundle();
extras.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, true);
- mImeSwitcherNotification = new Notification.Builder(mContext)
- .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
- .setWhen(0)
- .setOngoing(true)
- .addExtras(extras)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setColor(com.android.internal.R.color.system_notification_accent_color);
+ mImeSwitcherNotification =
+ new Notification.Builder(mContext, SystemNotificationChannels.VIRTUAL_KEYBOARD)
+ .setSmallIcon(com.android.internal.R.drawable.ic_notification_ime_default)
+ .setWhen(0)
+ .setOngoing(true)
+ .addExtras(extras)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setColor(com.android.internal.R.color.system_notification_accent_color);
Intent intent = new Intent(Settings.ACTION_SHOW_INPUT_METHOD_PICKER);
mImeSwitchPendingIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0);
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index f76ddc71bc01..0a9610f36abb 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -76,6 +76,7 @@ import android.util.Log;
import android.util.Slog;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.widget.ICheckCredentialProgressCallback;
import com.android.internal.widget.ILockSettings;
@@ -442,21 +443,20 @@ public class LockSettingsService extends ILockSettings.Stub {
// Suppress all notifications on non-FBE devices for now
if (!StorageManager.isFileEncryptedNativeOrEmulated()) return;
- Notification notification = new Notification.Builder(mContext)
- .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
- .setWhen(0)
- .setOngoing(true)
- .setTicker(title)
- .setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_MAX)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(message)
- .setSubText(detail)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setContentIntent(intent)
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.SECURITY)
+ .setSmallIcon(com.android.internal.R.drawable.ic_user_secure)
+ .setWhen(0)
+ .setOngoing(true)
+ .setTicker(title)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(message)
+ .setSubText(detail)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setContentIntent(intent)
+ .build();
mNotificationManager.notifyAsUser(null, FBE_ENCRYPTED_NOTIFICATION, notification, user);
}
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index d54ebaafb5bb..b83dbd686ae5 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -663,12 +663,12 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
@Override
public boolean setActiveScorer(String packageName) {
// Only the system can set the active scorer
- if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
- return mNetworkScorerAppManager.setActiveScorer(packageName);
- } else {
+ if (!isCallerSystemProcess(getCallingUid()) || !callerCanRequestScores()) {
throw new SecurityException(
"Caller is neither the system process nor a score requester.");
}
+
+ return mNetworkScorerAppManager.setActiveScorer(packageName);
}
/**
@@ -732,23 +732,23 @@ public class NetworkScoreService extends INetworkScoreService.Stub {
@Override
public List<NetworkScorerAppData> getAllValidScorers() {
// Only the system can access this data.
- if (isCallerSystemProcess(getCallingUid()) || callerCanRequestScores()) {
- return mNetworkScorerAppManager.getAllValidScorers();
- } else {
+ if (!isCallerSystemProcess(getCallingUid()) || !callerCanRequestScores()) {
throw new SecurityException(
"Caller is neither the system process nor a score requester.");
}
+
+ return mNetworkScorerAppManager.getAllValidScorers();
}
@Override
public void disableScoring() {
// Only the active scorer or the system should be allowed to disable scoring.
- if (isCallerActiveScorer(getCallingUid()) || callerCanRequestScores()) {
- // no-op for now but we could write to the setting if needed.
- } else {
+ if (!isCallerActiveScorer(getCallingUid()) || !callerCanRequestScores()) {
throw new SecurityException(
"Caller is neither the active scorer nor the scorer manager.");
}
+
+ // no-op for now but we could write to the setting if needed.
}
/** Clear scores. Callers are responsible for checking permissions as appropriate. */
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index acacb9e0be70..5115fdecd1bf 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -58,6 +58,7 @@ import java.util.Collections;
import com.android.internal.R;
import com.android.internal.app.DisableCarModeActivity;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.power.ShutdownThread;
import com.android.server.twilight.TwilightListener;
import com.android.server.twilight.TwilightManager;
@@ -739,7 +740,8 @@ final class UiModeManagerService extends SystemService {
if (mCarModeEnabled) {
Intent carModeOffIntent = new Intent(context, DisableCarModeActivity.class);
- Notification.Builder n = new Notification.Builder(context)
+ Notification.Builder n =
+ new Notification.Builder(context, SystemNotificationChannels.CAR_MODE)
.setSmallIcon(R.drawable.stat_notify_car_mode)
.setDefaults(Notification.DEFAULT_LIGHTS)
.setOngoing(true)
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 1b2c75d50014..dc73b6385897 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -92,6 +92,7 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.content.PackageMonitor;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -2780,16 +2781,17 @@ public class AccountManagerService
}
UserHandle user = UserHandle.of(userId);
Context contextForUser = getContextForUser(user);
- Notification n = new Notification.Builder(contextForUser)
- .setSmallIcon(android.R.drawable.stat_sys_warning)
- .setWhen(0)
- .setColor(contextForUser.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(subtitle)
- .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
- PendingIntent.FLAG_CANCEL_CURRENT, null, user))
- .build();
+ Notification n =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setWhen(0)
+ .setColor(contextForUser.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(subtitle)
+ .setContentIntent(PendingIntent.getActivityAsUser(mContext, 0, intent,
+ PendingIntent.FLAG_CANCEL_CURRENT, null, user))
+ .build();
installNotification(getCredentialPermissionNotificationId(
account, authTokenType, uid), n, packageName, user.getIdentifier());
}
@@ -4844,7 +4846,8 @@ public class AccountManagerService
final String notificationTitleFormat =
contextForUser.getText(R.string.notification_title).toString();
- Notification n = new Notification.Builder(contextForUser)
+ Notification n =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
.setWhen(0)
.setSmallIcon(android.R.drawable.stat_sys_warning)
.setColor(contextForUser.getColor(
@@ -4864,6 +4867,7 @@ public class AccountManagerService
private void installNotification(int notificationId, final Notification notification,
String packageName, int userId) {
+ SystemNotificationChannels.createAccountChannelForPackage(packageName, mContext);
final long token = clearCallingIdentity();
try {
INotificationManager notificationManager = mInjector.getNotificationManager();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2bc131fae905..b4f8f61971f8 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -2810,14 +2810,13 @@ public final class ActiveServices {
}
List<ActivityManager.RunningServiceInfo> getRunningServiceInfoLocked(int maxNum, int flags,
- int callingUid, boolean allowed) {
+ int callingUid, boolean allowed, boolean canInteractAcrossUsers) {
ArrayList<ActivityManager.RunningServiceInfo> res
= new ArrayList<ActivityManager.RunningServiceInfo>();
final long ident = Binder.clearCallingIdentity();
try {
- if (ActivityManager.checkUidPermission(INTERACT_ACROSS_USERS_FULL, callingUid)
- == PERMISSION_GRANTED) {
+ if (canInteractAcrossUsers) {
int[] users = mAm.mUserController.getUsers();
for (int ui=0; ui<users.length && res.size() < maxNum; ui++) {
ArrayMap<ComponentName, ServiceRecord> alls = getServicesLocked(users[ui]);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 67cac981f599..2f2b533a531d 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -314,6 +314,7 @@ import android.view.LayoutInflater;
import android.view.View;
import android.view.WindowManager;
+import com.android.internal.notification.SystemNotificationChannels;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
@@ -1972,7 +1973,8 @@ public class ActivityManagerService extends IActivityManager.Stub
Context context = mContext.createPackageContext(process.info.packageName, 0);
String text = mContext.getString(R.string.heavy_weight_notification,
context.getApplicationInfo().loadLabel(context.getPackageManager()));
- Notification notification = new Notification.Builder(context)
+ Notification notification =
+ new Notification.Builder(context, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
@@ -2222,7 +2224,8 @@ public class ActivityManagerService extends IActivityManager.Stub
intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
}
int userId = UserHandle.getUserId(uid);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
@@ -17506,12 +17509,15 @@ public class ActivityManagerService extends IActivityManager.Stub
public List<ActivityManager.RunningServiceInfo> getServices(int maxNum,
int flags) {
enforceNotIsolatedCaller("getServices");
- synchronized (this) {
- final int callingUid = Binder.getCallingUid();
- final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
- callingUid);
- return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid, allowed);
+ final int callingUid = Binder.getCallingUid();
+ final boolean canInteractAcrossUsers = (ActivityManager.checkUidPermission(
+ INTERACT_ACROSS_USERS_FULL, callingUid) == PERMISSION_GRANTED);
+ final boolean allowed = isGetTasksAllowed("getServices", Binder.getCallingPid(),
+ callingUid);
+ synchronized (this) {
+ return mServices.getRunningServiceInfoLocked(maxNum, flags, callingUid,
+ allowed, canInteractAcrossUsers);
}
}
diff --git a/services/core/java/com/android/server/am/PreBootBroadcaster.java b/services/core/java/com/android/server/am/PreBootBroadcaster.java
index f4f6b661c0e1..e0d3abd03988 100644
--- a/services/core/java/com/android/server/am/PreBootBroadcaster.java
+++ b/services/core/java/com/android/server/am/PreBootBroadcaster.java
@@ -35,6 +35,7 @@ import android.os.UserHandle;
import android.util.Slog;
import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ProgressReporter;
import com.android.server.UiThread;
@@ -144,13 +145,13 @@ public abstract class PreBootBroadcaster extends IIntentReceiver.Stub {
contentIntent = null;
}
- final Notification notif = new Notification.Builder(mService.mContext)
+ final Notification notif =
+ new Notification.Builder(mService.mContext,
+ SystemNotificationChannels.UPDATES)
.setSmallIcon(R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
- .setDefaults(0)
- .setPriority(Notification.PRIORITY_MAX)
.setColor(context.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 82b00da5b809..dfbe59f1c8f2 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -115,7 +115,7 @@ final class ServiceRecord extends Binder {
long destroyTime; // time at which destory was initiated.
String stringName; // caching of toString
-
+
private int lastStartId; // identifier of most recent start request.
static class StartItem {
@@ -203,7 +203,7 @@ final class ServiceRecord extends Binder {
}
}
}
-
+
void dump(PrintWriter pw, String prefix) {
pw.print(prefix); pw.print("intent={");
pw.print(intent.getIntent().toShortString(false, true, false, true));
@@ -413,7 +413,7 @@ final class ServiceRecord extends Binder {
restartDelay = 0;
restartTime = 0;
}
-
+
public StartItem findDeliveredStart(int id, boolean remove) {
final int N = deliveredStarts.size();
for (int i=0; i<N; i++) {
@@ -423,10 +423,10 @@ final class ServiceRecord extends Binder {
return si;
}
}
-
+
return null;
}
-
+
public int getLastStartId() {
return lastStartId;
}
@@ -478,7 +478,8 @@ final class ServiceRecord extends Binder {
ctx = ams.mContext.createPackageContextAsUser(
appInfo.packageName, 0, new UserHandle(userId));
- Notification.Builder notiBuilder = new Notification.Builder(ctx);
+ Notification.Builder notiBuilder = new Notification.Builder(ctx,
+ localForegroundNoti.getChannel());
// it's ugly, but it clearly identifies the app
notiBuilder.setSmallIcon(appInfo.icon);
@@ -486,9 +487,6 @@ final class ServiceRecord extends Binder {
// mark as foreground
notiBuilder.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true);
- // we are doing the app a kindness here
- notiBuilder.setPriority(Notification.PRIORITY_MIN);
-
Intent runningIntent = new Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
runningIntent.setData(Uri.fromParts("package",
@@ -541,7 +539,7 @@ final class ServiceRecord extends Binder {
});
}
}
-
+
public void cancelNotification() {
// Do asynchronous communication with notification manager to
// avoid deadlocks.
@@ -588,7 +586,7 @@ final class ServiceRecord extends Binder {
}
});
}
-
+
public void clearDeliveredStartsLocked() {
for (int i=deliveredStarts.size()-1; i>=0; i--) {
deliveredStarts.get(i).removeUriPermissionsLocked();
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index d648dd82dc9a..4404dcf5e01c 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -152,9 +152,11 @@ public final class PlaybackActivityMonitor
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (checkConfigurationCaller(piid, apc, binderUid)) {
- apc.getPlayerProxy().applyVolumeShaper(
- DUCK_ID,
- TERMINATE);
+ try {
+ apc.getPlayerProxy().applyVolumeShaper(
+ DUCK_ID,
+ TERMINATE);
+ } catch (Exception e) { /* silent failure, happens happens with binder failure */ }
mPlayers.remove(new Integer(piid));
} else {
Log.e(TAG, "Error releasing player " + piid);
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 68fe5053b585..83751a9c15df 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -32,6 +32,7 @@ import android.widget.Toast;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.notification.SystemNotificationChannels;
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
@@ -187,7 +188,9 @@ public class NetworkNotificationManager {
return;
}
- Notification.Builder builder = new Notification.Builder(mContext)
+ final String channelId = highPriority ? SystemNotificationChannels.NETWORK_ALERTS :
+ SystemNotificationChannels.NETWORK_STATUS;
+ Notification.Builder builder = new Notification.Builder(mContext, channelId)
.setWhen(System.currentTimeMillis())
.setShowWhen(notifyType == NotificationType.NETWORK_SWITCH)
.setSmallIcon(icon)
@@ -198,10 +201,6 @@ public class NetworkNotificationManager {
.setContentTitle(title)
.setContentIntent(intent)
.setLocalOnly(true)
- .setPriority(highPriority ?
- Notification.PRIORITY_HIGH :
- Notification.PRIORITY_DEFAULT)
- .setDefaults(highPriority ? Notification.DEFAULT_ALL : 0)
.setOnlyAlertOnce(true);
if (notifyType == NotificationType.NETWORK_SWITCH) {
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 6c608a28089d..39e3758393df 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -66,6 +66,7 @@ import android.util.Log;
import android.util.SparseArray;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.TelephonyIntents;
import com.android.internal.util.IndentingPrintWriter;
@@ -668,7 +669,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
tethered_notification_message);
if (mTetheredNotificationBuilder == null) {
- mTetheredNotificationBuilder = new Notification.Builder(mContext);
+ mTetheredNotificationBuilder =
+ new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS);
mTetheredNotificationBuilder.setWhen(0)
.setOngoing(true)
.setColor(mContext.getColor(
@@ -950,6 +952,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
// Events from NetworkCallbacks that we process on the master state
// machine thread on behalf of the UpstreamNetworkMonitor.
static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5;
+ // we treated the error and want now to clear it
+ static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
private State mInitialState;
private State mTetherModeAliveState;
@@ -1491,6 +1495,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
who.sendMessage(mErrorNotification);
break;
+ case CMD_CLEAR_ERROR:
+ mErrorNotification = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ transitionTo(mInitialState);
+ break;
default:
retValue = false;
}
@@ -1635,6 +1643,12 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering
// Not really very much we can do here.
}
+ // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
+ // Thus we give a chance for TetherMasterSM to recover to InitialState
+ // by sending CMD_CLEAR_ERROR
+ if (error == ConnectivityManager.TETHER_ERROR_MASTER_ERROR) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+ }
switch (state) {
case IControlsTethering.STATE_UNAVAILABLE:
case IControlsTethering.STATE_AVAILABLE:
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index b963555124ab..9fc2fc7bb31e 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -85,6 +85,7 @@ import com.android.internal.net.LegacyVpnInfo;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnInfo;
import com.android.internal.net.VpnProfile;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.DeviceIdleController;
import com.android.server.LocalServices;
import com.android.server.net.BaseNetworkObserver;
@@ -1293,17 +1294,16 @@ public class Vpn {
mContext, /* request */ 0, intent,
PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT,
null, user);
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setDefaults(0)
- .setSmallIcon(R.drawable.vpn_connected)
- .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
- .setContentText(mContext.getString(R.string.vpn_lockdown_config))
- .setContentIntent(configIntent)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setPriority(Notification.PRIORITY_LOW)
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setOngoing(true)
- .setColor(mContext.getColor(R.color.system_notification_accent_color));
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+ .setSmallIcon(R.drawable.vpn_connected)
+ .setContentTitle(mContext.getString(R.string.vpn_lockdown_disconnected))
+ .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+ .setContentIntent(configIntent)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setOngoing(true)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color));
notificationManager.notifyAsUser(TAG, 0, builder.build(), user);
} finally {
Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 5e5157913f20..710ab33874cd 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -167,7 +167,8 @@ public class TetherInterfaceStateMachine extends StateMachine {
private void maybeLogMessage(State state, int what) {
if (DBG) {
Log.d(TAG, state.getName() + " got " +
- sMagicDecoderRing.get(what, Integer.toString(what)));
+ sMagicDecoderRing.get(what, Integer.toString(what)) + ", Iface = " +
+ mIfaceName);
}
}
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 5b539ff1976d..bbad493a913f 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -81,6 +81,7 @@ import android.util.Log;
import android.util.Pair;
import android.util.Slog;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.server.LocalServices;
import com.android.server.job.JobSchedulerInternal;
@@ -3250,7 +3251,8 @@ public class SyncManager {
R.string.contentServiceTooManyDeletesNotificationDesc);
Context contextForUser = getContextForUser(user);
- Notification notification = new Notification.Builder(contextForUser)
+ Notification notification =
+ new Notification.Builder(contextForUser, SystemNotificationChannels.ACCOUNT)
.setSmallIcon(R.drawable.stat_notify_sync_error)
.setTicker(mContext.getString(R.string.contentServiceSync))
.setWhen(System.currentTimeMillis())
@@ -3460,4 +3462,4 @@ public class SyncManager {
return mContext;
}
}
-} \ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 5a1e44574e13..43bb21d2b44a 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -68,7 +68,9 @@ public abstract class ClientMonitor implements IBinder.DeathRecipient {
mIsRestricted = restricted;
mOwner = owner;
try {
- token.linkToDeath(this, 0);
+ if (token != null) {
+ token.linkToDeath(this, 0);
+ }
} catch (RemoteException e) {
Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 3793b911a038..297d5bd1afc9 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -23,6 +23,7 @@ import android.os.ShellCallback;
import android.util.Log;
import android.view.Display;
import com.android.internal.inputmethod.InputMethodSubtypeHandle;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
@@ -973,17 +974,17 @@ public class InputManagerService extends IInputManager.Stub
intent, 0, null, UserHandle.CURRENT);
Resources r = mContext.getResources();
- Notification notification = new Notification.Builder(mContext)
- .setContentTitle(r.getString(
- R.string.select_keyboard_layout_notification_title))
- .setContentText(r.getString(
- R.string.select_keyboard_layout_notification_message))
- .setContentIntent(keyboardLayoutIntent)
- .setSmallIcon(R.drawable.ic_settings_language)
- .setPriority(Notification.PRIORITY_LOW)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.PHYSICAL_KEYBOARD)
+ .setContentTitle(r.getString(
+ R.string.select_keyboard_layout_notification_title))
+ .setContentText(r.getString(
+ R.string.select_keyboard_layout_notification_message))
+ .setContentIntent(keyboardLayoutIntent)
+ .setSmallIcon(R.drawable.ic_settings_language)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .build();
mNotificationManager.notifyAsUser(null,
R.string.select_keyboard_layout_notification_title,
notification, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 4a8539aa3282..a5e7d7c7b945 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -47,6 +47,7 @@ import android.util.Slog;
import com.android.internal.R;
import com.android.internal.net.VpnConfig;
import com.android.internal.net.VpnProfile;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.Preconditions;
import com.android.server.ConnectivityService;
import com.android.server.EventLogTags;
@@ -330,18 +331,18 @@ public class LockdownVpnTracker {
}
private void showNotification(int titleRes, int iconRes) {
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setWhen(0)
- .setSmallIcon(iconRes)
- .setContentTitle(mContext.getString(titleRes))
- .setContentText(mContext.getString(R.string.vpn_lockdown_config))
- .setContentIntent(mConfigIntent)
- .setPriority(Notification.PRIORITY_LOW)
- .setOngoing(true)
- .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset),
- mResetIntent)
- .setColor(mContext.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.VPN)
+ .setWhen(0)
+ .setSmallIcon(iconRes)
+ .setContentTitle(mContext.getString(titleRes))
+ .setContentText(mContext.getString(R.string.vpn_lockdown_config))
+ .setContentIntent(mConfigIntent)
+ .setOngoing(true)
+ .addAction(R.drawable.ic_menu_refresh, mContext.getString(R.string.reset),
+ mResetIntent)
+ .setColor(mContext.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
NotificationManager.from(mContext).notify(TAG, 0, builder.build());
}
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index ac3a025a6fc0..507899836ee2 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -58,6 +58,8 @@ import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.computeLastCycleBoundary;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileIdleOrPowerSaveMode;
+import static android.net.NetworkPolicyManager.isProcStateAllowedWhileOnRestrictBackground;
import static android.net.NetworkPolicyManager.uidPoliciesToString;
import static android.net.NetworkPolicyManager.uidRulesToString;
import static android.net.NetworkTemplate.MATCH_MOBILE_3G_LOWER;
@@ -169,6 +171,7 @@ import android.util.Xml;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -1067,7 +1070,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
*/
private void enqueueNotification(NetworkPolicy policy, int type, long totalBytes) {
final String tag = buildNotificationTag(policy, type);
- final Notification.Builder builder = new Notification.Builder(mContext);
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.NETWORK_STATUS);
builder.setOnlyAlertOnce(true);
builder.setWhen(0L);
builder.setColor(mContext.getColor(
@@ -1085,7 +1089,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
builder.setContentTitle(title);
builder.setContentText(body);
builder.setDefaults(Notification.DEFAULT_ALL);
- builder.setPriority(Notification.PRIORITY_HIGH);
+ builder.setChannel(SystemNotificationChannels.NETWORK_ALERTS);
final Intent snoozeIntent = buildSnoozeWarningIntent(policy.template);
builder.setDeleteIntent(PendingIntent.getBroadcast(
@@ -2527,14 +2531,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
}
}
- static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
- return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
- }
-
- static boolean isProcStateAllowedWhileOnRestrictBackground(int procState) {
- return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
- }
-
void updateRulesForPowerSaveUL() {
Trace.traceBegin(Trace.TRACE_TAG_NETWORK, "updateRulesForPowerSaveUL");
try {
@@ -2608,8 +2604,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
// (mPowerSaveTempWhitelistAppIds) for whitelisting, we can reuse their logic in this method.
private void updateRulesForWhitelistedPowerSaveUL(int uid, boolean enabled, int chain) {
if (enabled) {
- if (isWhitelistedBatterySaverUL(uid)
- || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
+ if (isWhitelistedBatterySaverUL(uid) || isUidForegroundOnRestrictPowerUL(uid)) {
setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
} else {
setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 45ff20bd3a6d..dae5da3c6ceb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2736,9 +2736,10 @@ public class NotificationManagerService extends SystemService {
Notification.EXTRA_BUILDER_APPLICATION_INFO);
final Bundle extras = new Bundle();
extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
+ final String channelId = notificationRecord.getChannel().getId();
final Notification summaryNotification =
- new Notification.Builder(getContext()).setSmallIcon(
- adjustedSbn.getNotification().getSmallIcon())
+ new Notification.Builder(getContext(), channelId)
+ .setSmallIcon(adjustedSbn.getNotification().getSmallIcon())
.setGroupSummary(true)
.setGroup(GroupHelper.AUTOGROUP_KEY)
.setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
diff --git a/services/core/java/com/android/server/pm/InstantAppRegistry.java b/services/core/java/com/android/server/pm/InstantAppRegistry.java
index 55a5f725f90b..0ae5f314d473 100644
--- a/services/core/java/com/android/server/pm/InstantAppRegistry.java
+++ b/services/core/java/com/android/server/pm/InstantAppRegistry.java
@@ -438,6 +438,7 @@ class InstantAppRegistry {
bitmap = Bitmap.createBitmap(icon.getIntrinsicWidth(),
icon.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
+ icon.setBounds(0, 0, icon.getIntrinsicWidth(), icon.getIntrinsicHeight());
icon.draw(canvas);
}
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index a7a1683f8479..37f78b40c4ff 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -88,6 +88,7 @@ import libcore.io.IoUtils;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageHelper;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.ImageUtils;
import com.android.internal.util.IndentingPrintWriter;
@@ -1103,7 +1104,7 @@ public class PackageInstallerService extends IPackageInstaller.Stub {
context.getResources().getDimensionPixelSize(
android.R.dimen.notification_large_icon_height));
CharSequence packageLabel = packageInfo.applicationInfo.loadLabel(pm);
- return new Notification.Builder(context)
+ return new Notification.Builder(context, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(R.drawable.ic_check_circle_24px)
.setColor(context.getResources().getColor(
R.color.system_notification_accent_color))
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1c5675ac010e..fd731c323a74 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -29,6 +29,7 @@ import static com.android.server.pm.PackageInstallerService.prepareExternalStage
import static com.android.server.pm.PackageInstallerService.prepareStageDir;
import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
@@ -45,6 +46,7 @@ import android.content.pm.PackageParser.ApkLite;
import android.content.pm.PackageParser.PackageLite;
import android.content.pm.PackageParser.PackageParserException;
import android.content.pm.Signature;
+import android.content.pm.UserInfo;
import android.os.Binder;
import android.os.Bundle;
import android.os.FileBridge;
@@ -295,6 +297,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
info.active = mActiveCount.get() > 0;
info.mode = params.mode;
+ info.installReason = params.installReason;
info.sizeBytes = params.sizeBytes;
info.appPackageName = params.appPackageName;
info.appIcon = params.appIcon;
@@ -1139,6 +1142,25 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
}
final boolean success = (returnCode == PackageManager.INSTALL_SUCCEEDED);
+
+ // Send broadcast to default launcher only if it's a new install
+ final boolean isNewInstall = extras == null || !extras.getBoolean(Intent.EXTRA_REPLACING);
+ if (success && isNewInstall) {
+ UserManagerService ums = UserManagerService.getInstance();
+ if (ums != null) {
+ final UserInfo parent = ums.getProfileParent(userId);
+ final int launcherUid = (parent != null) ? parent.id : userId;
+ final ComponentName launcherComponent = mPm.getDefaultHomeActivity(launcherUid);
+ if (launcherComponent != null) {
+ Intent launcherIntent = new Intent(PackageInstaller.ACTION_SESSION_COMMITTED)
+ .putExtra(PackageInstaller.EXTRA_SESSION, generateInfo())
+ .putExtra(Intent.EXTRA_USER, UserHandle.of(userId))
+ .setPackage(launcherComponent.getPackageName());
+ mContext.sendBroadcastAsUser(launcherIntent, UserHandle.of(launcherUid));
+ }
+ }
+ }
+
mCallback.onSessionFinished(this, success);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 116c0a353643..838098310caf 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -582,7 +582,8 @@ public class PackageManagerService extends IPackageManager.Stub {
Manifest.permission.RECEIVE_MMS,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_NUMBER);
+ Manifest.permission.READ_PHONE_NUMBER,
+ Manifest.permission.ANSWER_PHONE_CALLS);
/**
@@ -6317,6 +6318,7 @@ public class PackageManagerService extends IPackageManager.Stub {
ephemeralInstaller.filter = new IntentFilter(intent.getAction());
ephemeralInstaller.filter.addDataPath(
intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
+ ephemeralInstaller.instantAppAvailable = true;
result.add(ephemeralInstaller);
}
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
@@ -7310,12 +7312,17 @@ public class PackageManagerService extends IPackageManager.Stub {
return false;
}
- if (!isCallerSameApp(packageName)) {
- return false;
- }
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null) {
+ final boolean returnAllowed =
+ ps != null
+ && (isCallerSameApp(packageName)
+ || mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.ACCESS_INSTANT_APPS)
+ == PERMISSION_GRANTED
+ || mInstantAppRegistry.isInstantAccessGranted(
+ userId, UserHandle.getAppId(Binder.getCallingUid()), ps.appId));
+ if (returnAllowed) {
return ps.getInstantApp(userId);
}
}
@@ -12334,6 +12341,7 @@ public class PackageManagerService extends IPackageManager.Stub {
}
res.iconResourceId = info.icon;
res.system = res.activityInfo.applicationInfo.isSystemApp();
+ res.instantAppAvailable = userState.instantApp;
return res;
}
@@ -16824,11 +16832,20 @@ public class PackageManagerService extends IPackageManager.Stub {
res.origUsers = ps.queryInstalledUsers(sUserManager.getUserIds(), true);
}
- // Check whether the newly-scanned package wants to define an already-defined perm
int N = pkg.permissions.size();
for (int i = N-1; i >= 0; i--) {
PackageParser.Permission perm = pkg.permissions.get(i);
BasePermission bp = mSettings.mPermissions.get(perm.info.name);
+
+ // Don't allow anyone but the platform to define ephemeral permissions.
+ if ((perm.info.protectionLevel & PermissionInfo.PROTECTION_FLAG_EPHEMERAL) != 0
+ && !PLATFORM_PACKAGE_NAME.equals(pkg.packageName)) {
+ Slog.w(TAG, "Package " + pkg.packageName
+ + " attempting to delcare ephemeral permission "
+ + perm.info.name + "; Removing ephemeral.");
+ perm.info.protectionLevel &= ~PermissionInfo.PROTECTION_FLAG_EPHEMERAL;
+ }
+ // Check whether the newly-scanned package wants to define an already-defined perm
if (bp != null) {
// If the defining package is signed with our cert, it's okay. This
// also includes the "updating the same package" case, of course.
@@ -19636,6 +19653,35 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
return getHomeActivitiesAsUser(allHomeCandidates, UserHandle.getCallingUserId());
}
+ /**
+ * Report the 'Home' activity which is currently set as "always use this one". If non is set
+ * then reports the most likely home activity or null if there are more than one.
+ */
+ public ComponentName getDefaultHomeActivity(int userId) {
+ List<ResolveInfo> allHomeCandidates = new ArrayList<>();
+ ComponentName cn = getHomeActivitiesAsUser(allHomeCandidates, userId);
+ if (cn != null) {
+ return cn;
+ }
+
+ // Find the launcher with the highest priority and return that component if there are no
+ // other home activity with the same priority.
+ int lastPriority = Integer.MIN_VALUE;
+ ComponentName lastComponent = null;
+ final int size = allHomeCandidates.size();
+ for (int i = 0; i < size; i++) {
+ final ResolveInfo ri = allHomeCandidates.get(i);
+ if (ri.priority > lastPriority) {
+ lastComponent = ri.activityInfo.getComponentName();
+ lastPriority = ri.priority;
+ } else if (ri.priority == lastPriority) {
+ // Two components found with same priority.
+ lastComponent = null;
+ }
+ }
+ return lastComponent;
+ }
+
private Intent getHomeIntent() {
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
diff --git a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
index afdec9ffddc3..12836dbb4820 100644
--- a/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
+++ b/services/core/java/com/android/server/storage/DeviceStorageMonitorService.java
@@ -17,6 +17,7 @@
package com.android.server.storage;
import android.app.NotificationChannel;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.server.EventLogTags;
import com.android.server.SystemService;
import com.android.server.pm.InstructionSets;
@@ -141,7 +142,7 @@ public class DeviceStorageMonitorService extends SystemService {
*/
static final String SERVICE = "devicestoragemonitor";
- private static final String NOTIFICATION_CHANNEL_ID = SERVICE;
+ private static final String TV_NOTIFICATION_CHANNEL_ID = "devicestoragemonitor.tv";
/**
* Handler that checks the amount of disk space on the device and sends a
@@ -388,14 +389,13 @@ public class DeviceStorageMonitorService extends SystemService {
PackageManager packageManager = context.getPackageManager();
boolean isTv = packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK);
- int importance = isTv
- ? NotificationManager.IMPORTANCE_HIGH // Do not change: this is TV-specific
- : NotificationManager.IMPORTANCE_LOW;
- notificationMgr.createNotificationChannel(
- new NotificationChannel(NOTIFICATION_CHANNEL_ID,
- context.getString(
- com.android.internal.R.string.device_storage_monitor_notification_channel),
- importance));
+ if (isTv) {
+ notificationMgr.createNotificationChannel(new NotificationChannel(
+ TV_NOTIFICATION_CHANNEL_ID,
+ context.getString(
+ com.android.internal.R.string.device_storage_monitor_notification_channel),
+ NotificationManager.IMPORTANCE_HIGH));
+ }
publishBinderService(SERVICE, mRemoteService);
publishLocalService(DeviceStorageMonitorInternal.class, mLocalService);
@@ -495,21 +495,22 @@ public class DeviceStorageMonitorService extends SystemService {
: com.android.internal.R.string.low_internal_storage_view_text_no_boot);
PendingIntent intent = PendingIntent.getActivityAsUser(context, 0, lowMemIntent, 0,
null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(context)
- .setSmallIcon(com.android.internal.R.drawable.stat_notify_disk_full)
- .setTicker(title)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color))
- .setContentTitle(title)
- .setContentText(details)
- .setContentIntent(intent)
- .setStyle(new Notification.BigTextStyle()
- .bigText(details))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setCategory(Notification.CATEGORY_SYSTEM)
- .setChannel(NOTIFICATION_CHANNEL_ID)
- .extend(new Notification.TvExtender())
- .build();
+ Notification notification =
+ new Notification.Builder(context, SystemNotificationChannels.ALERTS)
+ .setSmallIcon(com.android.internal.R.drawable.stat_notify_disk_full)
+ .setTicker(title)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setContentTitle(title)
+ .setContentText(details)
+ .setContentIntent(intent)
+ .setStyle(new Notification.BigTextStyle()
+ .bigText(details))
+ .setVisibility(Notification.VISIBILITY_PUBLIC)
+ .setCategory(Notification.CATEGORY_SYSTEM)
+ .extend(new Notification.TvExtender()
+ .setChannel(TV_NOTIFICATION_CHANNEL_ID))
+ .build();
notification.flags |= Notification.FLAG_NO_CLEAR;
notificationMgr.notifyAsUser(null, LOW_MEMORY_NOTIFICATION_ID, notification,
UserHandle.ALL);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 22630428ad01..379e3cea405e 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -762,6 +762,16 @@ class AppWindowToken extends WindowToken implements WindowManagerService.AppFree
if (canFreezeBounds()) {
freezeBounds();
}
+
+ // In the process of tearing down before relaunching, the app will
+ // try and clean up it's child surfaces. We need to prevent this from
+ // happening, so we sever the children, transfering their ownership
+ // from the client it-self to the parent surface (owned by us).
+ for (int i = mChildren.size() - 1; i >= 0; i--) {
+ final WindowState w = mChildren.get(i);
+ w.mWinAnimator.detachChildren();
+ }
+
mPendingRelaunchCount++;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 2a4dfc444fe2..eb10f0c2978c 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2199,6 +2199,15 @@ public class WindowManagerService extends IWindowManager.Stub
if (mAccessibilityController != null && win.getDisplayId() == DEFAULT_DISPLAY) {
mAccessibilityController.onWindowTransitionLocked(win, transit);
}
+
+ // When we start the exit animation we take the Surface from the client
+ // so it will stop perturbing it. We need to likewise takeaway the SurfaceFlinger
+ // side child surfaces, so they will remain preserved in their current state
+ // (rather than be cleaned up immediately by the app code).
+ SurfaceControl.openTransaction();
+ winAnimator.detachChildren();
+ SurfaceControl.closeTransaction();
+
return focusMayChange;
}
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 98598e1654dc..4b7133836db8 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -566,6 +566,20 @@ class WindowStateAnimator {
if (!mDestroyPreservedSurfaceUponRedraw) {
return;
}
+ if (mSurfaceController != null) {
+ if (mPendingDestroySurface != null) {
+ // If we are preserving a surface but we aren't relaunching that means
+ // we are just doing an in-place switch. In that case any SurfaceFlinger side
+ // child layers need to be reparented to the new surface to make this
+ // transparent to the app.
+ if (mWin.mAppToken == null || mWin.mAppToken.isRelaunching() == false) {
+ SurfaceControl.openTransaction();
+ mPendingDestroySurface.reparentChildrenInTransaction(mSurfaceController);
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
destroyDeferredSurfaceLocked();
mDestroyPreservedSurfaceUponRedraw = false;
}
@@ -1965,4 +1979,10 @@ class WindowStateAnimator {
}
return mForceScaleUntilResize;
}
+
+ void detachChildren() {
+ if (mSurfaceController != null) {
+ mSurfaceController.detachChildren();
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index f8e74284fafd..f7d3343831bf 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -135,6 +135,20 @@ class WindowSurfaceController {
}
}
+ void reparentChildrenInTransaction(WindowSurfaceController other) {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "REPARENT from: " + this + " to: " + other);
+ if ((mSurfaceControl != null) && (other.mSurfaceControl != null)) {
+ mSurfaceControl.reparentChildren(other.getHandle());
+ }
+ }
+
+ void detachChildren() {
+ if (SHOW_TRANSACTIONS) Slog.i(TAG, "SEVER CHILDREN");
+ if (mSurfaceControl != null) {
+ mSurfaceControl.detachChildren();
+ }
+ }
+
void hideInTransaction(String reason) {
if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
mHiddenForOtherReasons = true;
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 20b70a6344b4..36ae94b88b23 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1144,7 +1144,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
}
auto result = gnssHal->setCallback(gnssCbIface);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("SetCallback for Gnss Interface fails\n");
return JNI_FALSE;
}
@@ -1154,7 +1154,7 @@ static jboolean android_location_GnssLocationProvider_init(JNIEnv* env, jobject
ALOGE("Unable to initialize GNSS Xtra interface\n");
} else {
result = gnssXtraIface->setCallback(gnssXtraCbIface);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
gnssXtraIface = nullptr;
ALOGE("SetCallback for Gnss Xtra Interface fails\n");
}
@@ -1344,7 +1344,7 @@ static void android_location_GnssLocationProvider_inject_time(JNIEnv* /* env */,
jlong time, jlong timeReference, jint uncertainty) {
if (gnssHal != nullptr) {
auto result = gnssHal->injectTime(time, timeReference, uncertainty);
- if (!result || !result.isOk()) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Gnss injectTime() failed", __func__);
}
}
@@ -1354,7 +1354,7 @@ static void android_location_GnssLocationProvider_inject_location(JNIEnv* /* env
jobject /* obj */, jdouble latitude, jdouble longitude, jfloat accuracy) {
if (gnssHal != nullptr) {
auto result = gnssHal->injectLocation(latitude, longitude, accuracy);
- if (!result || !result.isOk()) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Gnss injectLocation() failed", __func__);
}
}
@@ -1391,7 +1391,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_open(
const char *apnStr = env->GetStringUTFChars(apn, NULL);
auto result = agnssIface->dataConnOpen(apnStr, static_cast<IAGnss::ApnIpType>(apnIpType));
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result){
ALOGE("%s: Failed to set APN and its IP type", __func__);
}
env->ReleaseStringUTFChars(apn, apnStr);
@@ -1405,7 +1405,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_closed(JNIEnv*
}
auto result = agnssIface->dataConnClosed();
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to close AGnss data connection", __func__);
}
}
@@ -1418,7 +1418,7 @@ static void android_location_GnssLocationProvider_agps_data_conn_failed(JNIEnv*
}
auto result = agnssIface->dataConnFailed();
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to notify unavailability of AGnss data connection", __func__);
}
}
@@ -1434,7 +1434,7 @@ static void android_location_GnssLocationProvider_set_agps_server(JNIEnv* env, j
auto result = agnssIface->setServer(static_cast<IAGnssCallback::AGnssType>(type),
c_hostname,
port);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("%s: Failed to set AGnss host name and port", __func__);
}
@@ -1512,13 +1512,13 @@ static void android_location_GnssLocationProvider_update_network_state(JNIEnv* e
auto result = agnssRilIface->updateNetworkState(connected,
static_cast<IAGnssRil::NetworkType>(type),
roaming);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("updateNetworkState failed");
}
const char *c_apn = env->GetStringUTFChars(apn, NULL);
result = agnssRilIface->updateNetworkAvailability(available, c_apn);
- if ((!result) || (!result.isOk())) {
+ if (!result.isOk() || !result) {
ALOGE("updateNetworkAvailability failed");
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 17e6bba5f1c7..8b94ca067621 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -165,10 +165,10 @@ import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.JournaledFile;
-import com.android.internal.util.ParcelableString;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.internal.widget.LockPatternUtils;
@@ -4863,6 +4863,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
/**
+ * Determine whether DPMS should check if a delegate package is already installed before
+ * granting it new delegations via {@link #setDelegatedScopes}.
+ */
+ private static boolean shouldCheckIfDelegatePackageIsInstalled(String delegatePackage,
+ int targetSdk, List<String> scopes) {
+ // 1) Never skip is installed check from N.
+ if (targetSdk >= Build.VERSION_CODES.N) {
+ return true;
+ }
+ // 2) Skip if DELEGATION_CERT_INSTALL is the only scope being given.
+ if (scopes.size() == 1 && scopes.get(0).equals(DELEGATION_CERT_INSTALL)) {
+ return false;
+ }
+ // 3) Skip if all previously granted scopes are being cleared.
+ if (scopes.isEmpty()) {
+ return false;
+ }
+ // Otherwise it should check that delegatePackage is installed.
+ return true;
+ }
+
+ /**
* Set the scopes of a device owner or profile owner delegate.
*
* @param who the device owner or profile owner.
@@ -4888,8 +4910,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
// Ensure calling process is device/profile owner.
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
// Ensure the delegate is installed (skip this for DELEGATION_CERT_INSTALL in pre-N).
- if (scopes.size() == 1 && scopes.get(0).equals(DELEGATION_CERT_INSTALL) ||
- getTargetSdk(who.getPackageName(), userId) >= Build.VERSION_CODES.N) {
+ if (shouldCheckIfDelegatePackageIsInstalled(delegatePackage,
+ getTargetSdk(who.getPackageName(), userId), scopes)) {
// Throw when the delegate package is not installed.
if (!isPackageInstalledForUser(delegatePackage, userId)) {
throw new IllegalArgumentException("Package " + delegatePackage
@@ -5107,8 +5129,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final String currentPackage = policy.mDelegationMap.keyAt(i);
final List<String> currentScopes = policy.mDelegationMap.valueAt(i);
- if (!currentPackage.equals(delegatePackage) && currentScopes.remove(scope)) {
- setDelegatedScopes(who, currentPackage, currentScopes);
+ if (!currentPackage.equals(delegatePackage) && currentScopes.contains(scope)) {
+ final List<String> newScopes = new ArrayList(currentScopes);
+ newScopes.remove(scope);
+ setDelegatedScopes(who, currentPackage, newScopes);
}
}
}
@@ -5269,13 +5293,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void sendWipeProfileNotification() {
String contentText = mContext.getString(R.string.work_profile_deleted_description_dpm_wipe);
- Notification notification = new Notification.Builder(mContext)
- .setSmallIcon(android.R.drawable.stat_sys_warning)
- .setContentTitle(mContext.getString(R.string.work_profile_deleted))
- .setContentText(contentText)
- .setColor(mContext.getColor(R.color.system_notification_accent_color))
- .setStyle(new Notification.BigTextStyle().bigText(contentText))
- .build();
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
+ .setSmallIcon(android.R.drawable.stat_sys_warning)
+ .setContentTitle(mContext.getString(R.string.work_profile_deleted))
+ .setContentText(contentText)
+ .setColor(mContext.getColor(R.color.system_notification_accent_color))
+ .setStyle(new Notification.BigTextStyle().bigText(contentText))
+ .build();
mInjector.getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
}
@@ -10695,7 +10720,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
intent.setPackage("com.android.systemui");
final PendingIntent pendingIntent = PendingIntent.getBroadcastAsUser(mContext, 0, intent, 0,
UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVICE_ADMIN)
.setSmallIcon(R.drawable.ic_qs_network_logging)
.setContentTitle(mContext.getString(R.string.network_logging_notification_title))
.setContentText(mContext.getString(R.string.network_logging_notification_text))
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java b/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
index 03c137a95b85..1933fe750e75 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
@@ -34,8 +34,8 @@ import android.provider.Settings;
import android.security.KeyChain.KeyChainConnection;
import android.util.Log;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.R;
-import com.android.internal.util.ParcelableString;
import java.util.ArrayList;
import java.util.List;
@@ -132,16 +132,16 @@ public class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Voi
dialogIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
UserHandle.of(parentUserId));
- final Notification noti = new Notification.Builder(userContext)
- .setSmallIcon(smallIconId)
- .setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
- pendingCertificateCount))
- .setContentText(contentText)
- .setContentIntent(notifyIntent)
- .setPriority(Notification.PRIORITY_HIGH)
- .setShowWhen(false)
- .setColor(R.color.system_notification_accent_color)
- .build();
+ final Notification noti =
+ new Notification.Builder(userContext, SystemNotificationChannels.SECURITY)
+ .setSmallIcon(smallIconId)
+ .setContentTitle(resources.getQuantityText(R.plurals.ssl_ca_cert_warning,
+ pendingCertificateCount))
+ .setContentText(contentText)
+ .setContentIntent(notifyIntent)
+ .setShowWhen(false)
+ .setColor(R.color.system_notification_accent_color)
+ .build();
mInjector.getNotificationManager().notifyAsUser(
LOG_TAG, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
@@ -150,12 +150,7 @@ public class MonitoringCertNotificationTask extends AsyncTask<Integer, Void, Voi
private List<String> getInstalledCaCertificates(UserHandle userHandle)
throws RemoteException, RuntimeException {
try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
- List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList();
- List<String> result = new ArrayList<>(aliases.size());
- for (int i = 0; i < aliases.size(); i++) {
- result.add(aliases.get(i).string);
- }
- return result;
+ return conn.getService().getUserCaAliases().getList();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
index 6d42dc9e4e5a..969c89eb4029 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
@@ -28,6 +28,7 @@ import android.provider.Settings;
import android.text.format.DateUtils;
import com.android.internal.R;
+import com.android.internal.notification.SystemNotificationChannels;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -62,14 +63,14 @@ class RemoteBugreportUtils {
PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
dialogIntent, 0, null, UserHandle.CURRENT);
- Notification.Builder builder = new Notification.Builder(context)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
- .setOngoing(true)
- .setLocalOnly(true)
- .setPriority(Notification.PRIORITY_HIGH)
- .setContentIntent(pendingDialogIntent)
- .setColor(context.getColor(
- com.android.internal.R.color.system_notification_accent_color));
+ Notification.Builder builder =
+ new Notification.Builder(context, SystemNotificationChannels.DEVELOPER)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
+ .setOngoing(true)
+ .setLocalOnly(true)
+ .setContentIntent(pendingDialogIntent)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color));
if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
builder.setContentTitle(context.getString(
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index e586482af83e..1a0aff79be6e 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -53,6 +53,7 @@ import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.app.NightDisplayController;
import com.android.internal.logging.MetricsLogger;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
import com.android.internal.policy.EmergencyAffordanceManager;
@@ -1118,6 +1119,7 @@ public final class SystemServer {
traceBeginAndSlog("StartNotificationManager");
mSystemServiceManager.startService(NotificationManagerService.class);
+ SystemNotificationChannels.createAll(context);
notification = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
networkPolicy.bindNotificationManager(notification);
diff --git a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
index f943ee2c09bf..472f98455d6a 100644
--- a/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
+++ b/services/retaildemo/java/com/android/server/retaildemo/RetailDemoModeService.java
@@ -61,6 +61,7 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.KeyValueListParser;
import android.util.Slog;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.BackgroundThread;
import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
@@ -818,7 +819,7 @@ public class RetailDemoModeService extends SystemService {
}
Notification createResetNotification() {
- return new Notification.Builder(getContext())
+ return new Notification.Builder(getContext(), SystemNotificationChannels.RETAIL_MODE)
.setContentTitle(getContext().getString(R.string.reset_retail_demo_mode_title))
.setContentText(getContext().getString(R.string.reset_retail_demo_mode_text))
.setOngoing(true)
diff --git a/services/tests/notification/AndroidManifest.xml b/services/tests/notification/AndroidManifest.xml
index 92f155f53420..cf050a89b0e6 100644
--- a/services/tests/notification/AndroidManifest.xml
+++ b/services/tests/notification/AndroidManifest.xml
@@ -23,6 +23,7 @@
<uses-permission android:name="android.permission.MANAGE_USERS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.ACCESS_NOTIFICATIONS" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
<application>
<uses-library android:name="android.test.runner" />
diff --git a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
index 936531b07059..05c33a4e1cea 100644
--- a/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GroupHelperTest.java
@@ -64,7 +64,7 @@ public class GroupHelperTest {
private StatusBarNotification getSbn(String pkg, int id, String tag,
UserHandle user, String groupKey) {
- Notification.Builder nb = new Notification.Builder(getContext())
+ Notification.Builder nb = new Notification.Builder(getContext(), "test_channel_id")
.setContentTitle("A")
.setWhen(1205);
if (groupKey != null) {
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index 064ab0a3adc4..176342be99fd 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -63,6 +63,7 @@ public class NotificationComparatorTest {
private final int smsUid = 11;
private final String pkg2 = "pkg2";
private final int uid2 = 1111111;
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
private NotificationRecord mRecordMinCall;
private NotificationRecord mRecordHighCall;
@@ -100,7 +101,7 @@ public class NotificationComparatorTest {
smsPkg = Settings.Secure.getString(mContext.getContentResolver(),
Settings.Secure.SMS_DEFAULT_APPLICATION);
- Notification n1 = new Notification.Builder(mContext)
+ Notification n1 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.build();
@@ -109,7 +110,7 @@ public class NotificationComparatorTest {
new UserHandle(userId), "", 2000), getDefaultChannel());
mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
- Notification n2 = new Notification.Builder(mContext)
+ Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_CALL)
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
.setColorized(true /* colorized */)
@@ -119,7 +120,7 @@ public class NotificationComparatorTest {
new UserHandle(userId), "", 1999), getDefaultChannel());
mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
- Notification n3 = new Notification.Builder(mContext)
+ Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MediaStyle()
.setMediaSession(new MediaSession.Token(null)))
.setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
@@ -129,7 +130,7 @@ public class NotificationComparatorTest {
"", 1499), getDefaultChannel());
mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n4 = new Notification.Builder(mContext)
+ Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.MessagingStyle("sender!")).build();
mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
@@ -137,34 +138,34 @@ public class NotificationComparatorTest {
mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
- Notification n5 = new Notification.Builder(mContext)
+ Notification n5 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE).build();
mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
"", 1299), getDefaultChannel());
mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n6 = new Notification.Builder(mContext).build();
+ Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
"", 1259), getDefaultChannel());
mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n7 = new Notification.Builder(mContext).build();
+ Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
"", 1259), getDefaultChannel());
mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
- Notification n8 = new Notification.Builder(mContext).build();
+ Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
"", 1258), getDefaultChannel());
mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
- Notification n9 = new Notification.Builder(mContext)
+ Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setCategory(Notification.CATEGORY_MESSAGE)
.setFlag(Notification.FLAG_ONGOING_EVENT
|Notification.FLAG_FOREGROUND_SERVICE, true)
@@ -174,7 +175,7 @@ public class NotificationComparatorTest {
"", 9258), getDefaultChannel());
mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
- Notification n10 = new Notification.Builder(mContext)
+ Notification n10 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
.setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 88f1a5362008..b7b3617d7ecf 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -129,11 +129,9 @@ public class NotificationManagerServiceTest {
if (channel == null) {
channel = new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
}
- Notification.Builder nb = new Notification.Builder(mContext)
+ Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
.setContentTitle("foo")
- .setSmallIcon(android.R.drawable.sym_def_app_icon)
- .setChannel(channel.getId())
- .setPriority(Notification.PRIORITY_HIGH);
+ .setSmallIcon(android.R.drawable.sym_def_app_icon);
if (extender != null) {
nb.extend(extender);
}
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 821007213993..62126265e117 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -93,6 +93,7 @@ public class RankingHelperTest {
private final int uid = 0;
private final String pkg2 = "pkg2";
private final int uid2 = 1111111;
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
private AudioAttributes mAudioAttributes;
private Context getContext() {
@@ -107,7 +108,7 @@ public class RankingHelperTest {
mHelper = new RankingHelper(getContext(), mPm, handler, mUsageStats,
new String[]{ImportanceExtractor.class.getName()});
- mNotiGroupGSortA = new Notification.Builder(getContext())
+ mNotiGroupGSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
@@ -117,7 +118,7 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiGroupGSortB = new Notification.Builder(getContext())
+ mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("B")
.setGroup("G")
.setSortKey("B")
@@ -127,7 +128,7 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroup = new Notification.Builder(getContext())
+ mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("C")
.setWhen(1201)
.build();
@@ -135,7 +136,7 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiNoGroup, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroup2 = new Notification.Builder(getContext())
+ mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("D")
.setWhen(1202)
.build();
@@ -143,7 +144,7 @@ public class RankingHelperTest {
"package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
null, System.currentTimeMillis()), getDefaultChannel());
- mNotiNoGroupSortA = new Notification.Builder(getContext())
+ mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("E")
.setWhen(1201)
.setSortKey("A")
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index c5abba8313c1..9575d3253b28 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -51,6 +51,8 @@ import static org.mockito.Mockito.when;
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SnoozeHelperTest {
+ private static final String TEST_CHANNEL_ID = "test_channel_id";
+
@Mock SnoozeHelper.Callback mCallback;
@Mock AlarmManager mAm;
@Mock ManagedServices.UserProfiles mUserProfiles;
@@ -77,7 +79,7 @@ public class SnoozeHelperTest {
verify(mAm, times(1)).setExactAndAllowWhileIdle(
anyInt(), captor.capture(), any(PendingIntent.class));
long actualSnoozedUntilDuration = captor.getValue() - SystemClock.elapsedRealtime();
- assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 2);
+ assertTrue(Math.abs(actualSnoozedUntilDuration - 1000) < 25);
assertTrue(mSnoozeHelper.isSnoozed(
UserHandle.USER_SYSTEM, r.sbn.getPackageName(), r.getKey()));
}
@@ -232,20 +234,16 @@ public class SnoozeHelperTest {
private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
UserHandle user) {
- Notification n = new Notification.Builder(getContext())
+ Notification n = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
.setContentTitle("A")
.setGroup("G")
.setSortKey("A")
.setWhen(1205)
.build();
+ final NotificationChannel notificationChannel = new NotificationChannel(
+ TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
return new NotificationRecord(getContext(), new StatusBarNotification(
pkg, pkg, id, tag, 0, 0, n, user, null,
- System.currentTimeMillis()), getDefaultChannel());
- }
-
- private NotificationChannel getDefaultChannel() {
- return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
- NotificationManager.IMPORTANCE_LOW);
+ System.currentTimeMillis()), notificationChannel);
}
-
}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d65a9bfbf897..756514bbecc4 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -34,7 +34,7 @@ import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
import android.content.res.Resources;
import android.graphics.Color;
import android.net.IIpConnectivityMetrics;
@@ -56,7 +56,6 @@ import android.util.ArraySet;
import android.util.Pair;
import com.android.internal.R;
-import com.android.internal.util.ParcelableString;
import com.android.internal.widget.LockPatternUtils;
import com.android.server.LocalServices;
import com.android.server.SystemService;
@@ -1220,8 +1219,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
mContext.userContexts.put(user, mContext);
when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
- ParceledListSlice<ParcelableString> oneCert = asSlice(new String[] {"1"});
- ParceledListSlice<ParcelableString> fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
+ StringParceledListSlice oneCert = asSlice(new String[] {"1"});
+ StringParceledListSlice fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
final String TEST_STRING = "Test for exactly 2 certs out of 4";
doReturn(TEST_STRING).when(mContext.resources).getQuantityText(anyInt(), eq(2));
@@ -1229,7 +1228,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Given that we have exactly one certificate installed,
when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(oneCert);
// when that certificate is approved,
- dpms.approveCaCert(oneCert.getList().get(0).string, userId, true);
+ dpms.approveCaCert(oneCert.getList().get(0), userId, true);
// a notification should not be shown.
verify(mContext.notificationManager, timeout(1000))
.cancelAsUser(anyString(), anyInt(), eq(user));
@@ -1237,8 +1236,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
// Given that we have four certificates installed,
when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(fourCerts);
// when two of them are approved (one of them approved twice hence no action),
- dpms.approveCaCert(fourCerts.getList().get(0).string, userId, true);
- dpms.approveCaCert(fourCerts.getList().get(1).string, userId, true);
+ dpms.approveCaCert(fourCerts.getList().get(0), userId, true);
+ dpms.approveCaCert(fourCerts.getList().get(1), userId, true);
// a notification should be shown saying that there are two certificates left to approve.
verify(mContext.notificationManager, timeout(1000))
.notifyAsUser(anyString(), anyInt(), argThat(
@@ -3974,18 +3973,9 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
/**
- * Convert String[] to ParceledListSlice&lt;ParcelableString&gt;.
- * <p>
- * TODO: This shouldn't be necessary. If ParcelableString does need to exist, it also needs
- * a real constructor.
+ * Convert String[] to StringParceledListSlice.
*/
- private static ParceledListSlice<ParcelableString> asSlice(String[] s) {
- List<ParcelableString> list = new ArrayList<>(s.length);
- for (int i = 0; i < s.length; i++) {
- ParcelableString item = new ParcelableString();
- item.string = s[i];
- list.add(i, item);
- }
- return new ParceledListSlice<ParcelableString>(list);
+ private static StringParceledListSlice asSlice(String[] s) {
+ return new StringParceledListSlice(Arrays.asList(s));
}
}
diff --git a/services/usb/java/com/android/server/usb/MtpNotificationManager.java b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
index 5c46222b2feb..db7b3853d06e 100644
--- a/services/usb/java/com/android/server/usb/MtpNotificationManager.java
+++ b/services/usb/java/com/android/server/usb/MtpNotificationManager.java
@@ -20,7 +20,6 @@ import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -32,6 +31,8 @@ import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.UserHandle;
+import com.android.internal.notification.SystemNotificationChannels;
+
/**
* Manager for MTP storage notification.
*/
@@ -77,11 +78,12 @@ class MtpNotificationManager {
device.getProductName());
final String description = resources.getString(
com.android.internal.R.string.usb_mtp_launch_notification_description);
- final Notification.Builder builder = new Notification.Builder(mContext)
- .setContentTitle(title)
- .setContentText(description)
- .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
- .setCategory(Notification.CATEGORY_SYSTEM);
+ final Notification.Builder builder =
+ new Notification.Builder(mContext, SystemNotificationChannels.USB)
+ .setContentTitle(title)
+ .setContentText(description)
+ .setSmallIcon(com.android.internal.R.drawable.stat_sys_data_usb)
+ .setCategory(Notification.CATEGORY_SYSTEM);
final Intent intent = new Intent(ACTION_OPEN_IN_APPS);
intent.putExtra(UsbManager.EXTRA_DEVICE, device);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 07b4ca12171f..b1df0af100af 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -50,6 +50,7 @@ import android.util.Pair;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.notification.SystemNotificationChannels;
import com.android.internal.os.SomeArgs;
import com.android.internal.util.IndentingPrintWriter;
import com.android.server.FgThread;
@@ -912,13 +913,13 @@ public class UsbDeviceManager {
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.USB)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
.setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_MIN)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
@@ -951,13 +952,13 @@ public class UsbDeviceManager {
PendingIntent pi = PendingIntent.getActivityAsUser(mContext, 0,
intent, 0, null, UserHandle.CURRENT);
- Notification notification = new Notification.Builder(mContext)
+ Notification notification =
+ new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
.setWhen(0)
.setOngoing(true)
.setTicker(title)
.setDefaults(0) // please be quiet
- .setPriority(Notification.PRIORITY_DEFAULT)
.setColor(mContext.getColor(
com.android.internal.R.color.system_notification_accent_color))
.setContentTitle(title)
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 4295d401edd4..3f7c908436a4 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -878,6 +878,7 @@ public final class Call {
* party, if it is active.
*/
public static final class RttCall {
+ /** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
public @interface RttAudioMode {}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 6807ef4b0601..2e144f24bfa9 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -1130,18 +1130,22 @@ public class TelecomManager {
/**
* If there is a ringing incoming call, this method accepts the call on behalf of the user.
- * TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
- * this method (clockwork & gearhead).
+ *
* If the incoming call is a video call, the call will be answered with the same video state as
* the incoming call requests. This means, for example, that an incoming call requesting
* {@link VideoProfile#STATE_BIDIRECTIONAL} will be answered, accepting that state.
- * @hide
+ *
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
+ * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
*/
- @SystemApi
+ //TODO: L-release - need to convert all invocation of ITelecmmService#answerRingingCall to use
+ // this method (clockwork & gearhead).
+ @RequiresPermission(anyOf =
+ {Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
public void acceptRingingCall() {
try {
if (isServiceConnected()) {
- getTelecomService().acceptRingingCall();
+ getTelecomService().acceptRingingCall(mContext.getPackageName());
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#acceptRingingCall", e);
@@ -1152,14 +1156,18 @@ public class TelecomManager {
* If there is a ringing incoming call, this method accepts the call on behalf of the user,
* with the specified video state.
*
+ * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE} or
+ * {@link android.Manifest.permission#ANSWER_PHONE_CALLS}
+ *
* @param videoState The desired video state to answer the call with.
- * @hide
*/
- @SystemApi
+ @RequiresPermission(anyOf =
+ {Manifest.permission.ANSWER_PHONE_CALLS, Manifest.permission.MODIFY_PHONE_STATE})
public void acceptRingingCall(int videoState) {
try {
if (isServiceConnected()) {
- getTelecomService().acceptRingingCallWithVideoState(videoState);
+ getTelecomService().acceptRingingCallWithVideoState(
+ mContext.getPackageName(), videoState);
}
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelecomService#acceptRingingCallWithVideoState", e);
diff --git a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
index d9465dce49d2..eb1cde393cd4 100644
--- a/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
+++ b/telecomm/java/com/android/internal/telecom/ITelecomService.aidl
@@ -182,12 +182,12 @@ interface ITelecomService {
/**
* @see TelecomServiceImpl#acceptRingingCall
*/
- void acceptRingingCall();
+ void acceptRingingCall(String callingPackage);
/**
* @see TelecomServiceImpl#acceptRingingCallWithVideoState(int)
*/
- void acceptRingingCallWithVideoState(int videoState);
+ void acceptRingingCallWithVideoState(String callingPackage, int videoState);
/**
* @see TelecomServiceImpl#cancelMissedCallsNotification
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index 406f01e82c35..f1f683c70735 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -18,6 +18,7 @@ package android.telephony.ims;
import android.app.PendingIntent;
import android.content.Intent;
+import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.Message;
import android.os.RemoteException;
@@ -43,6 +44,7 @@ import com.android.internal.annotations.VisibleForTesting;
import static android.Manifest.permission.MODIFY_PHONE_STATE;
import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
/**
* Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
@@ -137,7 +139,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public boolean isConnected(int slotId, int featureType, int callSessionType, int callType)
throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "isConnected");
+ enforceReadPhoneStatePermission("isConnected");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -149,7 +151,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public boolean isOpened(int slotId, int featureType) throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "isOpened");
+ enforceReadPhoneStatePermission("isOpened");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -161,7 +163,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "getFeatureStatus");
+ enforceReadPhoneStatePermission("getFeatureStatus");
int status = ImsFeature.STATE_NOT_AVAILABLE;
synchronized (mFeatures) {
SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
@@ -178,7 +180,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public void addRegistrationListener(int slotId, int featureType,
IImsRegistrationListener listener) throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "addRegistrationListener");
+ enforceReadPhoneStatePermission("addRegistrationListener");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -190,7 +192,7 @@ public abstract class ImsService extends ImsServiceBase {
@Override
public void removeRegistrationListener(int slotId, int featureType,
IImsRegistrationListener listener) throws RemoteException {
- enforceCallingOrSelfPermission(READ_PHONE_STATE, "removeRegistrationListener");
+ enforceReadPhoneStatePermission("removeRegistrationListener");
synchronized (mFeatures) {
MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
if (feature != null) {
@@ -351,6 +353,8 @@ public abstract class ImsService extends ImsServiceBase {
}
ImsFeature f = makeImsFeature(slotId, featureType);
if (f != null) {
+ f.setContext(this);
+ f.setSlotId(slotId);
f.setImsFeatureStatusCallback(c);
featureMap.put(featureType, f);
}
@@ -434,6 +438,17 @@ public abstract class ImsService extends ImsServiceBase {
}
/**
+ * Check for both READ_PHONE_STATE and READ_PRIVILEGED_PHONE_STATE. READ_PHONE_STATE is a
+ * public permission and READ_PRIVILEGED_PHONE_STATE is only granted to system apps.
+ */
+ private void enforceReadPhoneStatePermission(String fn) {
+ if (checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ enforceCallingOrSelfPermission(READ_PHONE_STATE, fn);
+ }
+ }
+
+ /**
* @return An implementation of MMTelFeature that will be used by the system for MMTel
* functionality. Must be able to handle emergency calls at any time as well.
*/
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 8d7d260104e2..988dd588ecad 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -17,7 +17,10 @@
package android.telephony.ims.feature;
import android.annotation.IntDef;
+import android.content.Context;
+import android.content.Intent;
import android.os.RemoteException;
+import android.telephony.SubscriptionManager;
import android.util.Log;
import com.android.ims.internal.IImsFeatureStatusCallback;
@@ -35,6 +38,32 @@ public abstract class ImsFeature {
private static final String LOG_TAG = "ImsFeature";
+ /**
+ * Action to broadcast when ImsService is up.
+ * Internal use only.
+ * Only defined here separately compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_UP =
+ "com.android.ims.IMS_SERVICE_UP";
+
+ /**
+ * Action to broadcast when ImsService is down.
+ * Internal use only.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_DOWN =
+ "com.android.ims.IMS_SERVICE_DOWN";
+
+ /**
+ * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
+ * A long value; the phone ID corresponding to the IMS service coming up or down.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String EXTRA_PHONE_ID = "android:phone_id";
+
// Invalid feature value
public static final int INVALID = -1;
// ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
@@ -61,11 +90,21 @@ public abstract class ImsFeature {
private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
private IImsFeatureStatusCallback mStatusCallback;
private @ImsState int mState = STATE_NOT_AVAILABLE;
+ private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ private Context mContext;
public interface INotifyFeatureRemoved {
void onFeatureRemoved(int slotId);
}
+ public void setContext(Context context) {
+ mContext = context;
+ }
+
+ public void setSlotId(int slotId) {
+ mSlotId = slotId;
+ }
+
public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
synchronized (mRemovedListeners) {
mRemovedListeners.add(listener);
@@ -118,6 +157,30 @@ public abstract class ImsFeature {
Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
}
}
+ sendImsServiceIntent(state);
+ }
+
+ /**
+ * Provide backwards compatibility using deprecated service UP/DOWN intents.
+ */
+ private void sendImsServiceIntent(@ImsState int state) {
+ if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ return;
+ }
+ Intent intent;
+ switch (state) {
+ case ImsFeature.STATE_NOT_AVAILABLE:
+ case ImsFeature.STATE_INITIALIZING:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ break;
+ case ImsFeature.STATE_READY:
+ intent = new Intent(ACTION_IMS_SERVICE_UP);
+ break;
+ default:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ }
+ intent.putExtra(EXTRA_PHONE_ID, mSlotId);
+ mContext.sendBroadcast(intent);
}
/**
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index eeaf26f92f47..c05045ebd18d 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -369,6 +369,11 @@ public class ConnectivityServiceTest extends AndroidTestCase {
connect(false);
}
+ public void suspend() {
+ mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
public void disconnect() {
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -1054,6 +1059,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
AVAILABLE,
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
+ SUSPENDED,
LOSING,
LOST,
UNAVAILABLE
@@ -1067,7 +1073,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
state = s; network = n; arg = o;
}
public String toString() {
- return String.format("%s (%s)", state, network);
+ return String.format("%s (%s) (%s)", state, network, arg);
}
@Override
public boolean equals(Object o) {
@@ -1105,11 +1111,26 @@ public class ConnectivityServiceTest extends AndroidTestCase {
}
@Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
+ setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
+ setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
+ }
+
+ @Override
public void onUnavailable() {
setLastCallback(CallbackState.UNAVAILABLE, null, null);
}
@Override
+ public void onNetworkSuspended(Network network) {
+ setLastCallback(CallbackState.SUSPENDED, network, null);
+ }
+
+ @Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
}
@@ -1132,11 +1153,12 @@ public class ConnectivityServiceTest extends AndroidTestCase {
return cb;
}
- void expectCallback(CallbackState state, MockNetworkAgent mockAgent, int timeoutMs) {
- CallbackInfo expected = new CallbackInfo(
- state, (mockAgent != null) ? mockAgent.getNetwork() : null, 0);
+ CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs) {
+ final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
+ CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
CallbackInfo actual = nextCallback(timeoutMs);
assertEquals("Unexpected callback:", expected, actual);
+
if (state == CallbackState.LOSING) {
String msg = String.format(
"Invalid linger time value %d, must be between %d and %d",
@@ -1144,10 +1166,50 @@ public class ConnectivityServiceTest extends AndroidTestCase {
int maxMsToLive = (Integer) actual.arg;
assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= TEST_LINGER_DELAY_MS);
}
+
+ return actual;
}
- void expectCallback(CallbackState state, MockNetworkAgent mockAgent) {
- expectCallback(state, mockAgent, TIMEOUT_MS);
+ CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
+ return expectCallback(state, agent, TIMEOUT_MS);
+ }
+
+ void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
+ expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
+
+ final boolean HAS_DATASYNC_ON_AVAILABLE = false;
+ if (HAS_DATASYNC_ON_AVAILABLE) {
+ if (expectSuspended) {
+ expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
+ }
+ expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
+ expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
+ }
+ }
+
+ void expectAvailableCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, false, TIMEOUT_MS);
+ }
+
+ void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ }
+
+ void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+ }
+
+ void expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+ assertTrue(nc.hasCapability(capability));
+ }
+
+ void expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+ assertFalse(nc.hasCapability(capability));
}
void assertNoCallback() {
@@ -1184,8 +1246,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1199,8 +1261,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1223,8 +1285,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Test validated networks
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ genericNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1236,9 +1298,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1274,28 +1337,32 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.connect(true);
// We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
// We then get LOSING when wifi validates and cell is outscored.
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+ callback.expectAvailableCallbacks(mEthernetNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
for (int i = 0; i < 4; i++) {
MockNetworkAgent oldNetwork, newNetwork;
@@ -1312,7 +1379,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
callback.expectCallback(CallbackState.LOSING, oldNetwork);
// TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
// longer lingering?
- defaultCallback.expectCallback(CallbackState.AVAILABLE, newNetwork);
+ defaultCallback.expectAvailableCallbacks(newNetwork);
assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
}
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -1320,17 +1387,19 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
// if the network is still up.
mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
+ // We expect a notification about the capabilities change, and nothing else.
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
+ defaultCallback.assertNoCallback();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Wifi no longer satisfies our listen, which is for an unmetered network.
// But because its score is 55, it's still up (and the default network).
- defaultCallback.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Disconnect our test networks.
mWiFiNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1346,22 +1415,22 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false); // Score: 10
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 20.
// Cell stays up because it would satisfy the default request if it validated.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false); // Score: 20
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 70.
@@ -1369,31 +1438,33 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.adjustScore(50);
mWiFiNetworkAgent.connect(false); // Score: 70
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
// it's arguably correct to linger it, since it was the default network before it validated.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1401,13 +1472,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// If a network is lingering, and we add and remove a request from it, resume lingering.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
@@ -1423,7 +1496,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
// Cell is now the default network. Pin it with a cell-specific request.
noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1432,8 +1505,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Now connect wifi, and expect it to become the default network.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
// The default request is lingering on cell, but nothing happens to cell, and we send no
// callbacks for it, because it's kept up by cellRequest.
callback.assertNoCallback();
@@ -1619,7 +1692,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mCellNetworkAgent.connectWithoutInternet();
- networkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ networkCallback.expectAvailableCallbacks(mCellNetworkAgent);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test releasing NetworkRequest disconnects cellular with MMS
cv = mCellNetworkAgent.getDisconnectedCV();
@@ -1645,7 +1718,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mmsNetworkAgent.connectWithoutInternet();
- networkCallback.expectCallback(CallbackState.AVAILABLE, mmsNetworkAgent);
+ networkCallback.expectAvailableCallbacks(mmsNetworkAgent);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
cv = mmsNetworkAgent.getDisconnectedCV();
@@ -1671,7 +1744,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
String firstRedirectUrl = "http://example.com/firstPath";
mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
- captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
// Take down network.
@@ -1684,7 +1757,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
String secondRedirectUrl = "http://example.com/secondPath";
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
- captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
// Make captive portal disappear then revalidate.
@@ -1694,7 +1767,9 @@ public class ConnectivityServiceTest extends AndroidTestCase {
captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate only sending available callbacks.
+ validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// Break network connectivity.
// Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -1739,7 +1814,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
// But there should be no CaptivePortal callback.
captivePortalCallback.assertNoCallback();
}
@@ -1792,14 +1867,14 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Bring up cell and expect CALLBACK_AVAILABLE.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
// Bring up wifi and expect CALLBACK_AVAILABLE.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
@@ -1809,7 +1884,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Bring up cell. Expect no default network callback, since it won't be the default.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
// Bring down wifi. Expect the default network callback to notified of LOST wifi
@@ -1817,28 +1892,16 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
}
- private class TestRequestUpdateCallback extends TestNetworkCallback {
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
- setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
- setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
- }
- }
-
@SmallTest
- public void testRequestCallbackUpdates() throws Exception {
+ public void testAdditionalStateCallbacks() throws Exception {
// File a network request for mobile.
- final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
mCm.requestNetwork(cellRequest, cellNetworkCallback);
@@ -1847,10 +1910,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- // We should get onAvailable().
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- // We should get onCapabilitiesChanged(), when the mobile network successfully validates.
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
+ // We should get onAvailable(), onCapabilitiesChanged(), and
+ // onLinkPropertiesChanged() in rapid succession. Additionally, we
+ // should get onCapabilitiesChanged() when the mobile network validates.
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Update LinkProperties.
@@ -1861,20 +1924,28 @@ public class ConnectivityServiceTest extends AndroidTestCase {
cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
+ // Suspend the network.
+ mCellNetworkAgent.suspend();
+ cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+
// Register a garden variety default network request.
- final TestNetworkCallback dfltNetworkCallback = new TestRequestUpdateCallback();
+ final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // Only onAvailable() is called; no other information is delivered.
- dfltNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
+ // as well as onNetworkSuspended() in rapid succession.
+ dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent);
dfltNetworkCallback.assertNoCallback();
// Request a NetworkCapabilities update; only the requesting callback is notified.
+ // TODO: Delete this together with Connectivity{Manager,Service} code.
mCm.requestNetworkCapabilities(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback.assertNoCallback();
// Request a LinkProperties update; only the requesting callback is notified.
+ // TODO: Delete this together with Connectivity{Manager,Service} code.
mCm.requestLinkProperties(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
@@ -1917,18 +1988,20 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ fgCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
// When wifi connects, cell lingers.
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1936,7 +2009,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mService.waitForIdle();
int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
- callback.assertNoCallback();
+ // Expect a network capabilities update sans FOREGROUND.
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1945,9 +2019,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
.addTransportType(TRANSPORT_CELLULAR).build();
final TestNetworkCallback cellCallback = new TestNetworkCallback();
mCm.requestNetwork(cellRequest, cellCallback);
- cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- callback.assertNoCallback(); // Because the network is already up.
+ // NOTE: This request causes the network's capabilities to change. This
+ // is currently delivered before the onAvailable() callbacks.
+ // TODO: Fix this.
+ cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
+ cellCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ // Expect a network capabilities update with FOREGROUND, because the most recent
+ // request causes its state to change.
+ callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1955,7 +2035,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// lingering.
mCm.unregisterNetworkCallback(cellCallback);
fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- callback.assertNoCallback();
+ // Expect a network capabilities update sans FOREGROUND.
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1963,7 +2044,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
mCm.unregisterNetworkCallback(callback);
@@ -2104,7 +2185,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
testFactory.expectAddRequests(2); // Because the cell request changes score twice.
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
testFactory.waitForNetworkRequests(2);
assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us.
@@ -2195,20 +2276,22 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// Bring up validated cell.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
Network cellNetwork = mCellNetworkAgent.getNetwork();
// Bring up validated wifi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi.
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
mCm.reportNetworkConnectivity(wifiNetwork, false);
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Because avoid bad wifi is off, we don't switch to cellular.
@@ -2223,18 +2306,18 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// that we switch back to cell.
tracker.configRestrictsAvoidBadWifi = false;
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// Switch back to a restrictive carrier.
tracker.configRestrictsAvoidBadWifi = true;
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
// Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
mCm.setAvoidUnvalidated(wifiNetwork);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
NET_CAPABILITY_VALIDATED));
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2245,13 +2328,15 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent.disconnect();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi and expect the dialog to appear.
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
mCm.reportNetworkConnectivity(wifiNetwork, false);
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
@@ -2259,7 +2344,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
tracker.reevaluate();
// We now switch to cell.
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
NET_CAPABILITY_VALIDATED));
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2270,17 +2355,17 @@ public class ConnectivityServiceTest extends AndroidTestCase {
// We switch to wifi and then to cell.
Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
validatedWifiCallback.assertNoCallback();
mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -2322,7 +2407,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, timeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, timeoutMs);
// pass timeout and validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
@@ -2343,7 +2428,7 @@ public class ConnectivityServiceTest extends AndroidTestCase {
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
final int assertTimeoutMs = 150;
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, assertTimeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs);
sleepFor(20);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index df3ce19b05e5..04fdae9f2db4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -106,7 +106,7 @@ import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
-import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
+import static android.os._Original_Build.VERSION_CODES.JELLY_BEAN_MR1;
import static com.android.layoutlib.bridge.android.RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE;
/**
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
index 5386b1758682..7f8d9928d7ce 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/Config.java
@@ -16,13 +16,13 @@
package com.android.layoutlib.bridge.bars;
-import android.os.Build.VERSION_CODES;
+import android.os._Original_Build.VERSION_CODES;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import static android.os.Build.VERSION_CODES.*;
+import static android.os._Original_Build.VERSION_CODES.*;
/**
* Various helper methods to simulate older versions of platform.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index a6e5fb841bff..8bb2c593f7a1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -49,7 +49,7 @@ import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
-import static android.os.Build.VERSION_CODES.LOLLIPOP;
+import static android.os._Original_Build.VERSION_CODES.LOLLIPOP;
/**
* Base "bar" class for the window decor around the the edited layout.
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index bed5806aadad..d59b41980179 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -37,6 +37,7 @@ import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
+import java.util.stream.Stream;
/**
* Class that generates a new JAR from a list of classes, some of which are to be kept as-is
@@ -127,7 +128,10 @@ public class AsmGenerator {
// Create the map of classes to rename.
mRenameClasses = new HashMap<>();
mClassesNotRenamed = new HashSet<>();
- String[] renameClasses = createInfo.getRenamedClasses();
+ String[] renameClasses = Stream.concat(
+ Arrays.stream(createInfo.getRenamedClasses()),
+ Arrays.stream(createInfo.getRefactoredClasses()))
+ .toArray(String[]::new);
int n = renameClasses.length;
for (int i = 0; i < n; i += 2) {
assert i + 1 < n;
@@ -140,7 +144,10 @@ public class AsmGenerator {
// Create a map of classes to be refactored.
mRefactorClasses = new HashMap<>();
- String[] refactorClasses = createInfo.getJavaPkgClasses();
+ String[] refactorClasses = Stream.concat(
+ Arrays.stream(createInfo.getJavaPkgClasses()),
+ Arrays.stream(createInfo.getRefactoredClasses()))
+ .toArray(String[]::new);
n = refactorClasses.length;
for (int i = 0; i < n; i += 2) {
assert i + 1 < n;
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index a8582c60bc64..b0aa3c2989a5 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -36,66 +36,42 @@ import java.util.Set;
*/
public final class CreateInfo implements ICreateInfo {
- /**
- * Returns the list of class from layoutlib_create to inject in layoutlib.
- * The list can be empty but must not be null.
- */
@Override
public Class<?>[] getInjectedClasses() {
return INJECTED_CLASSES;
}
- /**
- * Returns the list of methods to rewrite as delegates.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDelegateMethods() {
return DELEGATE_METHODS;
}
- /**
- * Returns the list of classes on which to delegate all native methods.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDelegateClassNatives() {
return DELEGATE_CLASS_NATIVES;
}
- /**
- * Returns the list of classes to rename, must be an even list: the binary FQCN
- * of class to replace followed by the new FQCN.
- * The list can be empty but must not be null.
- */
@Override
public String[] getRenamedClasses() {
return RENAMED_CLASSES;
}
- /**
- * Returns the list of classes for which the methods returning them should be deleted.
- * The array contains a list of null terminated section starting with the name of the class
- * to rename in which the methods are deleted, followed by a list of return types identifying
- * the methods to delete.
- * The list can be empty but must not be null.
- */
@Override
public String[] getDeleteReturns() {
return DELETE_RETURNS;
}
- /**
- * Returns the list of classes to refactor, must be an even list: the binary FQCN of class to
- * replace followed by the new FQCN. All references to the old class should be updated to the
- * new class. The list can be empty but must not be null.
- */
@Override
public String[] getJavaPkgClasses() {
return JAVA_PKG_CLASSES;
}
@Override
+ public String[] getRefactoredClasses() {
+ return REFACTOR_CLASSES;
+ }
+
+ @Override
public Set<String> getExcludedClasses() {
String[] refactoredClasses = getJavaPkgClasses();
int count = refactoredClasses.length / 2 + EXCLUDED_CLASSES.length;
@@ -333,10 +309,22 @@ public final class CreateInfo implements ICreateInfo {
"java.text.SimpleDateFormat", "android.icu.text.SimpleDateFormat",
};
+ /**
+ * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and
+ * {@link #getJavaPkgClasses()}.
+ * Classes included here will be renamed and then all their references in any other classes
+ * will be also modified.
+ * FQCN of class to refactor followed by its new FQCN.
+ */
+ private final static String[] REFACTOR_CLASSES =
+ new String[] {
+ "android.os.Build", "android.os._Original_Build",
+ };
+
private final static String[] EXCLUDED_CLASSES =
new String[] {
"android.preference.PreferenceActivity",
- "org.kxml2.io.KXmlParser"
+ "org.kxml2.io.KXmlParser",
};
/**
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
index 48abde4517e6..eca1c078faec 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -52,6 +52,15 @@ public interface ICreateInfo {
String[] getRenamedClasses();
/**
+ * List of classes to refactor. This is similar to combining {@link #getRenamedClasses()} and
+ * {@link #getJavaPkgClasses()}.
+ * Classes included here will be renamed and then all their references in any other classes
+ * will be also modified.
+ * FQCN of class to refactor followed by its new FQCN.
+ */
+ String[] getRefactoredClasses();
+
+ /**
* Returns the list of classes for which the methods returning them should be deleted.
* The array contains a list of null terminated section starting with the name of the class
* to rename in which the methods are deleted, followed by a list of return types identifying
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 4d5d5d2c4a6e..e718fb9133ee 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -35,6 +35,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashSet;
@@ -54,8 +55,6 @@ import static org.junit.Assert.assertTrue;
* Unit tests for some methods of {@link AsmGenerator}.
*/
public class AsmGeneratorTest {
-
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
private MockLog mLog;
private ArrayList<String> mOsJarPath;
private String mOsDestJar;
@@ -81,6 +80,7 @@ public class AsmGeneratorTest {
@After
public void tearDown() throws Exception {
if (mTempFile != null) {
+ //noinspection ResultOfMethodCallIgnored
mTempFile.delete();
mTempFile = null;
}
@@ -89,23 +89,7 @@ public class AsmGeneratorTest {
@Test
public void testClassRenaming() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
- @Override
- public Class<?>[] getInjectedClasses() {
- // classes to inject in the final JAR
- return new Class<?>[0];
- }
-
- @Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public String[] getRenamedClasses() {
// classes to rename (so that we can replace them)
@@ -114,37 +98,6 @@ public class AsmGeneratorTest {
"not.an.actual.ClassName", "anoter.fake.NewClassName",
};
}
-
- @Override
- public String[] getJavaPkgClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Set<String> getExcludedClasses() {
- return null;
- }
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -154,7 +107,7 @@ public class AsmGeneratorTest {
new String[] { // include classes
"**"
},
- Collections.<String>emptySet() /* excluded classes */,
+ Collections.emptySet() /* excluded classes */,
new String[]{} /* include files */);
aa.analyze();
agen.generate();
@@ -165,8 +118,8 @@ public class AsmGeneratorTest {
}
@Test
- public void testClassRefactoring() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
+ public void testJavaClassRefactoring() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Class<?>[] getInjectedClasses() {
// classes to inject in the final JAR
@@ -176,22 +129,6 @@ public class AsmGeneratorTest {
}
@Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
public String[] getJavaPkgClasses() {
// classes to refactor (so that we can replace them)
return new String[] {
@@ -203,27 +140,6 @@ public class AsmGeneratorTest {
public Set<String> getExcludedClasses() {
return Collections.singleton("java.lang.JavaClass");
}
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -233,7 +149,7 @@ public class AsmGeneratorTest {
new String[] { // include classes
"**"
},
- Collections.<String>emptySet(),
+ Collections.emptySet(),
new String[] { /* include files */
"mock_android/data/data*"
});
@@ -242,47 +158,64 @@ public class AsmGeneratorTest {
Map<String, ClassReader> output = new TreeMap<>();
Map<String, InputStream> filesFound = new TreeMap<>();
parseZip(mOsDestJar, output, filesFound);
- boolean injectedClassFound = false;
+ RecordingClassVisitor cv = new RecordingClassVisitor();
for (ClassReader cr: output.values()) {
- TestClassVisitor cv = new TestClassVisitor();
cr.accept(cv, 0);
- injectedClassFound |= cv.mInjectedClassFound;
}
- assertTrue(injectedClassFound);
+ assertTrue(cv.mVisitedClasses.contains(
+ "com/android/tools/layoutlib/create/dataclass/JavaClass"));
+ assertFalse(cv.mVisitedClasses.contains(
+ JAVA_CLASS_NAME));
assertArrayEquals(new String[] {"mock_android/data/dataFile"},
filesFound.keySet().toArray());
}
@Test
- public void testClassExclusion() throws IOException, LogAbortException {
- ICreateInfo ci = new ICreateInfo() {
+ public void testClassRefactoring() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Class<?>[] getInjectedClasses() {
- return new Class<?>[0];
- }
-
- @Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
+ // classes to inject in the final JAR
+ return new Class<?>[] {
+ com.android.tools.layoutlib.create.dataclass.JavaClass.class
+ };
}
@Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
+ public String[] getRefactoredClasses() {
+ // classes to refactor (so that we can replace them)
+ return new String[] {
+ "mock_android.view.View", "mock_android.view._Original_View",
+ };
}
+ };
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
+ AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
- @Override
- public String[] getJavaPkgClasses() {
- // classes to refactor (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
+ AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen,
+ null, // derived from
+ new String[] { // include classes
+ "**"
+ },
+ Collections.emptySet(),
+ new String[] {});
+ aa.analyze();
+ agen.generate();
+ Map<String, ClassReader> output = new TreeMap<>();
+ parseZip(mOsDestJar, output, new TreeMap<>());
+ RecordingClassVisitor cv = new RecordingClassVisitor();
+ for (ClassReader cr: output.values()) {
+ cr.accept(cv, 0);
+ }
+ assertTrue(cv.mVisitedClasses.contains(
+ "mock_android/view/_Original_View"));
+ assertFalse(cv.mVisitedClasses.contains(
+ "mock_android/view/View"));
+ }
+ @Test
+ public void testClassExclusion() throws IOException, LogAbortException {
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Set<String> getExcludedClasses() {
Set<String> set = new HashSet<>(2);
@@ -290,27 +223,6 @@ public class AsmGeneratorTest {
set.add("java.lang.JavaClass");
return set;
}
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
- return Collections.emptyMap();
- }
};
AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
@@ -340,55 +252,7 @@ public class AsmGeneratorTest {
public void testMethodInjection() throws IOException, LogAbortException,
ClassNotFoundException, IllegalAccessException, InstantiationException,
NoSuchMethodException, InvocationTargetException {
- ICreateInfo ci = new ICreateInfo() {
- @Override
- public Class<?>[] getInjectedClasses() {
- return new Class<?>[0];
- }
-
- @Override
- public String[] getDelegateMethods() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getDelegateClassNatives() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getRenamedClasses() {
- // classes to rename (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getJavaPkgClasses() {
- // classes to refactor (so that we can replace them)
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public Set<String> getExcludedClasses() {
- return Collections.emptySet();
- }
-
- @Override
- public String[] getDeleteReturns() {
- // methods deleted from their return type.
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedFields() {
- return EMPTY_STRING_ARRAY;
- }
-
- @Override
- public String[] getPromotedClasses() {
- return EMPTY_STRING_ARRAY;
- }
-
+ ICreateInfo ci = new CreateInfoAdapter() {
@Override
public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
return Collections.singletonMap("mock_android.util.EmptyArray",
@@ -474,97 +338,94 @@ public class AsmGeneratorTest {
}
}
- private class TestClassVisitor extends ClassVisitor {
+ /**
+ * {@link ClassVisitor} that records every class that sees.
+ */
+ private static class RecordingClassVisitor extends ClassVisitor {
+ private Set<String> mVisitedClasses = new HashSet<>();
- boolean mInjectedClassFound = false;
-
- TestClassVisitor() {
+ private RecordingClassVisitor() {
super(Main.ASM_VERSION);
}
+ private void addClass(String className) {
+ if (className == null) {
+ return;
+ }
+
+ int pos = className.indexOf('$');
+ if (pos > 0) {
+ // For inner classes, add also the base class
+ mVisitedClasses.add(className.substring(0, pos));
+ }
+ mVisitedClasses.add(className);
+ }
+
@Override
- public void visit(int version, int access, String name, String signature,
- String superName, String[] interfaces) {
- assertTrue(!getBase(name).equals(JAVA_CLASS_NAME));
- if (name.equals("com/android/tools/layoutlib/create/dataclass/JavaClass")) {
- mInjectedClassFound = true;
+ public void visit(int version, int access, String name, String signature, String superName,
+ String[] interfaces) {
+ addClass(superName);
+ Arrays.stream(interfaces).forEach(this::addClass);
+ }
+
+ private void processType(Type type) {
+ switch (type.getSort()) {
+ case Type.OBJECT:
+ addClass(type.getInternalName());
+ break;
+ case Type.ARRAY:
+ addClass(type.getElementType().getInternalName());
+ break;
+ case Type.METHOD:
+ processType(type.getReturnType());
+ Arrays.stream(type.getArgumentTypes()).forEach(this::processType);
+ break;
}
- super.visit(version, access, name, signature, superName, interfaces);
}
@Override
- public FieldVisitor visitField(int access, String name, String desc,
- String signature, Object value) {
- assertTrue(testType(Type.getType(desc)));
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value) {
+ processType(Type.getType(desc));
return super.visitField(access, name, desc, signature, value);
}
- @SuppressWarnings("hiding")
@Override
- public MethodVisitor visitMethod(int access, String name, String desc,
- String signature, String[] exceptions) {
+ public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+ String[] exceptions) {
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
return new MethodVisitor(Main.ASM_VERSION, mv) {
@Override
- public void visitFieldInsn(int opcode, String owner, String name,
- String desc) {
- assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
- assertTrue(testType(Type.getType(desc)));
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ addClass(owner);
+ processType(Type.getType(desc));
super.visitFieldInsn(opcode, owner, name, desc);
}
@Override
public void visitLdcInsn(Object cst) {
if (cst instanceof Type) {
- assertTrue(testType((Type)cst));
+ processType((Type) cst);
}
super.visitLdcInsn(cst);
}
@Override
public void visitTypeInsn(int opcode, String type) {
- assertTrue(!getBase(type).equals(JAVA_CLASS_NAME));
+ addClass(type);
super.visitTypeInsn(opcode, type);
}
@Override
- public void visitMethodInsn(int opcode, String owner, String name,
- String desc, boolean itf) {
- assertTrue(!getBase(owner).equals(JAVA_CLASS_NAME));
- assertTrue(testType(Type.getType(desc)));
+ public void visitMethodInsn(int opcode, String owner, String name, String desc,
+ boolean itf) {
+ addClass(owner);
+ processType(Type.getType(desc));
super.visitMethodInsn(opcode, owner, name, desc, itf);
}
};
}
-
- private boolean testType(Type type) {
- int sort = type.getSort();
- if (sort == Type.OBJECT) {
- assertTrue(!getBase(type.getInternalName()).equals(JAVA_CLASS_NAME));
- } else if (sort == Type.ARRAY) {
- assertTrue(!getBase(type.getElementType().getInternalName())
- .equals(JAVA_CLASS_NAME));
- } else if (sort == Type.METHOD) {
- boolean r = true;
- for (Type t : type.getArgumentTypes()) {
- r &= testType(t);
- }
- return r & testType(type.getReturnType());
- }
- return true;
- }
-
- private String getBase(String className) {
- if (className == null) {
- return null;
- }
- int pos = className.indexOf('$');
- if (pos > 0) {
- return className.substring(0, pos);
- }
- return className;
- }
}
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java
new file mode 100644
index 000000000000..ad7cb9a0ed40
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/CreateInfoAdapter.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+class CreateInfoAdapter implements ICreateInfo {
+ private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
+ @Override
+ public Class<?>[] getInjectedClasses() {
+ return new Class<?>[0];
+ }
+
+ @Override
+ public String[] getDelegateMethods() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getDelegateClassNatives() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getRenamedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getRefactoredClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getDeleteReturns() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getJavaPkgClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public Set<String> getExcludedClasses() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public String[] getPromotedFields() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public String[] getPromotedClasses() {
+ return EMPTY_STRING_ARRAY;
+ }
+
+ @Override
+ public Map<String, InjectMethodRunnable> getInjectedMethodsMap() {
+ return Collections.emptyMap();
+ }
+}
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index 57b98e984f17..59fe1ee6bc80 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -31,7 +31,7 @@ import java.lang.ref.WeakReference;
* {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
* class provides functionality common to both publish and subscribe discovery sessions:
* <ul>
- * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])}.
+ * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} method.
* <li>Creating a network-specifier when requesting a Aware connection:
* {@link #createNetworkSpecifier(PeerHandle, byte[])}.
* </ul>
@@ -247,8 +247,8 @@ public class DiscoverySession {
}
/**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
- * WiFi Aware connection to the specified peer. The
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
@@ -256,7 +256,58 @@ public class DiscoverySession {
* discovery or communication (in such scenarios the MAC address of the peer is shielded by
* an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
* OOB (out-of-band) mechanism then use the alternative
- * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
+ * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} method - which uses the
+ * peer's MAC address.
+ * <p>
+ * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
+ * and a Publisher is a RESPONDER.
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
+ * or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
+ * On a RESPONDER this value is used to gate the acceptance of a connection
+ * request from only that peer. A RESPONDER may specify a null - indicating
+ * that it will accept connection requests from any device.
+ *
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) {
+ if (mTerminated) {
+ Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session");
+ return null;
+ } else {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.w(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
+ return null;
+ }
+
+ int role = this instanceof SubscribeDiscoverySession
+ ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+ : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
+
+ return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, null);
+ }
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * encrypted WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p>
+ * This method should be used when setting up a connection with a peer discovered through Aware
+ * discovery or communication (in such scenarios the MAC address of the peer is shielded by
+ * an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
+ * OOB (out-of-band) mechanism then use the alternative
+ * {@link WifiAwareSession#createNetworkSpecifierPmk(int, byte[], byte[])} method - which uses the
* peer's MAC address.
* <p>
* Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
@@ -267,29 +318,34 @@ public class DiscoverySession {
* byte[], java.util.List)} or
* {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
- * from only that peer. A RESPONDER may specified a null - indicating that
+ * from only that peer. A RESPONDER may specify a null - indicating that
* it will accept connection requests from any device.
- * @param token An arbitrary token (message) to be used to match connection initiation request
- * to a responder setup. A RESPONDER is set up with a {@code token} which must
- * be matched by the token provided by the INITIATOR. A null token is permitted
- * on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
- * not the same as a null token and requires the peer token to be empty as well.
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the
+ * {@link #createNetworkSpecifierOpen(PeerHandle)} to specify an open (unencrypted)
+ * link.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
+ *
+ * @hide
*/
- public String createNetworkSpecifier(@Nullable PeerHandle peerHandle,
- @Nullable byte[] token) {
+ public String createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle,
+ @NonNull byte[] pmk) {
+ if (pmk == null || pmk.length == 0) {
+ throw new IllegalArgumentException("PMK must not be null or empty");
+ }
+
if (mTerminated) {
- Log.w(TAG, "createNetworkSpecifier: called on terminated session");
+ Log.w(TAG, "createNetworkSpecifierPmk: called on terminated session");
return null;
} else {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
- Log.w(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
+ Log.w(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
return null;
}
@@ -297,7 +353,30 @@ public class DiscoverySession {
? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, token);
+ return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, pmk);
}
}
+
+ /**
+ * Place-holder for {@code createNetworkSpecifierOpen(PeerHandle)}. Present to enable
+ * development of replacements CL without causing an API change. Will be removed when new
+ * APIs are exposed.
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
+ * byte[], java.util.List)} or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
+ * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
+ * from only that peer. A RESPONDER may specify a null - indicating that
+ * it will accept connection requests from any device.
+ * @param token Deprecated and ignored.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ */
+ public String createNetworkSpecifier(@Nullable PeerHandle peerHandle, @Nullable byte[] token) {
+ return createNetworkSpecifierOpen(peerHandle);
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 0eb6a3d157c3..3d784ba02fd6 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -130,55 +130,34 @@ public class WifiAwareManager {
*/
/**
- * TYPE_1A: role, client_id, session_id, peer_id, token
+ * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk optional
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1A = 0;
+ public static final int NETWORK_SPECIFIER_TYPE_IB = 0;
/**
- * TYPE_1B: role, client_id, session_id, peer_id [only permitted for RESPONDER]
+ * TYPE: in band, any peer: role, client_id, session_id, pmk optional
+ * [only permitted for RESPONDER]
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1B = 1;
+ public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1;
/**
- * TYPE_1C: role, client_id, session_id, token [only permitted for RESPONDER]
+ * TYPE: out-of-band: role, client_id, peer_mac, pmk optional
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1C = 2;
+ public static final int NETWORK_SPECIFIER_TYPE_OOB = 2;
/**
- * TYPE_1C: role, client_id, session_id [only permitted for RESPONDER]
+ * TYPE: out-of-band, any peer: role, client_id, pmk optional
+ * [only permitted for RESPONDER]
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1D = 3;
+ public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3;
- /**
- * TYPE_2A: role, client_id, peer_mac, token
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2A = 4;
-
- /**
- * TYPE_2B: role, client_id, peer_mac [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2B = 5;
-
- /**
- * TYPE_2C: role, client_id, token [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2C = 6;
-
- /**
- * TYPE_2D: role, client_id [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2D = 7;
/** @hide */
- public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_2D;
+ public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER;
/** @hide */
public static final String NETWORK_SPECIFIER_KEY_TYPE = "type";
@@ -199,7 +178,7 @@ public class WifiAwareManager {
public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac";
/** @hide */
- public static final String NETWORK_SPECIFIER_KEY_TOKEN = "token";
+ public static final String NETWORK_SPECIFIER_KEY_PMK = "pmk";
/**
* Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed.
@@ -494,23 +473,15 @@ public class WifiAwareManager {
/** @hide */
public String createNetworkSpecifier(int clientId, int role, int sessionId,
- PeerHandle peerHandle, byte[] token) {
+ PeerHandle peerHandle, @Nullable byte[] pmk) {
if (VDBG) {
Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
+ ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId)
- + ", token=" + token);
+ + ", pmk=" + ((pmk == null) ? "null" : "non-null"));
}
- int type;
- if (token != null && peerHandle != null) {
- type = NETWORK_SPECIFIER_TYPE_1A;
- } else if (token == null && peerHandle != null) {
- type = NETWORK_SPECIFIER_TYPE_1B;
- } else if (token != null && peerHandle == null) {
- type = NETWORK_SPECIFIER_TYPE_1C;
- } else {
- type = NETWORK_SPECIFIER_TYPE_1D;
- }
+ int type = (peerHandle == null) ? NETWORK_SPECIFIER_TYPE_IB_ANY_PEER
+ : NETWORK_SPECIFIER_TYPE_IB;
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
&& role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
@@ -519,10 +490,6 @@ public class WifiAwareManager {
+ "specifier");
}
if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (token == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
- }
if (peerHandle == null) {
throw new IllegalArgumentException(
"createNetworkSpecifier: Invalid peer handle (value of null) - not "
@@ -540,10 +507,11 @@ public class WifiAwareManager {
if (peerHandle != null) {
json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId);
}
- if (token != null) {
- json.put(NETWORK_SPECIFIER_KEY_TOKEN,
- Base64.encodeToString(token, 0, token.length, Base64.DEFAULT));
+ if (pmk == null) {
+ pmk = new byte[0];
}
+ json.put(NETWORK_SPECIFIER_KEY_PMK,
+ Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT));
} catch (JSONException e) {
return "";
}
@@ -553,21 +521,14 @@ public class WifiAwareManager {
/** @hide */
public String createNetworkSpecifier(int clientId, @DataPathRole int role,
- @Nullable byte[] peer, @Nullable byte[] token) {
+ @Nullable byte[] peer, @Nullable byte[] pmk) {
if (VDBG) {
- Log.v(TAG, "createNetworkSpecifier: role=" + role + ", token=" + token);
+ Log.v(TAG, "createNetworkSpecifier: role=" + role
+ + ", pmk=" + ((pmk == null) ? "null" : "non-null"));
}
- int type;
- if (token != null && peer != null) {
- type = NETWORK_SPECIFIER_TYPE_2A;
- } else if (token == null && peer != null) {
- type = NETWORK_SPECIFIER_TYPE_2B;
- } else if (token != null && peer == null) {
- type = NETWORK_SPECIFIER_TYPE_2C;
- } else { // both are null
- type = NETWORK_SPECIFIER_TYPE_2D;
- }
+ int type = (peer == null) ?
+ NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER : NETWORK_SPECIFIER_TYPE_OOB;
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
&& role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
@@ -576,20 +537,14 @@ public class WifiAwareManager {
+ "specifier");
}
if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (peer == null || peer.length != 6) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC address");
- }
- if (token == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
- }
- } else {
- if (peer != null && peer.length != 6) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC address");
+ if (peer == null) {
+ throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC "
+ + "address - null not permitted on INITIATOR");
}
}
+ if (peer != null && peer.length != 6) {
+ throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address");
+ }
JSONObject json;
try {
@@ -600,10 +555,11 @@ public class WifiAwareManager {
if (peer != null) {
json.put(NETWORK_SPECIFIER_KEY_PEER_MAC, new String(HexEncoding.encode(peer)));
}
- if (token != null) {
- json.put(NETWORK_SPECIFIER_KEY_TOKEN,
- Base64.encodeToString(token, 0, token.length, Base64.DEFAULT));
+ if (pmk == null) {
+ pmk = new byte[0];
}
+ json.put(NETWORK_SPECIFIER_KEY_PMK,
+ Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT));
} catch (JSONException e) {
return "";
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 86969200bc46..856066efff62 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -183,47 +183,114 @@ public class WifiAwareSession {
}
/**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
- * WiFi Aware connection to the specified peer. The
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link DiscoverySession#createNetworkSpecifier(PeerHandle,
- * byte[])}.
+ * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
- * peer. A RESPONDER may specified a null - indicating that it will accept
+ * peer. A RESPONDER may specify a null - indicating that it will accept
* connection requests from any device.
- * @param token An arbitrary token (message) to be used to match connection initiation request
- * to a responder setup. A RESPONDER is set up with a {@code token} which must
- * be matched by the token provided by the INITIATOR. A null token is permitted
- * on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
- * not the same as a null token and requires the peer token to be empty as well.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
+ *
+ * @hide
*/
- public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
- @Nullable byte[] peer, @Nullable byte[] token) {
+ public String createNetworkSpecifierOpen(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer) {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
- Log.e(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
+ Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
return "";
}
if (mTerminated) {
- Log.e(TAG, "createNetworkSpecifier: called after termination");
+ Log.e(TAG, "createNetworkSpecifierOpen: called after termination");
return "";
}
- return mgr.createNetworkSpecifier(mClientId, role, peer, token);
+ return mgr.createNetworkSpecifier(mClientId, role, peer, null);
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * encrypted WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p>
+ * This API is targeted for applications which can obtain the peer MAC address using OOB
+ * (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
+ * when using Aware discovery use the alternative network specifier method -
+ * {@link DiscoverySession#createNetworkSpecifierPmk(PeerHandle, byte[])}}.
+ *
+ * @param role The role of this device:
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
+ * value is used to gate the acceptance of a connection request from only that
+ * peer. A RESPONDER may specify a null - indicating that it will accept
+ * connection requests from any device.
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the {@link #createNetworkSpecifierOpen(int, byte[])}
+ * to specify an open (unencrypted) link.
+ *
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierPmk(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer, @NonNull byte[] pmk) {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
+ return "";
+ }
+ if (mTerminated) {
+ Log.e(TAG, "createNetworkSpecifierPmk: called after termination");
+ return "";
+ }
+ if (pmk == null || pmk.length == 0) {
+ throw new IllegalArgumentException("PMK must not be null or empty");
+ }
+ return mgr.createNetworkSpecifier(mClientId, role, peer, pmk);
+ }
+
+ /**
+ * Place-holder for {@code #createNetworkSpecifierOpen(int, byte[])}. Present to enable
+ * development of replacements CL without causing an API change. Will be removed when new
+ * APIs are exposed.
+ *
+ * @param role The role of this device:
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
+ * value is used to gate the acceptance of a connection request from only that
+ * peer. A RESPONDER may specify a null - indicating that it will accept
+ * connection requests from any device.
+ * @param token Deprecated and ignored.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ */
+ public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer, @Nullable byte[] token) {
+ return createNetworkSpecifierOpen(role, peer);
}
}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 7f68f6f128da..992958b84e1a 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -973,11 +973,11 @@ public class WifiAwareManagerTest {
final int sessionId = 123;
final PeerHandle peerHandle = new PeerHandle(123412);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- final String token = "Some arbitrary token string - can really be anything";
+ final byte[] pmk = "Some arbitrary byte array".getBytes();
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
- String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+ String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -1008,9 +1008,8 @@ public class WifiAwareManagerTest {
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
- // (3) request a network specifier from the session
- String networkSpecifier = publishSession.getValue().createNetworkSpecifier(peerHandle,
- token.getBytes());
+ // (3) request an open (unencrypted) network specifier from the session
+ String networkSpecifier = publishSession.getValue().createNetworkSpecifierOpen(peerHandle);
// validate format
JSONObject jsonObject = new JSONObject(networkSpecifier);
@@ -1022,8 +1021,22 @@ public class WifiAwareManagerTest {
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
collector.checkThat("peer_id", peerHandle.peerId,
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
- collector.checkThat("token", tokenB64,
- equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+ // (4) request an encrypted (PMK) network specifier from the session
+ networkSpecifier = publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
+
+ // validate format
+ jsonObject = new JSONObject(networkSpecifier);
+ collector.checkThat("role", role,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+ collector.checkThat("client_id", clientId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+ collector.checkThat("session_id", sessionId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
+ collector.checkThat("peer_id", peerHandle.peerId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
+ collector.checkThat("pmk", pmkB64 ,
+ equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK)));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);
@@ -1039,9 +1052,9 @@ public class WifiAwareManagerTest {
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
- final String token = "Some arbitrary token string - can really be anything";
+ final byte[] pmk = "Some arbitrary pmk data".getBytes();
- String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+ String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -1060,10 +1073,10 @@ public class WifiAwareManagerTest {
inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
WifiAwareSession session = sessionCaptor.getValue();
- /* (2) request a direct network specifier*/
- String networkSpecifier = session.createNetworkSpecifier(role, someMac, token.getBytes());
+ // (2) request an open (unencrypted) direct network specifier
+ String networkSpecifier = session.createNetworkSpecifierOpen(role, someMac);
- /* validate format*/
+ // validate format
JSONObject jsonObject = new JSONObject(networkSpecifier);
collector.checkThat("role", role,
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
@@ -1072,8 +1085,21 @@ public class WifiAwareManagerTest {
collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
false)));
- collector.checkThat("token", tokenB64,
- equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+ // (3) request an encrypted (PMK) direct network specifier
+ networkSpecifier = session.createNetworkSpecifierPmk(role, someMac, pmk);
+
+ // validate format
+ jsonObject = new JSONObject(networkSpecifier);
+ collector.checkThat("role", role,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+ collector.checkThat("client_id", clientId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+ collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
+ jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
+ false)));
+ collector.checkThat("pmk", pmkB64,
+ equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK)));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);