diff options
42 files changed, 1887 insertions, 366 deletions
diff --git a/api/current.txt b/api/current.txt index d5ece2e7301c..54bfac2cd59c 100644 --- a/api/current.txt +++ b/api/current.txt @@ -17289,6 +17289,7 @@ package android.hardware.camera2 { field public static final int LENS_OPTICAL_STABILIZATION_MODE_ON = 1; // 0x1 field public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1; // 0x1 field public static final int LENS_POSE_REFERENCE_PRIMARY_CAMERA = 0; // 0x0 + field public static final int LENS_POSE_REFERENCE_UNDEFINED = 2; // 0x2 field public static final int LENS_STATE_MOVING = 1; // 0x1 field public static final int LENS_STATE_STATIONARY = 0; // 0x0 field public static final int LOGICAL_MULTI_CAMERA_SENSOR_SYNC_TYPE_APPROXIMATE = 0; // 0x0 diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 9424862c56fe..4372e2245ee8 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -53,6 +53,7 @@ import "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.proto import "frameworks/base/core/proto/android/stats/mediaprovider/mediaprovider_enums.proto"; import "frameworks/base/core/proto/android/stats/storage/storage_enums.proto"; import "frameworks/base/core/proto/android/stats/style/style_enums.proto"; +import "frameworks/base/core/proto/android/stats/sysui/notification_enums.proto"; import "frameworks/base/core/proto/android/telecomm/enums.proto"; import "frameworks/base/core/proto/android/telephony/enums.proto"; import "frameworks/base/core/proto/android/view/enums.proto"; @@ -337,6 +338,9 @@ message Atom { BootTimeEventUtcTime boot_time_event_utc_time_reported = 241; BootTimeEventErrorCode boot_time_event_error_code_reported = 242; UserspaceRebootReported userspace_reboot_reported = 243; + NotificationReported notification_reported = 244; + NotificationPanelReported notification_panel_reported = 245; + NotificationChannelModified notification_panel_modified = 246; } // Pulled events will start at field 10000. @@ -3287,6 +3291,10 @@ message GenericAtom { * this button" or "this dialog was displayed". * Keep the UI event stream clean: don't use for system or background events. * Log using the UiEventLogger wrapper - don't write with the StatsLog API directly. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/ + * frameworks/base/packages/SystemUI/src/com/android/systemui/ */ message UiEventReported { // The event_id. @@ -3298,6 +3306,122 @@ message UiEventReported { } /** + * Reports a notification was created or updated. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/notification/ + */ +message NotificationReported { + // The event_id (as for UiEventReported). + optional int32 event_id = 1; + // The notifying app's uid and package. + optional int32 uid = 2 [(is_uid) = true]; + optional string package_name = 3; + // A small system-assigned identifier for the notification. + // Locally probably-unique, but expect collisions across users and/or days. + optional int32 instance_id = 4; + // The app-assigned notification ID and tag + optional int32 notification_id = 5; + optional string notification_tag = 6; + optional string channel_id = 7; // App-assigned channel ID + + // Grouping information + optional string group_id = 8; // Group the notification currently belongs to + optional int32 group_instance_id = 9; // Instance_id of the group-summary notification + optional bool is_group_summary = 10; // Tags the group-summary notification + + // Attributes + optional string category = 11; // App-assigned notification category (API-defined strings) + optional int32 style = 12; // App-assigned notification style + optional int32 num_people = 13; // Number of Person records attached to the notification + + // Ordering, importance and interruptiveness + + optional int32 position = 14; // Position in NotificationManager's list + + optional android.stats.sysui.NotificationImportance importance = 15; + optional int32 alerting = 16; // Bitfield, 1=buzz 2=beep 4=blink + + enum NotificationImportanceExplanation { + IMPORTANCE_EXPLANATION_UNKNOWN = 0; + IMPORTANCE_EXPLANATION_APP = 1; // App-specified channel importance. + IMPORTANCE_EXPLANATION_USER = 2; // User-specified channel importance. + IMPORTANCE_EXPLANATION_ASST = 3; // Notification Assistant override. + IMPORTANCE_EXPLANATION_SYSTEM = 4; // System override. + // Like _APP, but based on pre-channels priority signal. + IMPORTANCE_EXPLANATION_APP_PRE_CHANNELS = 5; + } + + optional NotificationImportanceExplanation importance_source = 17; + optional android.stats.sysui.NotificationImportance importance_initial = 18; + optional NotificationImportanceExplanation importance_initial_source = 19; + optional android.stats.sysui.NotificationImportance importance_asst = 20; + optional int32 assistant_hash = 21; + optional float assistant_ranking_score = 22; +} + +message Notification { + // The notifying app's uid and package. + optional int32 uid = 1 [(is_uid) = true]; + optional string package_name = 2; + // A small system-assigned identifier for the notification. + optional int32 instance_id = 3; + + // Grouping information. + optional int32 group_instance_id = 4; + optional bool is_group_summary = 5; + + // The section of the shade that the notification is in. + // See NotificationSectionsManager.PriorityBucket. + enum NotificationSection { + SECTION_UNKNOWN = 0; + SECTION_PEOPLE = 1; + SECTION_ALERTING = 2; + SECTION_SILENT = 3; + } + optional NotificationSection section = 6; +} + +message NotificationList { + repeated Notification notifications = 1; // An ordered sequence of notifications. +} + +/** + * Reports a notification panel was displayed, e.g. from the lockscreen or status bar. + * + * Logged from: + * frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/notification/ + */ +message NotificationPanelReported { + // The event_id (as for UiEventReported). + optional int32 event_id = 1; + optional int32 num_notifications = 2; + // The notifications in the panel, in the order that they appear there. + optional NotificationList notifications = 3 [(log_mode) = MODE_BYTES]; +} + +/** + * Reports a notification channel, or channel group, was created, updated, or deleted. + * + * Logged from: + * frameworks/base/services/core/java/com/android/server/notification/ + */ +message NotificationChannelModified { + // The event_id (as for UiEventReported). + optional int32 event_id = 1; + // The notifying app's uid and package. + optional int32 uid = 2 [(is_uid) = true]; + optional string package_name = 3; + // App-assigned notification channel ID or channel-group ID + optional string channel_id = 4; + // Previous importance setting, if applicable + optional android.stats.sysui.NotificationImportance old_importance = 5; + // New importance setting + optional android.stats.sysui.NotificationImportance importance = 6; +} + + +/** * Logs when a biometric acquire event occurs. * * Logged from: @@ -3485,12 +3609,14 @@ message BinaryPushStateChanged { INSTALL_FAILURE_DOWNLOAD = 23; INSTALL_FAILURE_STATE_MISMATCH = 24; INSTALL_FAILURE_COMMIT = 25; + REBOOT_TRIGGERED = 26; } optional State state = 6; // Possible experiment ids for monitoring this push. optional TrainExperimentIds experiment_ids = 7 [(log_mode) = MODE_BYTES]; // user id optional int32 user_id = 8; + optional int32 reason = 9; } /* Test atom, is not logged anywhere */ @@ -6782,6 +6908,7 @@ message TrainInfo { INSTALL_FAILURE_DOWNLOAD = 23; INSTALL_FAILURE_STATE_MISMATCH = 24; INSTALL_FAILURE_COMMIT = 25; + REBOOT_TRIGGERED = 26; } optional Status status = 4; } diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java index 70262b08dcc9..0c5e67cd4c6a 100644 --- a/core/java/android/app/LoadedApk.java +++ b/core/java/android/app/LoadedApk.java @@ -464,6 +464,9 @@ public final class LoadedApk { || appDir.equals(instrumentedAppDir)) { outZipPaths.clear(); outZipPaths.add(instrumentationAppDir); + if (!instrumentationAppDir.equals(instrumentedAppDir)) { + outZipPaths.add(instrumentedAppDir); + } // Only add splits if the app did not request isolated split loading. if (!aInfo.requestsIsolatedSplitLoading()) { @@ -472,7 +475,6 @@ public final class LoadedApk { } if (!instrumentationAppDir.equals(instrumentedAppDir)) { - outZipPaths.add(instrumentedAppDir); if (instrumentedSplitAppDirs != null) { Collections.addAll(outZipPaths, instrumentedSplitAppDirs); } diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java index a45648f06093..7bddc1decae1 100644 --- a/core/java/android/hardware/camera2/CameraCharacteristics.java +++ b/core/java/android/hardware/camera2/CameraCharacteristics.java @@ -1539,10 +1539,15 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <p><code>p' = Rp</code></p> * <p>where <code>p</code> is in the device sensor coordinate system, and * <code>p'</code> is in the camera-oriented coordinate system.</p> + * <p>If {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, the quaternion rotation cannot + * be accurately represented by the camera device, and will be represented by + * default values matching its default facing.</p> * <p><b>Units</b>: * Quaternion coefficients</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p> + * + * @see CameraCharacteristics#LENS_POSE_REFERENCE */ @PublicKey @NonNull @@ -1577,6 +1582,8 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to * the center of the primary gyroscope on the device. The axis definitions are the same as * with PRIMARY_CAMERA.</p> + * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, this position cannot be accurately + * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p> * <p><b>Units</b>: Meters</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p> @@ -1714,20 +1721,24 @@ public final class CameraCharacteristics extends CameraMetadata<CameraCharacteri new Key<float[]>("android.lens.radialDistortion", float[].class); /** - * <p>The origin for {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}.</p> + * <p>The origin for {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation}, and the accuracy of + * {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} and {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation}.</p> * <p>Different calibration methods and use cases can produce better or worse results * depending on the selected coordinate origin.</p> * <p><b>Possible values:</b> * <ul> * <li>{@link #LENS_POSE_REFERENCE_PRIMARY_CAMERA PRIMARY_CAMERA}</li> * <li>{@link #LENS_POSE_REFERENCE_GYROSCOPE GYROSCOPE}</li> + * <li>{@link #LENS_POSE_REFERENCE_UNDEFINED UNDEFINED}</li> * </ul></p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p> * + * @see CameraCharacteristics#LENS_POSE_ROTATION * @see CameraCharacteristics#LENS_POSE_TRANSLATION * @see #LENS_POSE_REFERENCE_PRIMARY_CAMERA * @see #LENS_POSE_REFERENCE_GYROSCOPE + * @see #LENS_POSE_REFERENCE_UNDEFINED */ @PublicKey @NonNull diff --git a/core/java/android/hardware/camera2/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java index ec13a36ca1d2..2377ccde5f89 100644 --- a/core/java/android/hardware/camera2/CameraMetadata.java +++ b/core/java/android/hardware/camera2/CameraMetadata.java @@ -366,6 +366,20 @@ public abstract class CameraMetadata<TKey> { */ public static final int LENS_POSE_REFERENCE_GYROSCOPE = 1; + /** + * <p>The camera device cannot represent the values of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} + * and {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} accurately enough. One such example is a camera device + * on the cover of a foldable phone: in order to measure the pose translation and rotation, + * some kind of hinge position sensor would be needed.</p> + * <p>The value of {@link CameraCharacteristics#LENS_POSE_TRANSLATION android.lens.poseTranslation} must be all zeros, and + * {@link CameraCharacteristics#LENS_POSE_ROTATION android.lens.poseRotation} must be values matching its default facing.</p> + * + * @see CameraCharacteristics#LENS_POSE_ROTATION + * @see CameraCharacteristics#LENS_POSE_TRANSLATION + * @see CameraCharacteristics#LENS_POSE_REFERENCE + */ + public static final int LENS_POSE_REFERENCE_UNDEFINED = 2; + // // Enumeration values for CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES // diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java index 9b305b32b61d..6f0d1358a1b7 100644 --- a/core/java/android/hardware/camera2/CaptureResult.java +++ b/core/java/android/hardware/camera2/CaptureResult.java @@ -3027,10 +3027,15 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <p><code>p' = Rp</code></p> * <p>where <code>p</code> is in the device sensor coordinate system, and * <code>p'</code> is in the camera-oriented coordinate system.</p> + * <p>If {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, the quaternion rotation cannot + * be accurately represented by the camera device, and will be represented by + * default values matching its default facing.</p> * <p><b>Units</b>: * Quaternion coefficients</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p> + * + * @see CameraCharacteristics#LENS_POSE_REFERENCE */ @PublicKey @NonNull @@ -3065,6 +3070,8 @@ public class CaptureResult extends CameraMetadata<CaptureResult.Key<?>> { * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is GYROSCOPE, then this position is relative to * the center of the primary gyroscope on the device. The axis definitions are the same as * with PRIMARY_CAMERA.</p> + * <p>When {@link CameraCharacteristics#LENS_POSE_REFERENCE android.lens.poseReference} is UNDEFINED, this position cannot be accurately + * represented by the camera device, and will be represented as <code>(0, 0, 0)</code>.</p> * <p><b>Units</b>: Meters</p> * <p><b>Optional</b> - The value for this key may be {@code null} on some devices.</p> * <p><b>Permission {@link android.Manifest.permission#CAMERA } is needed to access this property</b></p> diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java index ff8455ab0915..cc4278bdd2b6 100644 --- a/core/java/android/view/SurfaceControl.java +++ b/core/java/android/view/SurfaceControl.java @@ -122,6 +122,8 @@ public final class SurfaceControl implements Parcelable { private static native void nativeSetColor(long transactionObj, long nativeObject, float[] color); private static native void nativeSetFlags(long transactionObj, long nativeObject, int flags, int mask); + private static native void nativeSetFrameRateSelectionPriority(long transactionObj, + long nativeObject, int priority); private static native void nativeSetWindowCrop(long transactionObj, long nativeObject, int l, int t, int r, int b); private static native void nativeSetCornerRadius(long transactionObj, long nativeObject, @@ -2245,6 +2247,19 @@ public final class SurfaceControl implements Parcelable { } /** + * This information is passed to SurfaceFlinger to decide which window should have a + * priority when deciding about the refresh rate of the display. All windows have the + * lowest priority by default. + * @hide + */ + @NonNull + public Transaction setFrameRateSelectionPriority(@NonNull SurfaceControl sc, int priority) { + sc.checkNotReleased(); + nativeSetFrameRateSelectionPriority(mNativeObject, sc.mNativeObject, priority); + return this; + } + + /** * Request that a given surface and it's sub-tree be shown. * * @param sc The surface to show. diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp index b47080f787a1..573f378f57b1 100644 --- a/core/jni/android_view_SurfaceControl.cpp +++ b/core/jni/android_view_SurfaceControl.cpp @@ -423,6 +423,14 @@ static void nativeSetFlags(JNIEnv* env, jclass clazz, jlong transactionObj, transaction->setFlags(ctrl, flags, mask); } +static void nativeSetFrameRateSelectionPriority(JNIEnv* env, jclass clazz, jlong transactionObj, + jlong nativeObject, jint priority) { + auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj); + + SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); + transaction->setFrameRateSelectionPriority(ctrl, priority); +} + static void nativeSetTransparentRegionHint(JNIEnv* env, jclass clazz, jlong transactionObj, jlong nativeObject, jobject regionObj) { SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject); @@ -1362,6 +1370,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = { (void*)nativeSetColorSpaceAgnostic }, {"nativeSetFlags", "(JJII)V", (void*)nativeSetFlags }, + {"nativeSetFrameRateSelectionPriority", "(JJI)V", + (void*)nativeSetFrameRateSelectionPriority }, {"nativeSetWindowCrop", "(JJIIII)V", (void*)nativeSetWindowCrop }, {"nativeSetCornerRadius", "(JJF)V", diff --git a/core/proto/android/stats/sysui/notification_enums.proto b/core/proto/android/stats/sysui/notification_enums.proto new file mode 100644 index 000000000000..09837022e50d --- /dev/null +++ b/core/proto/android/stats/sysui/notification_enums.proto @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2020 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. + */ + +syntax = "proto2"; + +package android.stats.sysui; + +// Enum used in NotificationReported and NotificationChannelModified atoms +enum NotificationImportance { // Constants from NotificationManager.java + IMPORTANCE_UNSPECIFIED = -1000; // Should not occur for real notifications. + IMPORTANCE_NONE = 0; // No importance: does not show in the shade. + IMPORTANCE_MIN = 1; // Minimum to show in the shade. + IMPORTANCE_LOW = 2; // Shows in shade, maybe status bar, no buzz/beep. + IMPORTANCE_DEFAULT = 3; // Shows everywhere, makes noise, no heads-up. + IMPORTANCE_HIGH = 4; // Shows everywhere, makes noise, heads-up, may full-screen. +} diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp index b93759f87da2..c445885c5c63 100644 --- a/libs/hwui/utils/Color.cpp +++ b/libs/hwui/utils/Color.cpp @@ -108,10 +108,26 @@ SkColorType PixelFormatToColorType(android::PixelFormat format) { } } +// FIXME: Share with the version in android_bitmap.cpp? +// Skia's SkNamedGamut::kDCIP3 is based on a white point of D65. This gamut +// matches the white point used by ColorSpace.Named.DCIP3. +static constexpr skcms_Matrix3x3 kDCIP3 = {{ + {0.486143, 0.323835, 0.154234}, + {0.226676, 0.710327, 0.0629966}, + {0.000800549, 0.0432385, 0.78275}, +}}; + sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { if (dataspace == HAL_DATASPACE_UNKNOWN) { return SkColorSpace::MakeSRGB(); } + if (dataspace == HAL_DATASPACE_DCI_P3) { + // This cannot be handled by the switch statements below because it + // needs to use the locally-defined kDCIP3 gamut, rather than the one in + // Skia (SkNamedGamut), which is used for other data spaces with + // HAL_DATASPACE_STANDARD_DCI_P3 (e.g. HAL_DATASPACE_DISPLAY_P3). + return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, kDCIP3); + } skcms_Matrix3x3 gamut; switch (dataspace & HAL_DATASPACE_STANDARD_MASK) { @@ -152,10 +168,12 @@ sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) { return SkColorSpace::MakeRGB({2.6f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut); case HAL_DATASPACE_TRANSFER_GAMMA2_8: return SkColorSpace::MakeRGB({2.8f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, gamut); + case HAL_DATASPACE_TRANSFER_ST2084: + return SkColorSpace::MakeRGB(SkNamedTransferFn::kPQ, gamut); + case HAL_DATASPACE_TRANSFER_SMPTE_170M: + return SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, gamut); case HAL_DATASPACE_TRANSFER_UNSPECIFIED: return nullptr; - case HAL_DATASPACE_TRANSFER_SMPTE_170M: - case HAL_DATASPACE_TRANSFER_ST2084: case HAL_DATASPACE_TRANSFER_HLG: default: ALOGV("Unsupported Gamma: %d", dataspace); diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 5a72b221ce08..18969ae3279c 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -16,6 +16,7 @@ package android.media.tv.tuner; +import android.annotation.BytesLong; import android.annotation.CallbackExecutor; import android.annotation.NonNull; import android.annotation.Nullable; @@ -27,6 +28,8 @@ import android.media.tv.tuner.TunerConstants.FilterSubtype; import android.media.tv.tuner.TunerConstants.FrontendScanType; import android.media.tv.tuner.TunerConstants.Result; import android.media.tv.tuner.dvr.Dvr; +import android.media.tv.tuner.dvr.DvrCallback; +import android.media.tv.tuner.dvr.DvrSettings; import android.media.tv.tuner.filter.FilterConfiguration.FilterType; import android.media.tv.tuner.filter.FilterEvent; import android.media.tv.tuner.filter.TimeFilter; @@ -88,6 +91,31 @@ public final class Tuner implements AutoCloseable { nativeSetup(); } + /** + * Constructs a Tuner instance. + * + * @param context the context of the caller. + * @param tvInputSessionId the session ID of the TV input. + * @param useCase the use case of this Tuner instance. + * + * @hide + * TODO: replace the other constructor + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + public Tuner(@NonNull Context context, @NonNull String tvInputSessionId, int useCase) { + mContext = context; + } + + /** + * Shares the frontend resource with another Tuner instance + * + * @param tuner the Tuner instance to share frontend resource with. + * + * @hide + */ + public void shareFrontend(@NonNull Tuner tuner) { } + + private long mNativeContext; // used by native jMediaTuner /** @hide */ @@ -125,7 +153,7 @@ public final class Tuner implements AutoCloseable { private native int nativeConnectCiCam(int ciCamId); private native int nativeDisconnectCiCam(); private native FrontendInfo nativeGetFrontendInfo(int id); - private native Filter nativeOpenFilter(int type, int subType, int bufferSize); + private native Filter nativeOpenFilter(int type, int subType, long bufferSize); private native TimeFilter nativeOpenTimeFilter(); private native List<Integer> nativeGetLnbIds(); @@ -133,7 +161,7 @@ public final class Tuner implements AutoCloseable { private native Descrambler nativeOpenDescrambler(); - private native Dvr nativeOpenDvr(int type, int bufferSize); + private native Dvr nativeOpenDvr(int type, long bufferSize); private static native DemuxCapabilities nativeGetDemuxCapabilities(); @@ -159,6 +187,21 @@ public final class Tuner implements AutoCloseable { void onFilterStatusChanged(@NonNull Filter filter, @FilterStatus int status); } + + /** + * Listener for resource lost. + * + * @hide + */ + public interface OnResourceLostListener { + /** + * Invoked when resource lost. + * + * @param tuner the tuner instance whose resource is being reclaimed. + */ + void onResourceLost(@NonNull Tuner tuner); + } + @Nullable private EventHandler createEventHandler() { Looper looper; @@ -221,23 +264,32 @@ public final class Tuner implements AutoCloseable { /** * Stops a previous tuning. * - * If the method completes successfully the frontend is no longer tuned and no data + * <p>If the method completes successfully, the frontend is no longer tuned and no data * will be sent to attached filters. * * @return result status of the operation. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @Result public int stopTune() { + TunerUtils.checkTunerPermission(mContext); return nativeStopTune(); } /** * Scan channels. + * + * @param settings A {@link FrontendSettings} to configure the frontend. + * @param scanType The scan type. + * * @hide */ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int scan(@NonNull FrontendSettings settings, @FrontendScanType int scanType, @NonNull @CallbackExecutor Executor executor, @NonNull ScanCallback scanCallback) { + TunerUtils.checkTunerPermission(mContext); mScanCallback = scanCallback; mScanCallbackExecutor = executor; return nativeScan(settings.getType(), settings, scanType); @@ -255,6 +307,7 @@ public final class Tuner implements AutoCloseable { * @hide */ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @Result public int stopScan() { TunerUtils.checkTunerPermission(mContext); int retVal = nativeStopScan(); @@ -266,37 +319,44 @@ public final class Tuner implements AutoCloseable { /** * Sets Low-Noise Block downconverter (LNB) for satellite frontend. * - * This assigns a hardware LNB resource to the satellite tuner. It can be + * <p>This assigns a hardware LNB resource to the satellite tuner. It can be * called multiple times to update LNB assignment. * * @param lnb the LNB instance. * * @return result status of the operation. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @Result public int setLnb(@NonNull Lnb lnb) { + TunerUtils.checkTunerPermission(mContext); return nativeSetLnb(lnb.mId); } /** * Enable or Disable Low Noise Amplifier (LNA). * - * @param enable true to activate LNA module; false to deactivate LNA + * @param enable {@code true} to activate LNA module; {@code false} to deactivate LNA. * * @return result status of the operation. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @Result public int setLna(boolean enable) { + TunerUtils.checkTunerPermission(mContext); return nativeSetLna(enable); } /** * Gets the statuses of the frontend. * - * This retrieve the statuses of the frontend for given status types. - * - * @param statusTypes an array of status type which the caller request. + * <p>This retrieve the statuses of the frontend for given status types. * + * @param statusTypes an array of status types which the caller requests. * @return statuses which response the caller's requests. * @hide */ @@ -310,59 +370,77 @@ public final class Tuner implements AutoCloseable { * * @param filter the filter instance for the hardware sync ID. * @return the id of hardware A/V sync. + * * @hide */ - public int getAvSyncHwId(Filter filter) { + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + public int getAvSyncHwId(@NonNull Filter filter) { + TunerUtils.checkTunerPermission(mContext); return nativeGetAvSyncHwId(filter); } + /** - * Gets the current timestamp for A/V sync + * Gets the current timestamp for Audio/Video sync * - * The timestamp is maintained by hardware. The timestamp based on 90KHz, and it's format is the - * same as PTS (Presentation Time Stamp). + * <p>The timestamp is maintained by hardware. The timestamp based on 90KHz, and it's format is + * the same as PTS (Presentation Time Stamp). * * @param avSyncHwId the hardware id of A/V sync. * @return the current timestamp of hardware A/V sync. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public long getAvSyncTime(int avSyncHwId) { + TunerUtils.checkTunerPermission(mContext); return nativeGetAvSyncTime(avSyncHwId); } - /** * Connects Conditional Access Modules (CAM) through Common Interface (CI) * - * The demux uses the output from the frontend as the input by default, and must change to use - * the output from CI-CAM as the input after this call. + * <p>The demux uses the output from the frontend as the input by default, and must change to + * use the output from CI-CAM as the input after this call. * * @param ciCamId specify CI-CAM Id to connect. * @return result status of the operation. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) @Result public int connectCiCam(int ciCamId) { + TunerUtils.checkTunerPermission(mContext); return nativeConnectCiCam(ciCamId); } /** * Disconnects Conditional Access Modules (CAM) * - * The demux will use the output from the frontend as the input after this call. + * <p>The demux will use the output from the frontend as the input after this call. * * @return result status of the operation. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) @Result public int disconnectCiCam() { + TunerUtils.checkTunerPermission(mContext); return nativeDisconnectCiCam(); } /** - * Retrieve the frontend information. + * Gets the frontend information. + * + * @return The frontend information. {@code null} if the operation failed. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @Nullable public FrontendInfo getFrontendInfo() { + TunerUtils.checkTunerPermission(mContext); if (mFrontend == null) { throw new IllegalStateException("frontend is not initialized"); } @@ -370,10 +448,13 @@ public final class Tuner implements AutoCloseable { } /** - * Gets frontend ID. + * Gets the frontend ID. + * * @hide */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) public int getFrontendId() { + TunerUtils.checkTunerPermission(mContext); if (mFrontend == null) { throw new IllegalStateException("frontend is not initialized"); } @@ -382,6 +463,7 @@ public final class Tuner implements AutoCloseable { /** * Gets Demux capabilities. + * * @hide */ @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) @@ -424,8 +506,26 @@ public final class Tuner implements AutoCloseable { private Filter() {} } - private Filter openFilter(@FilterType int mainType, @FilterSubtype int subType, int bufferSize, - FilterCallback cb) { + /** + * Opens a filter object based on the given types and buffer size. + * + * @param mainType the main type of the filter. + * @param subType the subtype of the filter. + * @param bufferSize the buffer size of the filter to be opened in bytes. The buffer holds the + * data output from the filter. + * @param cb the callback to receive notifications from filter. + * @param executor the executor on which callback will be invoked. The default event handler + * executor is used if it's {@code null}. + * @return the opened filter. {@code null} if the operation failed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @Nullable + public Filter openFilter(@FilterType int mainType, @FilterSubtype int subType, + @BytesLong long bufferSize, @Nullable FilterCallback cb, + @CallbackExecutor @Nullable Executor executor) { + TunerUtils.checkTunerPermission(mContext); Filter filter = nativeOpenFilter( mainType, TunerUtils.getFilterSubtype(mainType, subType), bufferSize); if (filter != null) { @@ -437,6 +537,24 @@ public final class Tuner implements AutoCloseable { return filter; } + /** + * Opens an LNB (low-noise block downconverter) object. + * + * @param cb the callback to receive notifications from LNB. + * @param executor the executor on which callback will be invoked. The default event handler + * executor is used if it's {@code null}. + * @return the opened LNB object. {@code null} if the operation failed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @Nullable + public Lnb openLnb(LnbCallback cb, @CallbackExecutor @Nullable Executor executor) { + TunerUtils.checkTunerPermission(mContext); + // TODO: use resource manager to get LNB ID. + return new Lnb(0); + } + private List<Integer> getLnbIds() { mLnbIds = nativeGetLnbIds(); return mLnbIds; @@ -484,7 +602,24 @@ public final class Tuner implements AutoCloseable { return nativeOpenDescrambler(); } - private Dvr openDvr(int type, int bufferSize) { + /** + * Open a DVR (Digital Video Record) instance. + * + * @param type the DVR type to be opened. + * @param bufferSize the buffer size of the output in bytes. It's used to hold output data of + * the attached filters. + * @param cb the callback to receive notifications from DVR. + * @param executor the executor on which callback will be invoked. The default event handler + * executor is used if it's {@code null}. + * @return the opened DVR object. {@code null} if the operation failed. + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @Nullable + public Dvr openDvr(@DvrSettings.Type int type, @BytesLong long bufferSize, DvrCallback cb, + @CallbackExecutor @Nullable Executor executor) { + TunerUtils.checkTunerPermission(mContext); Dvr dvr = nativeOpenDvr(type, bufferSize); return dvr; } diff --git a/media/java/android/media/tv/tuner/TunerConstants.java b/media/java/android/media/tv/tuner/TunerConstants.java index 19cfa32eccd6..fa8f550867b8 100644 --- a/media/java/android/media/tv/tuner/TunerConstants.java +++ b/media/java/android/media/tv/tuner/TunerConstants.java @@ -129,93 +129,29 @@ public final class TunerConstants { */ public static final int FILTER_STATUS_OVERFLOW = Constants.DemuxFilterStatus.OVERFLOW; - /** - * Indexes can be tagged through TS (Transport Stream) header. - * - * @hide - */ - @IntDef(flag = true, value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR, - TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED, - TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR, - TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR, TS_INDEX_PCR_FLAG, - TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG, TS_INDEX_PRIVATE_DATA, - TS_INDEX_ADAPTATION_EXTENSION_FLAG}) + + /** @hide */ @Retention(RetentionPolicy.SOURCE) - public @interface TsIndex {} + @IntDef(prefix = "INDEX_TYPE_", value = + {INDEX_TYPE_NONE, INDEX_TYPE_SC, INDEX_TYPE_SC_HEVC}) + public @interface ScIndexType {} /** - * TS index FIRST_PACKET. + * Start Code Index is not used. * @hide */ - public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET; + public static final int INDEX_TYPE_NONE = Constants.DemuxRecordScIndexType.NONE; /** - * TS index PAYLOAD_UNIT_START_INDICATOR. + * Start Code index. * @hide */ - public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR = - Constants.DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR; + public static final int INDEX_TYPE_SC = Constants.DemuxRecordScIndexType.SC; /** - * TS index CHANGE_TO_NOT_SCRAMBLED. + * Start Code index for HEVC. * @hide */ - public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = - Constants.DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED; - /** - * TS index CHANGE_TO_EVEN_SCRAMBLED. - * @hide - */ - public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED = - Constants.DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED; - /** - * TS index CHANGE_TO_ODD_SCRAMBLED. - * @hide - */ - public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED = - Constants.DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED; - /** - * TS index DISCONTINUITY_INDICATOR. - * @hide - */ - public static final int TS_INDEX_DISCONTINUITY_INDICATOR = - Constants.DemuxTsIndex.DISCONTINUITY_INDICATOR; - /** - * TS index RANDOM_ACCESS_INDICATOR. - * @hide - */ - public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR = - Constants.DemuxTsIndex.RANDOM_ACCESS_INDICATOR; - /** - * TS index PRIORITY_INDICATOR. - * @hide - */ - public static final int TS_INDEX_PRIORITY_INDICATOR = Constants.DemuxTsIndex.PRIORITY_INDICATOR; - /** - * TS index PCR_FLAG. - * @hide - */ - public static final int TS_INDEX_PCR_FLAG = Constants.DemuxTsIndex.PCR_FLAG; - /** - * TS index OPCR_FLAG. - * @hide - */ - public static final int TS_INDEX_OPCR_FLAG = Constants.DemuxTsIndex.OPCR_FLAG; - /** - * TS index SPLICING_POINT_FLAG. - * @hide - */ - public static final int TS_INDEX_SPLICING_POINT_FLAG = - Constants.DemuxTsIndex.SPLICING_POINT_FLAG; - /** - * TS index PRIVATE_DATA. - * @hide - */ - public static final int TS_INDEX_PRIVATE_DATA = Constants.DemuxTsIndex.PRIVATE_DATA; - /** - * TS index ADAPTATION_EXTENSION_FLAG. - * @hide - */ - public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG = - Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG; + public static final int INDEX_TYPE_SC_HEVC = Constants.DemuxRecordScIndexType.SC_HEVC; + /** * Indexes can be tagged by Start Code in PES (Packetized Elementary Stream) diff --git a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java index f0fe533093ba..fcca6a1615c3 100644 --- a/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/AlpFilterConfiguration.java @@ -16,20 +16,123 @@ package android.media.tv.tuner.filter; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.hardware.tv.tuner.V1_0.Constants; +import android.media.tv.tuner.TunerUtils; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * Filter configuration for a ALP filter. * @hide */ public class AlpFilterConfiguration extends FilterConfiguration { - private int mPacketType; - private int mLengthType; + /** @hide */ + @Retention(RetentionPolicy.SOURCE) + @IntDef(prefix = "LENGTH_TYPE_", value = + {LENGTH_TYPE_UNDEFINED, LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER, + LENGTH_TYPE_WITH_ADDITIONAL_HEADER}) + public @interface LengthType {} + + /** + * Length type not defined. + */ + public static final int LENGTH_TYPE_UNDEFINED = Constants.DemuxAlpLengthType.UNDEFINED; + /** + * Length does NOT include additional header. + */ + public static final int LENGTH_TYPE_WITHOUT_ADDITIONAL_HEADER = + Constants.DemuxAlpLengthType.WITHOUT_ADDITIONAL_HEADER; + /** + * Length includes additional header. + */ + public static final int LENGTH_TYPE_WITH_ADDITIONAL_HEADER = + Constants.DemuxAlpLengthType.WITH_ADDITIONAL_HEADER; + - public AlpFilterConfiguration(Settings settings) { + private final int mPacketType; + private final int mLengthType; + + public AlpFilterConfiguration(Settings settings, int packetType, int lengthType) { super(settings); + mPacketType = packetType; + mLengthType = lengthType; } @Override public int getType() { return FilterConfiguration.FILTER_TYPE_ALP; } + + /** + * Gets packet type. + */ + @FilterConfiguration.PacketType + public int getPacketType() { + return mPacketType; + } + /** + * Gets length type. + */ + @LengthType + public int getLengthType() { + return mLengthType; + } + + /** + * Creates a builder for {@link AlpFilterConfiguration}. + * + * @param context the context of the caller. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder(@NonNull Context context) { + TunerUtils.checkTunerPermission(context); + return new Builder(); + } + + /** + * Builder for {@link AlpFilterConfiguration}. + */ + public static class Builder extends FilterConfiguration.Builder<Builder> { + private int mPacketType; + private int mLengthType; + + private Builder() { + } + + /** + * Sets packet type. + */ + @NonNull + public Builder setPacketType(@FilterConfiguration.PacketType int packetType) { + mPacketType = packetType; + return this; + } + /** + * Sets length type. + */ + @NonNull + public Builder setLengthType(@LengthType int lengthType) { + mLengthType = lengthType; + return this; + } + + /** + * Builds a {@link AlpFilterConfiguration} object. + */ + @NonNull + public AlpFilterConfiguration build() { + return new AlpFilterConfiguration(mSettings, mPacketType, mLengthType); + } + + @Override + Builder self() { + return this; + } + } } diff --git a/media/java/android/media/tv/tuner/filter/AvSettings.java b/media/java/android/media/tv/tuner/filter/AvSettings.java index a7c49d5585f8..940b5ae44a74 100644 --- a/media/java/android/media/tv/tuner/filter/AvSettings.java +++ b/media/java/android/media/tv/tuner/filter/AvSettings.java @@ -16,21 +16,84 @@ package android.media.tv.tuner.filter; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; import android.media.tv.tuner.TunerConstants; import android.media.tv.tuner.TunerUtils; +import android.media.tv.tuner.filter.FilterConfiguration.FilterType; /** * Filter Settings for a Video and Audio. + * * @hide */ public class AvSettings extends Settings { - private boolean mIsPassthrough; + private final boolean mIsPassthrough; - private AvSettings(int mainType, boolean isAudio) { + private AvSettings(int mainType, boolean isAudio, boolean isPassthrough) { super(TunerUtils.getFilterSubtype( mainType, isAudio ? TunerConstants.FILTER_SUBTYPE_AUDIO : TunerConstants.FILTER_SUBTYPE_VIDEO)); + mIsPassthrough = isPassthrough; + } + + /** + * Checks whether it's passthrough. + */ + public boolean isPassthrough() { + return mIsPassthrough; + } + + /** + * Creates a builder for {@link AvSettings}. + * + * @param context the context of the caller. + * @param mainType the filter main type. + * @param isAudio {@code true} if it's audio settings; {@code false} if it's video settings. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder( + @NonNull Context context, @FilterType int mainType, boolean isAudio) { + TunerUtils.checkTunerPermission(context); + return new Builder(mainType, isAudio); + } + + /** + * Builder for {@link AvSettings}. + */ + public static class Builder extends Settings.Builder<Builder> { + private final boolean mIsAudio; + private boolean mIsPassthrough; + + private Builder(int mainType, boolean isAudio) { + super(mainType); + mIsAudio = isAudio; + } + + /** + * Sets whether it's passthrough. + */ + @NonNull + public Builder setPassthrough(boolean isPassthrough) { + mIsPassthrough = isPassthrough; + return this; + } + + /** + * Builds a {@link AvSettings} object. + */ + @NonNull + public AvSettings build() { + return new AvSettings(mMainType, mIsAudio, mIsPassthrough); + } + + @Override + Builder self() { + return this; + } } } diff --git a/media/java/android/media/tv/tuner/filter/DownloadSettings.java b/media/java/android/media/tv/tuner/filter/DownloadSettings.java index 0742b1166ede..e3e1df064238 100644 --- a/media/java/android/media/tv/tuner/filter/DownloadSettings.java +++ b/media/java/android/media/tv/tuner/filter/DownloadSettings.java @@ -16,17 +16,75 @@ package android.media.tv.tuner.filter; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; import android.media.tv.tuner.TunerConstants; import android.media.tv.tuner.TunerUtils; +import android.media.tv.tuner.filter.FilterConfiguration.FilterType; /** * Filter Settings for a Download. * @hide */ public class DownloadSettings extends Settings { - private int mDownloadId; + private final int mDownloadId; - public DownloadSettings(int mainType) { + private DownloadSettings(int mainType, int downloadId) { super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_DOWNLOAD)); + mDownloadId = downloadId; + } + + /** + * Gets download ID. + */ + public int getDownloadId() { + return mDownloadId; + } + + /** + * Creates a builder for {@link DownloadSettings}. + * + * @param context the context of the caller. + * @param mainType the filter main type. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder(@NonNull Context context, @FilterType int mainType) { + TunerUtils.checkTunerPermission(context); + return new Builder(mainType); + } + + /** + * Builder for {@link DownloadSettings}. + */ + public static class Builder extends Settings.Builder<Builder> { + private int mDownloadId; + + private Builder(int mainType) { + super(mainType); + } + + /** + * Sets download ID. + */ + @NonNull + public Builder setDownloadId(int downloadId) { + mDownloadId = downloadId; + return this; + } + + /** + * Builds a {@link DownloadSettings} object. + */ + @NonNull + public DownloadSettings build() { + return new DownloadSettings(mMainType, mDownloadId); + } + + @Override + Builder self() { + return this; + } } } diff --git a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java index 6496627cd1d4..68c722f244d4 100644 --- a/media/java/android/media/tv/tuner/filter/FilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/FilterConfiguration.java @@ -33,7 +33,8 @@ import java.lang.annotation.RetentionPolicy; public abstract class FilterConfiguration { /** @hide */ - @IntDef({FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP}) + @IntDef(prefix = "FILTER_TYPE_", value = + {FILTER_TYPE_TS, FILTER_TYPE_MMTP, FILTER_TYPE_IP, FILTER_TYPE_TLV, FILTER_TYPE_ALP}) @Retention(RetentionPolicy.SOURCE) public @interface FilterType {} @@ -58,6 +59,30 @@ public abstract class FilterConfiguration { */ public static final int FILTER_TYPE_ALP = Constants.DemuxFilterMainType.ALP; + + /** @hide */ + @IntDef(prefix = "PACKET_TYPE_", value = + {PACKET_TYPE_IPV4, PACKET_TYPE_COMPRESSED, PACKET_TYPE_SIGNALING}) + @Retention(RetentionPolicy.SOURCE) + public @interface PacketType {} + + /** + * IP v4 packet type. + * @hide + */ + public static final int PACKET_TYPE_IPV4 = 0; + /** + * Compressed packet type. + * @hide + */ + public static final int PACKET_TYPE_COMPRESSED = 2; + /** + * Signaling packet type. + * @hide + */ + public static final int PACKET_TYPE_SIGNALING = 4; + + @Nullable /* package */ final Settings mSettings; @@ -77,4 +102,27 @@ public abstract class FilterConfiguration { public Settings getSettings() { return mSettings; } + + /** + * Builder for {@link FilterConfiguration}. + * + * @param <T> The subclass to be built. + * @hide + */ + public abstract static class Builder<T extends Builder<T>> { + /* package */ Settings mSettings; + + /* package */ Builder() { + } + + /** + * Sets filter settings. + */ + @Nullable + public T setFrequency(Settings settings) { + mSettings = settings; + return self(); + } + /* package */ abstract T self(); + } } diff --git a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java index c89636887628..98edf1035df3 100644 --- a/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/IpFilterConfiguration.java @@ -16,23 +16,152 @@ package android.media.tv.tuner.filter; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.annotation.Size; +import android.content.Context; +import android.media.tv.tuner.TunerUtils; + /** * Filter configuration for a IP filter. * @hide */ public class IpFilterConfiguration extends FilterConfiguration { - private byte[] mSrcIpAddress; - private byte[] mDstIpAddress; - private int mSrcPort; - private int mDstPort; - private boolean mPassthrough; + private final byte[] mSrcIpAddress; + private final byte[] mDstIpAddress; + private final int mSrcPort; + private final int mDstPort; + private final boolean mPassthrough; - public IpFilterConfiguration(Settings settings) { + public IpFilterConfiguration(Settings settings, byte[] srcAddr, byte[] dstAddr, int srcPort, + int dstPort, boolean passthrough) { super(settings); + mSrcIpAddress = srcAddr; + mDstIpAddress = dstAddr; + mSrcPort = srcPort; + mDstPort = dstPort; + mPassthrough = passthrough; } @Override public int getType() { return FilterConfiguration.FILTER_TYPE_IP; } + + /** + * Gets source IP address. + */ + @Size(min = 4, max = 16) + public byte[] getSrcIpAddress() { + return mSrcIpAddress; + } + /** + * Gets destination IP address. + */ + @Size(min = 4, max = 16) + public byte[] getDstIpAddress() { + return mDstIpAddress; + } + /** + * Gets source port. + */ + public int getSrcPort() { + return mSrcPort; + } + /** + * Gets destination port. + */ + public int getDstPort() { + return mDstPort; + } + /** + * Checks whether the filter is passthrough. + * + * @return {@code true} if the data from IP subtype go to next filter directly; + * {@code false} otherwise. + */ + public boolean isPassthrough() { + return mPassthrough; + } + + /** + * Creates a builder for {@link IpFilterConfiguration}. + * + * @param context the context of the caller. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder(@NonNull Context context) { + TunerUtils.checkTunerPermission(context); + return new Builder(); + } + + /** + * Builder for {@link IpFilterConfiguration}. + */ + public static class Builder extends FilterConfiguration.Builder<Builder> { + private byte[] mSrcIpAddress; + private byte[] mDstIpAddress; + private int mSrcPort; + private int mDstPort; + private boolean mPassthrough; + + private Builder() { + } + + /** + * Sets source IP address. + */ + @NonNull + public Builder setSrcIpAddress(byte[] srcIpAddress) { + mSrcIpAddress = srcIpAddress; + return this; + } + /** + * Sets destination IP address. + */ + @NonNull + public Builder setDstIpAddress(byte[] dstIpAddress) { + mDstIpAddress = dstIpAddress; + return this; + } + /** + * Sets source port. + */ + @NonNull + public Builder setSrcPort(int srcPort) { + mSrcPort = srcPort; + return this; + } + /** + * Sets destination port. + */ + @NonNull + public Builder setDstPort(int dstPort) { + mDstPort = dstPort; + return this; + } + /** + * Sets passthrough. + */ + @NonNull + public Builder setPassthrough(boolean passthrough) { + mPassthrough = passthrough; + return this; + } + + /** + * Builds a {@link IpFilterConfiguration} object. + */ + @NonNull + public IpFilterConfiguration build() { + return new IpFilterConfiguration( + mSettings, mSrcIpAddress, mDstIpAddress, mSrcPort, mDstPort, mPassthrough); + } + + @Override + Builder self() { + return this; + } + } } diff --git a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java index 9045ce67a61f..83246e51c8b6 100644 --- a/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/MmtpFilterConfiguration.java @@ -16,19 +16,78 @@ package android.media.tv.tuner.filter; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.media.tv.tuner.TunerUtils; + /** * Filter configuration for a MMTP filter. * @hide */ public class MmtpFilterConfiguration extends FilterConfiguration { - private int mMmtpPid; + private final int mMmtpPid; - public MmtpFilterConfiguration(Settings settings) { + public MmtpFilterConfiguration(Settings settings, int mmtpPid) { super(settings); + mMmtpPid = mmtpPid; } @Override public int getType() { return FilterConfiguration.FILTER_TYPE_MMTP; } + + /** + * Gets MMPT PID. + * + * <p>Packet ID is used to specify packets in MMTP. + */ + public int getMmtpPid() { + return mMmtpPid; + } + + /** + * Creates a builder for {@link IpFilterConfiguration}. + * + * @param context the context of the caller. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder(@NonNull Context context) { + TunerUtils.checkTunerPermission(context); + return new Builder(); + } + + /** + * Builder for {@link IpFilterConfiguration}. + */ + public static class Builder extends FilterConfiguration.Builder<Builder> { + private int mMmtpPid; + + private Builder() { + } + + /** + * Sets MMPT PID. + */ + @NonNull + public Builder setMmtpPid(int mmtpPid) { + mMmtpPid = mmtpPid; + return this; + } + + /** + * Builds a {@link IpFilterConfiguration} object. + */ + @NonNull + public MmtpFilterConfiguration build() { + return new MmtpFilterConfiguration(mSettings, mMmtpPid); + } + + @Override + Builder self() { + return this; + } + } } diff --git a/media/java/android/media/tv/tuner/filter/RecordSettings.java b/media/java/android/media/tv/tuner/filter/RecordSettings.java index 701868afc789..483370935352 100644 --- a/media/java/android/media/tv/tuner/filter/RecordSettings.java +++ b/media/java/android/media/tv/tuner/filter/RecordSettings.java @@ -16,18 +16,231 @@ package android.media.tv.tuner.filter; +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.hardware.tv.tuner.V1_0.Constants; import android.media.tv.tuner.TunerConstants; +import android.media.tv.tuner.TunerConstants.ScIndexType; import android.media.tv.tuner.TunerUtils; +import android.media.tv.tuner.filter.FilterConfiguration.FilterType; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; /** * The Settings for the record in DVR. * @hide */ public class RecordSettings extends Settings { - private int mIndexType; - private int mIndexMask; + /** + * Indexes can be tagged through TS (Transport Stream) header. + * + * @hide + */ + @IntDef(flag = true, + prefix = "TS_INDEX_", + value = {TS_INDEX_FIRST_PACKET, TS_INDEX_PAYLOAD_UNIT_START_INDICATOR, + TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED, + TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, TS_INDEX_DISCONTINUITY_INDICATOR, + TS_INDEX_RANDOM_ACCESS_INDICATOR, TS_INDEX_PRIORITY_INDICATOR, + TS_INDEX_PCR_FLAG, TS_INDEX_OPCR_FLAG, TS_INDEX_SPLICING_POINT_FLAG, + TS_INDEX_PRIVATE_DATA, TS_INDEX_ADAPTATION_EXTENSION_FLAG}) + @Retention(RetentionPolicy.SOURCE) + public @interface TsIndexMask {} + + /** + * TS index FIRST_PACKET. + * @hide + */ + public static final int TS_INDEX_FIRST_PACKET = Constants.DemuxTsIndex.FIRST_PACKET; + /** + * TS index PAYLOAD_UNIT_START_INDICATOR. + * @hide + */ + public static final int TS_INDEX_PAYLOAD_UNIT_START_INDICATOR = + Constants.DemuxTsIndex.PAYLOAD_UNIT_START_INDICATOR; + /** + * TS index CHANGE_TO_NOT_SCRAMBLED. + * @hide + */ + public static final int TS_INDEX_CHANGE_TO_NOT_SCRAMBLED = + Constants.DemuxTsIndex.CHANGE_TO_NOT_SCRAMBLED; + /** + * TS index CHANGE_TO_EVEN_SCRAMBLED. + * @hide + */ + public static final int TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED = + Constants.DemuxTsIndex.CHANGE_TO_EVEN_SCRAMBLED; + /** + * TS index CHANGE_TO_ODD_SCRAMBLED. + * @hide + */ + public static final int TS_INDEX_CHANGE_TO_ODD_SCRAMBLED = + Constants.DemuxTsIndex.CHANGE_TO_ODD_SCRAMBLED; + /** + * TS index DISCONTINUITY_INDICATOR. + * @hide + */ + public static final int TS_INDEX_DISCONTINUITY_INDICATOR = + Constants.DemuxTsIndex.DISCONTINUITY_INDICATOR; + /** + * TS index RANDOM_ACCESS_INDICATOR. + * @hide + */ + public static final int TS_INDEX_RANDOM_ACCESS_INDICATOR = + Constants.DemuxTsIndex.RANDOM_ACCESS_INDICATOR; + /** + * TS index PRIORITY_INDICATOR. + * @hide + */ + public static final int TS_INDEX_PRIORITY_INDICATOR = Constants.DemuxTsIndex.PRIORITY_INDICATOR; + /** + * TS index PCR_FLAG. + * @hide + */ + public static final int TS_INDEX_PCR_FLAG = Constants.DemuxTsIndex.PCR_FLAG; + /** + * TS index OPCR_FLAG. + * @hide + */ + public static final int TS_INDEX_OPCR_FLAG = Constants.DemuxTsIndex.OPCR_FLAG; + /** + * TS index SPLICING_POINT_FLAG. + * @hide + */ + public static final int TS_INDEX_SPLICING_POINT_FLAG = + Constants.DemuxTsIndex.SPLICING_POINT_FLAG; + /** + * TS index PRIVATE_DATA. + * @hide + */ + public static final int TS_INDEX_PRIVATE_DATA = Constants.DemuxTsIndex.PRIVATE_DATA; + /** + * TS index ADAPTATION_EXTENSION_FLAG. + * @hide + */ + public static final int TS_INDEX_ADAPTATION_EXTENSION_FLAG = + Constants.DemuxTsIndex.ADAPTATION_EXTENSION_FLAG; + /** + * @hide + */ + @IntDef(flag = true, + prefix = "SC_", + value = { + TunerConstants.SC_INDEX_I_FRAME, + TunerConstants.SC_INDEX_P_FRAME, + TunerConstants.SC_INDEX_B_FRAME, + TunerConstants.SC_INDEX_SEQUENCE, + TunerConstants.SC_HEVC_INDEX_SPS, + TunerConstants.SC_HEVC_INDEX_AUD, + TunerConstants.SC_HEVC_INDEX_SLICE_CE_BLA_W_LP, + TunerConstants.SC_HEVC_INDEX_SLICE_BLA_W_RADL, + TunerConstants.SC_HEVC_INDEX_SLICE_BLA_N_LP, + TunerConstants.SC_HEVC_INDEX_SLICE_IDR_W_RADL, + TunerConstants.SC_HEVC_INDEX_SLICE_IDR_N_LP, + TunerConstants.SC_HEVC_INDEX_SLICE_TRAIL_CRA, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ScIndexMask {} + - public RecordSettings(int mainType) { + private final int mTsIndexMask; + private final int mScIndexType; + private final int mScIndexMask; + + private RecordSettings(int mainType, int tsIndexType, int scIndexType, int scIndexMask) { super(TunerUtils.getFilterSubtype(mainType, TunerConstants.FILTER_SUBTYPE_RECORD)); + mTsIndexMask = tsIndexType; + mScIndexType = scIndexType; + mScIndexMask = scIndexMask; } + + /** + * Gets TS index mask. + */ + @TsIndexMask + public int getTsIndexMask() { + return mTsIndexMask; + } + /** + * Gets Start Code index type. + */ + @ScIndexType + public int getScIndexType() { + return mScIndexType; + } + /** + * Gets Start Code index mask. + */ + @ScIndexMask + public int getScIndexMask() { + return mScIndexMask; + } + + /** + * Creates a builder for {@link RecordSettings}. + * + * @param context the context of the caller. + * @param mainType the filter main type. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder(@NonNull Context context, @FilterType int mainType) { + TunerUtils.checkTunerPermission(context); + return new Builder(mainType); + } + + /** + * Builder for {@link RecordSettings}. + */ + public static class Builder extends Settings.Builder<Builder> { + private int mTsIndexMask; + private int mScIndexType; + private int mScIndexMask; + + private Builder(int mainType) { + super(mainType); + } + + /** + * Sets TS index mask. + */ + @NonNull + public Builder setTsIndexMask(@TsIndexMask int indexMask) { + mTsIndexMask = indexMask; + return this; + } + /** + * Sets index type. + */ + @NonNull + public Builder setScIndexType(@ScIndexType int indexType) { + mScIndexType = indexType; + return this; + } + /** + * Sets Start Code index mask. + */ + @NonNull + public Builder setScIndexMask(@ScIndexMask int indexMask) { + mScIndexMask = indexMask; + return this; + } + + /** + * Builds a {@link RecordSettings} object. + */ + @NonNull + public RecordSettings build() { + return new RecordSettings(mMainType, mTsIndexMask, mScIndexType, mScIndexMask); + } + + @Override + Builder self() { + return this; + } + } + } diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java index 414ea6790bf5..0fa982e3dd01 100644 --- a/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java +++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithSectionBits.java @@ -16,18 +16,116 @@ package android.media.tv.tuner.filter; -import java.util.List; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.media.tv.tuner.TunerUtils; +import android.media.tv.tuner.filter.FilterConfiguration.FilterType; /** - * Bits Settings for Section Filter. + * Bits Settings for Section Filters. * @hide */ public class SectionSettingsWithSectionBits extends SectionSettings { - private List<Byte> mFilter; - private List<Byte> mMask; - private List<Byte> mMode; + private final byte[] mFilter; + private final byte[] mMask; + private final byte[] mMode; - private SectionSettingsWithSectionBits(int mainType) { + + private SectionSettingsWithSectionBits(int mainType, byte[] filter, byte[] mask, byte[] mode) { super(mainType); + mFilter = filter; + mMask = mask; + mMode = mode; + } + + /** + * Gets the bytes configured for Section Filter + */ + public byte[] getFilterBytes() { + return mFilter; + } + /** + * Gets bit mask. + * + * <p>The bits in the bytes are used for filtering. + */ + public byte[] getMask() { + return mMask; + } + /** + * Gets mode. + * + * <p>Do positive match at the bit position of the configured bytes when the bit at same + * position of the mode is 0. + * <p>Do negative match at the bit position of the configured bytes when the bit at same + * position of the mode is 1. + */ + public byte[] getMode() { + return mMode; + } + + /** + * Creates a builder for {@link SectionSettingsWithSectionBits}. + * + * @param context the context of the caller. + * @param mainType the filter main type. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder(@NonNull Context context, @FilterType int mainType) { + TunerUtils.checkTunerPermission(context); + return new Builder(mainType); + } + + /** + * Builder for {@link SectionSettingsWithSectionBits}. + */ + public static class Builder extends Settings.Builder<Builder> { + private byte[] mFilter; + private byte[] mMask; + private byte[] mMode; + + private Builder(int mainType) { + super(mainType); + } + + /** + * Sets filter bytes. + */ + @NonNull + public Builder setFilter(byte[] filter) { + mFilter = filter; + return this; + } + /** + * Sets bit mask. + */ + @NonNull + public Builder setMask(byte[] mask) { + mMask = mask; + return this; + } + /** + * Sets mode. + */ + @NonNull + public Builder setMode(byte[] mode) { + mMode = mode; + return this; + } + + /** + * Builds a {@link SectionSettingsWithSectionBits} object. + */ + @NonNull + public SectionSettingsWithSectionBits build() { + return new SectionSettingsWithSectionBits(mMainType, mFilter, mMask, mMode); + } + + @Override + Builder self() { + return this; + } } } diff --git a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java index 0df1d7308e60..6542b89478b2 100644 --- a/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java +++ b/media/java/android/media/tv/tuner/filter/SectionSettingsWithTableInfo.java @@ -16,15 +16,92 @@ package android.media.tv.tuner.filter; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.media.tv.tuner.TunerUtils; +import android.media.tv.tuner.filter.FilterConfiguration.FilterType; + /** * Table information for Section Filter. * @hide */ public class SectionSettingsWithTableInfo extends SectionSettings { - private int mTableId; - private int mVersion; + private final int mTableId; + private final int mVersion; - private SectionSettingsWithTableInfo(int mainType) { + private SectionSettingsWithTableInfo(int mainType, int tableId, int version) { super(mainType); + mTableId = tableId; + mVersion = version; + } + + /** + * Gets table ID. + */ + public int getTableId() { + return mTableId; + } + /** + * Gets version. + */ + public int getVersion() { + return mVersion; } + + /** + * Creates a builder for {@link SectionSettingsWithTableInfo}. + * + * @param context the context of the caller. + * @param mainType the filter main type. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder(@NonNull Context context, @FilterType int mainType) { + TunerUtils.checkTunerPermission(context); + return new Builder(mainType); + } + + /** + * Builder for {@link SectionSettingsWithTableInfo}. + */ + public static class Builder extends Settings.Builder<Builder> { + private int mTableId; + private int mVersion; + + private Builder(int mainType) { + super(mainType); + } + + /** + * Sets table ID. + */ + @NonNull + public Builder setTableId(int tableId) { + mTableId = tableId; + return this; + } + /** + * Sets version. + */ + @NonNull + public Builder setVersion(int version) { + mVersion = version; + return this; + } + + /** + * Builds a {@link SectionSettingsWithTableInfo} object. + */ + @NonNull + public SectionSettingsWithTableInfo build() { + return new SectionSettingsWithTableInfo(mMainType, mTableId, mVersion); + } + + @Override + Builder self() { + return this; + } + } + } diff --git a/media/java/android/media/tv/tuner/filter/Settings.java b/media/java/android/media/tv/tuner/filter/Settings.java index 91559260031c..d697280a4106 100644 --- a/media/java/android/media/tv/tuner/filter/Settings.java +++ b/media/java/android/media/tv/tuner/filter/Settings.java @@ -39,4 +39,20 @@ public abstract class Settings { public int getType() { return mType; } + + + /** + * Builder for {@link Settings}. + * + * @param <T> The subclass to be built. + * @hide + */ + public abstract static class Builder<T extends Builder<T>> { + /* package */ final int mMainType; + + /* package */ Builder(int mainType) { + mMainType = mainType; + } + /* package */ abstract T self(); + } } diff --git a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java index de8ee754a28c..eb97fc04362c 100644 --- a/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java +++ b/media/java/android/media/tv/tuner/filter/TlvFilterConfiguration.java @@ -16,21 +16,118 @@ package android.media.tv.tuner.filter; +import android.annotation.NonNull; +import android.annotation.RequiresPermission; +import android.content.Context; +import android.media.tv.tuner.TunerUtils; + /** * Filter configuration for a TLV filter. * @hide */ public class TlvFilterConfiguration extends FilterConfiguration { - private int mPacketType; - private boolean mIsCompressedIpPacket; - private boolean mPassthrough; + private final int mPacketType; + private final boolean mIsCompressedIpPacket; + private final boolean mPassthrough; - public TlvFilterConfiguration(Settings settings) { + public TlvFilterConfiguration(Settings settings, int packetType, boolean isCompressed, + boolean passthrough) { super(settings); + mPacketType = packetType; + mIsCompressedIpPacket = isCompressed; + mPassthrough = passthrough; } @Override public int getType() { return FilterConfiguration.FILTER_TYPE_TLV; } + + /** + * Gets packet type. + */ + @FilterConfiguration.PacketType + public int getPacketType() { + return mPacketType; + } + /** + * Checks whether the data is compressed IP packet. + * + * @return {@code true} if the filtered data is compressed IP packet; {@code false} otherwise. + */ + public boolean isCompressedIpPacket() { + return mIsCompressedIpPacket; + } + /** + * Checks whether it's passthrough. + * + * @return {@code true} if the data from TLV subtype go to next filter directly; + * {@code false} otherwise. + */ + public boolean isPassthrough() { + return mPassthrough; + } + + /** + * Creates a builder for {@link TlvFilterConfiguration}. + * + * @param context the context of the caller. + */ + @RequiresPermission(android.Manifest.permission.ACCESS_TV_TUNER) + @NonNull + public static Builder builder(@NonNull Context context) { + TunerUtils.checkTunerPermission(context); + return new Builder(); + } + + /** + * Builder for {@link TlvFilterConfiguration}. + */ + public static class Builder extends FilterConfiguration.Builder<Builder> { + private int mPacketType; + private boolean mIsCompressedIpPacket; + private boolean mPassthrough; + + private Builder() { + } + + /** + * Sets packet type. + */ + @NonNull + public Builder setPacketType(@FilterConfiguration.PacketType int packetType) { + mPacketType = packetType; + return this; + } + /** + * Sets whether the data is compressed IP packet. + */ + @NonNull + public Builder setIsCompressedIpPacket(boolean isCompressedIpPacket) { + mIsCompressedIpPacket = isCompressedIpPacket; + return this; + } + /** + * Sets whether it's passthrough. + */ + @NonNull + public Builder setPassthrough(boolean passthrough) { + mPassthrough = passthrough; + return this; + } + + /** + * Builds a {@link TlvFilterConfiguration} object. + */ + @NonNull + public TlvFilterConfiguration build() { + return new TlvFilterConfiguration( + mSettings, mPacketType, mIsCompressedIpPacket, mPassthrough); + } + + @Override + Builder self() { + return this; + } + } } diff --git a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java index fa4dd72e3eda..1b8485e22dcf 100644 --- a/media/java/android/media/tv/tuner/filter/TsRecordEvent.java +++ b/media/java/android/media/tv/tuner/filter/TsRecordEvent.java @@ -16,12 +16,8 @@ package android.media.tv.tuner.filter; -import android.annotation.IntDef; import android.media.tv.tuner.Tuner.Filter; -import android.media.tv.tuner.TunerConstants; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; /** * Filter event sent from {@link Filter} objects for TS record data. @@ -29,47 +25,17 @@ import java.lang.annotation.RetentionPolicy; * @hide */ public class TsRecordEvent extends FilterEvent { - /** - * @hide - */ - @IntDef(flag = true, value = { - TunerConstants.TS_INDEX_FIRST_PACKET, - TunerConstants.TS_INDEX_PAYLOAD_UNIT_START_INDICATOR, - TunerConstants.TS_INDEX_CHANGE_TO_NOT_SCRAMBLED, - TunerConstants.TS_INDEX_CHANGE_TO_EVEN_SCRAMBLED, - TunerConstants.TS_INDEX_CHANGE_TO_ODD_SCRAMBLED, - TunerConstants.TS_INDEX_DISCONTINUITY_INDICATOR, - TunerConstants.TS_INDEX_RANDOM_ACCESS_INDICATOR, - TunerConstants.TS_INDEX_PRIORITY_INDICATOR, - TunerConstants.TS_INDEX_PCR_FLAG, - TunerConstants.TS_INDEX_OPCR_FLAG, - TunerConstants.TS_INDEX_SPLICING_POINT_FLAG, - TunerConstants.TS_INDEX_PRIVATE_DATA, - TunerConstants.TS_INDEX_ADAPTATION_EXTENSION_FLAG, - TunerConstants.SC_INDEX_I_FRAME, - TunerConstants.SC_INDEX_P_FRAME, - TunerConstants.SC_INDEX_B_FRAME, - TunerConstants.SC_INDEX_SEQUENCE, - TunerConstants.SC_HEVC_INDEX_SPS, - TunerConstants.SC_HEVC_INDEX_AUD, - TunerConstants.SC_HEVC_INDEX_SLICE_CE_BLA_W_LP, - TunerConstants.SC_HEVC_INDEX_SLICE_BLA_W_RADL, - TunerConstants.SC_HEVC_INDEX_SLICE_BLA_N_LP, - TunerConstants.SC_HEVC_INDEX_SLICE_IDR_W_RADL, - TunerConstants.SC_HEVC_INDEX_SLICE_IDR_N_LP, - TunerConstants.SC_HEVC_INDEX_SLICE_TRAIL_CRA, - }) - @Retention(RetentionPolicy.SOURCE) - public @interface IndexMask {} private final int mPid; - private final int mIndexMask; + private final int mTsIndexMask; + private final int mScIndexMask; private final long mByteNumber; // This constructor is used by JNI code only - private TsRecordEvent(int pid, int indexMask, long byteNumber) { + private TsRecordEvent(int pid, int tsIndexMask, int scIndexMask, long byteNumber) { mPid = pid; - mIndexMask = indexMask; + mTsIndexMask = tsIndexMask; + mScIndexMask = scIndexMask; mByteNumber = byteNumber; } @@ -81,13 +47,20 @@ public class TsRecordEvent extends FilterEvent { } /** - * Gets index mask. + * Gets TS index mask. + */ + @RecordSettings.TsIndexMask + public int getTsIndexMask() { + return mTsIndexMask; + } + /** + * Gets SC index mask. * - * <p>The index type is one of TS, SC, and SC-HEVC, and is set when configuring the filter. + * <p>The index type is SC or SC-HEVC, and is set when configuring the filter. */ - @IndexMask - public int getIndexMask() { - return mIndexMask; + @RecordSettings.ScIndexMask + public int getScIndexMask() { + return mScIndexMask; } /** diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java index 41a9b24afa03..50542818e0d7 100644 --- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java +++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java @@ -49,7 +49,6 @@ import android.webkit.WebViewClient; import android.widget.ProgressBar; import android.widget.TextView; -import com.android.internal.telephony.PhoneConstants; import com.android.internal.util.ArrayUtils; import com.android.internal.util.TrafficStatsConstants; @@ -207,7 +206,7 @@ public class CaptivePortalLoginActivity extends Activity { if (TextUtils.isEmpty(url)) url = mCm.getCaptivePortalServerUrl(); final CarrierConfigManager configManager = getApplicationContext() .getSystemService(CarrierConfigManager.class); - final int subId = getIntent().getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + final int subId = getIntent().getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.getDefaultVoiceSubscriptionId()); final String[] portalURLs = configManager.getConfigForSubId(subId).getStringArray( CarrierConfigManager.KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java index a58e3d78bb08..65fc215f7505 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java @@ -31,8 +31,8 @@ import static android.os.BatteryManager.EXTRA_MAX_CHARGING_VOLTAGE; import static android.os.BatteryManager.EXTRA_PLUGGED; import static android.os.BatteryManager.EXTRA_STATUS; import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; +import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM; -import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_BOOT; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW; import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT; @@ -92,7 +92,6 @@ import android.util.Log; import android.util.SparseBooleanArray; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.internal.widget.LockPatternUtils; import com.android.settingslib.WirelessUtils; @@ -446,7 +445,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab */ public List<SubscriptionInfo> getFilteredSubscriptionInfo(boolean forceReload) { List<SubscriptionInfo> subscriptions = getSubscriptionInfo(false); - if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) { + if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) { SubscriptionInfo info1 = subscriptions.get(0); SubscriptionInfo info2 = subscriptions.get(1); if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { @@ -1074,7 +1073,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab mHandler.sendEmptyMessage(MSG_AIRPLANE_MODE_CHANGED); } else if (Intent.ACTION_SERVICE_STATE.equals(action)) { ServiceState serviceState = ServiceState.newFromBundle(intent.getExtras()); - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); if (DEBUG) { Log.v(TAG, "action " + action + " serviceState=" + serviceState + " subId=" @@ -1236,8 +1235,8 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener, Dumpab throw new IllegalArgumentException("only handles intent ACTION_SIM_STATE_CHANGED"); } String stateExtra = intent.getStringExtra(Intent.EXTRA_SIM_STATE); - int slotId = intent.getIntExtra(PhoneConstants.PHONE_KEY, 0); - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int slotId = intent.getIntExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0); + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); if (Intent.SIM_STATE_ABSENT.equals(stateExtra)) { final String absentReason = intent diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java index 2c6a165cc550..2eec68b26347 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/EventBatch.java @@ -16,6 +16,8 @@ package com.android.systemui.statusbar.notification.collection.coalescer; +import androidx.annotation.Nullable; + import java.util.ArrayList; import java.util.List; @@ -35,6 +37,8 @@ public class EventBatch { */ final List<CoalescedEvent> mMembers = new ArrayList<>(); + @Nullable Runnable mCancelShortTimeout; + EventBatch(long createdTimestamp, String groupKey) { mCreatedTimestamp = createdTimestamp; this.mGroupKey = groupKey; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java index 8076616de05e..f5890386a14f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescer.java @@ -16,6 +16,7 @@ package com.android.systemui.statusbar.notification.collection.coalescer; +import static com.android.systemui.statusbar.notification.logging.NotifEvent.BATCH_MAX_TIMEOUT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.COALESCED_EVENT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.EARLY_BATCH_EMIT; import static com.android.systemui.statusbar.notification.logging.NotifEvent.EMIT_EVENT_BATCH; @@ -71,7 +72,8 @@ public class GroupCoalescer implements Dumpable { private final DelayableExecutor mMainExecutor; private final SystemClock mClock; private final NotifLog mLog; - private final long mGroupLingerDuration; + private final long mMinGroupLingerDuration; + private final long mMaxGroupLingerDuration; private BatchableNotificationHandler mHandler; @@ -82,22 +84,28 @@ public class GroupCoalescer implements Dumpable { public GroupCoalescer( @Main DelayableExecutor mainExecutor, SystemClock clock, NotifLog log) { - this(mainExecutor, clock, log, GROUP_LINGER_DURATION); + this(mainExecutor, clock, log, MIN_GROUP_LINGER_DURATION, MAX_GROUP_LINGER_DURATION); } /** - * @param groupLingerDuration How long, in ms, that notifications that are members of a group - * are delayed within the GroupCoalescer before being posted + * @param minGroupLingerDuration How long, in ms, to wait for another notification from the same + * group to arrive before emitting all pending events for that + * group. Each subsequent arrival of a group member resets the + * timer for that group. + * @param maxGroupLingerDuration The maximum time, in ms, that a group can linger in the + * coalescer before it's force-emitted. */ GroupCoalescer( @Main DelayableExecutor mainExecutor, SystemClock clock, NotifLog log, - long groupLingerDuration) { + long minGroupLingerDuration, + long maxGroupLingerDuration) { mMainExecutor = mainExecutor; mClock = clock; mLog = log; - mGroupLingerDuration = groupLingerDuration; + mMinGroupLingerDuration = minGroupLingerDuration; + mMaxGroupLingerDuration = maxGroupLingerDuration; } /** @@ -115,7 +123,7 @@ public class GroupCoalescer implements Dumpable { private final NotificationHandler mListener = new NotificationHandler() { @Override public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) { - maybeEmitBatch(sbn.getKey()); + maybeEmitBatch(sbn); applyRanking(rankingMap); final boolean shouldCoalesce = handleNotificationPosted(sbn, rankingMap); @@ -130,7 +138,7 @@ public class GroupCoalescer implements Dumpable { @Override public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) { - maybeEmitBatch(sbn.getKey()); + maybeEmitBatch(sbn); applyRanking(rankingMap); mHandler.onNotificationRemoved(sbn, rankingMap); } @@ -140,7 +148,7 @@ public class GroupCoalescer implements Dumpable { StatusBarNotification sbn, RankingMap rankingMap, int reason) { - maybeEmitBatch(sbn.getKey()); + maybeEmitBatch(sbn); applyRanking(rankingMap); mHandler.onNotificationRemoved(sbn, rankingMap, reason); } @@ -152,13 +160,20 @@ public class GroupCoalescer implements Dumpable { } }; - private void maybeEmitBatch(String memberKey) { - CoalescedEvent event = mCoalescedEvents.get(memberKey); + private void maybeEmitBatch(StatusBarNotification sbn) { + final CoalescedEvent event = mCoalescedEvents.get(sbn.getKey()); + final EventBatch batch = mBatches.get(sbn.getGroupKey()); if (event != null) { mLog.log(EARLY_BATCH_EMIT, String.format("Modification of %s triggered early emit of batched group %s", - memberKey, requireNonNull(event.getBatch()).mGroupKey)); + sbn.getKey(), requireNonNull(event.getBatch()).mGroupKey)); emitBatch(requireNonNull(event.getBatch())); + } else if (batch != null + && mClock.uptimeMillis() - batch.mCreatedTimestamp >= mMaxGroupLingerDuration) { + mLog.log(BATCH_MAX_TIMEOUT, + String.format("Modification of %s triggered timeout emit of batched group %s", + sbn.getKey(), batch.mGroupKey)); + emitBatch(batch); } } @@ -175,7 +190,8 @@ public class GroupCoalescer implements Dumpable { } if (sbn.isGroup()) { - EventBatch batch = startBatchingGroup(sbn.getGroupKey()); + final EventBatch batch = getOrBuildBatch(sbn.getGroupKey()); + CoalescedEvent event = new CoalescedEvent( sbn.getKey(), @@ -183,10 +199,10 @@ public class GroupCoalescer implements Dumpable { sbn, requireRanking(rankingMap, sbn.getKey()), batch); + mCoalescedEvents.put(event.getKey(), event); batch.mMembers.add(event); - - mCoalescedEvents.put(event.getKey(), event); + resetShortTimeout(batch); return true; } else { @@ -194,27 +210,39 @@ public class GroupCoalescer implements Dumpable { } } - private EventBatch startBatchingGroup(final String groupKey) { + private EventBatch getOrBuildBatch(final String groupKey) { EventBatch batch = mBatches.get(groupKey); if (batch == null) { - final EventBatch newBatch = new EventBatch(mClock.uptimeMillis(), groupKey); - mBatches.put(groupKey, newBatch); - mMainExecutor.executeDelayed(() -> emitBatch(newBatch), mGroupLingerDuration); - - batch = newBatch; + batch = new EventBatch(mClock.uptimeMillis(), groupKey); + mBatches.put(groupKey, batch); } return batch; } + private void resetShortTimeout(EventBatch batch) { + if (batch.mCancelShortTimeout != null) { + batch.mCancelShortTimeout.run(); + } + batch.mCancelShortTimeout = + mMainExecutor.executeDelayed( + () -> { + batch.mCancelShortTimeout = null; + emitBatch(batch); + }, + mMinGroupLingerDuration); + } + private void emitBatch(EventBatch batch) { if (batch != mBatches.get(batch.mGroupKey)) { - // If we emit a batch early, we don't want to emit it a second time when its timeout - // expires. - return; + throw new IllegalStateException("Cannot emit out-of-date batch " + batch.mGroupKey); } if (batch.mMembers.isEmpty()) { throw new IllegalStateException("Batch " + batch.mGroupKey + " cannot be empty"); } + if (batch.mCancelShortTimeout != null) { + batch.mCancelShortTimeout.run(); + batch.mCancelShortTimeout = null; + } mBatches.remove(batch.mGroupKey); @@ -299,5 +327,6 @@ public class GroupCoalescer implements Dumpable { void onNotificationBatchPosted(List<CoalescedEvent> events); } - private static final int GROUP_LINGER_DURATION = 500; + private static final int MIN_GROUP_LINGER_DURATION = 50; + private static final int MAX_GROUP_LINGER_DURATION = 500; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java index 2374cde0c16a..9adceb78c249 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotifEvent.java @@ -156,7 +156,8 @@ public class NotifEvent extends RichEvent { // GroupCoalescer labels: "CoalescedEvent", "EarlyBatchEmit", - "EmitEventBatch" + "EmitEventBatch", + "BatchMaxTimeout" }; private static final int TOTAL_EVENT_LABELS = EVENT_LABELS.length; @@ -206,5 +207,6 @@ public class NotifEvent extends RichEvent { public static final int COALESCED_EVENT = COALESCER_EVENT_START_INDEX; public static final int EARLY_BATCH_EMIT = COALESCER_EVENT_START_INDEX + 1; public static final int EMIT_EVENT_BATCH = COALESCER_EVENT_START_INDEX + 2; + public static final int BATCH_MAX_TIMEOUT = COALESCER_EVENT_START_INDEX + 3; private static final int TOTAL_COALESCER_EVENT_TYPES = 3; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java index 679fa7e2b016..6b3c5dc228bc 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java @@ -22,8 +22,7 @@ import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_IN import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_NONE; import static android.net.wifi.WifiManager.TrafficStateCallback.DATA_ACTIVITY_OUT; import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE; - -import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM; +import static android.telephony.TelephonyManager.MODEM_COUNT_DUAL_MODEM; import android.content.BroadcastReceiver; import android.content.Context; @@ -57,7 +56,6 @@ import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; -import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.settingslib.net.DataUsageController; import com.android.systemui.DemoMode; @@ -547,7 +545,7 @@ public class NetworkControllerImpl extends BroadcastReceiver mReceiverHandler.post(this::handleConfigurationChanged); break; default: - int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, + int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, SubscriptionManager.INVALID_SUBSCRIPTION_ID); if (SubscriptionManager.isValidSubscriptionId(subId)) { if (mMobileSignalControllers.indexOfKey(subId) >= 0) { @@ -582,7 +580,7 @@ public class NetworkControllerImpl extends BroadcastReceiver } private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) { - if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) { + if (subscriptions.size() == MODEM_COUNT_DUAL_MODEM) { SubscriptionInfo info1 = subscriptions.get(0); SubscriptionInfo info2 = subscriptions.get(1); if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) { diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java index 2e0fb3bc850d..12da00678ac2 100644 --- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java +++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java @@ -57,7 +57,6 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableContext; import android.testing.TestableLooper; -import com.android.internal.telephony.PhoneConstants; import com.android.internal.telephony.TelephonyIntents; import com.android.systemui.DumpController; import com.android.systemui.SysuiTestCase; @@ -524,9 +523,9 @@ public class KeyguardUpdateMonitorTest extends SysuiTestCase { int subscription = simInited ? 1/* mock subid=1 */ : SubscriptionManager.DUMMY_SUBSCRIPTION_ID_BASE; if (data != null) intent.putExtras(data); - intent.putExtra(PhoneConstants.PHONE_NAME_KEY, "Phone"); - intent.putExtra("subscription", subscription); - intent.putExtra("slot", 0/* SLOT 1 */); + + intent.putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subscription); + intent.putExtra(SubscriptionManager.EXTRA_SLOT_INDEX, 0); return intent; } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java index 5e0baf204ecf..86c1eb97d186 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/coalescer/GroupCoalescerTest.java @@ -80,7 +80,8 @@ public class GroupCoalescerTest extends SysuiTestCase { mExecutor, mClock, mLog, - LINGER_DURATION); + MIN_LINGER_DURATION, + MAX_LINGER_DURATION); mCoalescer.setNotificationHandler(mListener); mCoalescer.attach(mListenerService); @@ -96,7 +97,7 @@ public class GroupCoalescerTest extends SysuiTestCase { new NotificationEntryBuilder() .setId(0) .setPkg(TEST_PACKAGE_A)); - mClock.advanceTime(LINGER_DURATION); + mClock.advanceTime(MIN_LINGER_DURATION); // THEN the event is passed through to the handler verify(mListener).onNotificationPosted(notif1.sbn, notif1.rankingMap); @@ -144,12 +145,16 @@ public class GroupCoalescerTest extends SysuiTestCase { .setId(1) .setGroup(mContext, GROUP_1)); + mClock.advanceTime(2); + NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(2) .setGroup(mContext, GROUP_1) .setGroupSummary(mContext, true)); + mClock.advanceTime(3); + NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(3) @@ -161,7 +166,7 @@ public class GroupCoalescerTest extends SysuiTestCase { verify(mListener, never()).onNotificationBatchPosted(anyList()); // WHEN enough time passes - mClock.advanceTime(LINGER_DURATION); + mClock.advanceTime(MIN_LINGER_DURATION); // THEN the coalesced notifs are applied. The summary is sorted to the front. verify(mListener).onNotificationBatchPosted(Arrays.asList( @@ -212,7 +217,7 @@ public class GroupCoalescerTest extends SysuiTestCase { // WHEN the time runs out on the remainder of the group clearInvocations(mListener); - mClock.advanceTime(LINGER_DURATION); + mClock.advanceTime(MIN_LINGER_DURATION); // THEN no lingering batch is applied verify(mListener, never()).onNotificationBatchPosted(anyList()); @@ -225,11 +230,13 @@ public class GroupCoalescerTest extends SysuiTestCase { .setPkg(TEST_PACKAGE_A) .setId(1) .setGroup(mContext, GROUP_1)); + mClock.advanceTime(2); NotifEvent notif2a = mNoMan.postNotif(new NotificationEntryBuilder() .setPkg(TEST_PACKAGE_A) .setId(2) .setContentTitle(mContext, "Version 1") .setGroup(mContext, GROUP_1)); + mClock.advanceTime(4); // WHEN one of them gets updated NotifEvent notif2b = mNoMan.postNotif(new NotificationEntryBuilder() @@ -248,7 +255,7 @@ public class GroupCoalescerTest extends SysuiTestCase { any(RankingMap.class)); // THEN second, the update is emitted - mClock.advanceTime(LINGER_DURATION); + mClock.advanceTime(MIN_LINGER_DURATION); verify(mListener).onNotificationBatchPosted(Collections.singletonList( new CoalescedEvent(notif2b.key, 0, notif2b.sbn, notif2b.ranking, null) )); @@ -308,14 +315,61 @@ public class GroupCoalescerTest extends SysuiTestCase { .setId(17)); // THEN they have the new rankings when they are eventually emitted - mClock.advanceTime(LINGER_DURATION); + mClock.advanceTime(MIN_LINGER_DURATION); verify(mListener).onNotificationBatchPosted(Arrays.asList( new CoalescedEvent(notif1.key, 0, notif1.sbn, ranking1b, null), new CoalescedEvent(notif2.key, 1, notif2.sbn, ranking2b, null) )); } - private static final long LINGER_DURATION = 4700; + @Test + public void testMaxLingerDuration() { + // GIVEN five coalesced notifications that have collectively taken 20ms to arrive, 2ms + // longer than the max linger duration + NotifEvent notif1 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_A) + .setId(1) + .setGroup(mContext, GROUP_1)); + mClock.advanceTime(4); + NotifEvent notif2 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_A) + .setId(2) + .setGroup(mContext, GROUP_1)); + mClock.advanceTime(4); + NotifEvent notif3 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_A) + .setId(3) + .setGroup(mContext, GROUP_1)); + mClock.advanceTime(4); + NotifEvent notif4 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_A) + .setId(4) + .setGroup(mContext, GROUP_1)); + mClock.advanceTime(4); + NotifEvent notif5 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_A) + .setId(5) + .setGroup(mContext, GROUP_1)); + mClock.advanceTime(4); + + // WHEN a sixth notification arrives + NotifEvent notif6 = mNoMan.postNotif(new NotificationEntryBuilder() + .setPkg(TEST_PACKAGE_A) + .setId(6) + .setGroup(mContext, GROUP_1)); + + // THEN the first five notifications are emitted in a batch + verify(mListener).onNotificationBatchPosted(Arrays.asList( + new CoalescedEvent(notif1.key, 0, notif1.sbn, notif1.ranking, null), + new CoalescedEvent(notif2.key, 1, notif2.sbn, notif2.ranking, null), + new CoalescedEvent(notif3.key, 2, notif3.sbn, notif3.ranking, null), + new CoalescedEvent(notif4.key, 3, notif4.sbn, notif4.ranking, null), + new CoalescedEvent(notif5.key, 4, notif5.sbn, notif5.ranking, null) + )); + } + + private static final long MIN_LINGER_DURATION = 5; + private static final long MAX_LINGER_DURATION = 18; private static final String TEST_PACKAGE_A = "com.test.package_a"; private static final String TEST_PACKAGE_B = "com.test.package_b"; diff --git a/services/core/java/com/android/server/wm/RefreshRatePolicy.java b/services/core/java/com/android/server/wm/RefreshRatePolicy.java index e0a7b18f40c0..2cb7d5a23647 100644 --- a/services/core/java/com/android/server/wm/RefreshRatePolicy.java +++ b/services/core/java/com/android/server/wm/RefreshRatePolicy.java @@ -33,6 +33,27 @@ class RefreshRatePolicy { private final HighRefreshRateBlacklist mHighRefreshRateBlacklist; private final WindowManagerService mWmService; + /** + * The following constants represent priority of the window. SF uses this information when + * deciding which window has a priority when deciding about the refresh rate of the screen. + * Priority 0 is considered the highest priority. -1 means that the priority is unset. + */ + static final int LAYER_PRIORITY_UNSET = -1; + /** Windows that are in focus and voted for the preferred mode ID have the highest priority. */ + static final int LAYER_PRIORITY_FOCUSED_WITH_MODE = 0; + /** + * This is a default priority for all windows that are in focus, but have not requested a + * specific mode ID. + */ + static final int LAYER_PRIORITY_FOCUSED_WITHOUT_MODE = 1; + /** + * Windows that are not in focus, but voted for a specific mode ID should be + * acknowledged by SF. For example, there are two applications in a split screen. + * One voted for a given mode ID, and the second one doesn't care. Even though the + * second one might be in focus, we can honor the mode ID of the first one. + */ + static final int LAYER_PRIORITY_NOT_FOCUSED_WITH_MODE = 2; + RefreshRatePolicy(WindowManagerService wmService, DisplayInfo displayInfo, HighRefreshRateBlacklist blacklist) { mLowRefreshRateId = findLowRefreshRateModeId(displayInfo); @@ -92,4 +113,28 @@ class RefreshRatePolicy { } return 0; } + + /** + * Calculate the priority based on whether the window is in focus and whether the application + * voted for a specific refresh rate. + * + * TODO(b/144307188): This is a very basic algorithm version. Explore other signals that might + * be useful in edge cases when we are deciding which layer should get priority when deciding + * about the refresh rate. + */ + int calculatePriority(WindowState w) { + boolean isFocused = w.isFocused(); + int preferredModeId = getPreferredModeId(w); + + if (!isFocused && preferredModeId > 0) { + return LAYER_PRIORITY_NOT_FOCUSED_WITH_MODE; + } + if (isFocused && preferredModeId == 0) { + return LAYER_PRIORITY_FOCUSED_WITHOUT_MODE; + } + if (isFocused && preferredModeId > 0) { + return LAYER_PRIORITY_FOCUSED_WITH_MODE; + } + return LAYER_PRIORITY_UNSET; + } } diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index c2eb0e4492d5..36e9273a0904 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -657,6 +657,13 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private KeyInterceptionInfo mKeyInterceptionInfo; /** + * This information is passed to SurfaceFlinger to decide which window should have a priority + * when deciding about the refresh rate of the display. All windows have the lowest priority by + * default. The variable is cached, so we do not send too many updates to SF. + */ + int mFrameRateSelectionPriority = RefreshRatePolicy.LAYER_PRIORITY_UNSET; + + /** * @return The insets state as requested by the client, i.e. the dispatched insets state * for which the visibilities are overridden with what the client requested. */ @@ -5165,6 +5172,24 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } } + + /** + * Notifies SF about the priority of the window, if it changed. SF then uses this information + * to decide which window's desired rendering rate should have a priority when deciding about + * the refresh rate of the screen. Priority + * {@link RefreshRatePolicy#LAYER_PRIORITY_FOCUSED_WITH_MODE} is considered the highest. + */ + @VisibleForTesting + void updateFrameRateSelectionPriorityIfNeeded() { + final int priority = getDisplayContent().getDisplayPolicy().getRefreshRatePolicy() + .calculatePriority(this); + if (mFrameRateSelectionPriority != priority) { + mFrameRateSelectionPriority = priority; + getPendingTransaction().setFrameRateSelectionPriority(mSurfaceControl, + mFrameRateSelectionPriority); + } + } + @Override void prepareSurfaces() { final Dimmer dimmer = getDimmer(); @@ -5173,6 +5198,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP applyDims(dimmer); } updateSurfacePosition(); + // Send information to SufaceFlinger about the priority of the current window. + updateFrameRateSelectionPriorityIfNeeded(); mWinAnimator.prepareSurfaceLocked(true); super.prepareSurfaces(); diff --git a/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java new file mode 100644 index 000000000000..032edde61bec --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/FrameRateSelectionPriorityTests.java @@ -0,0 +1,161 @@ +/* + * Copyright 2020 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.server.wm; + +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; + +import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +import android.platform.test.annotations.Presubmit; + +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * This file tests WM setting the priority on windows that is used in SF to determine at what + * frame rate the Display should run. Any changes to the algorithm should be reflected in these + * tests. + * + * Build/Install/Run: atest FrameRateSelectionPriority + */ +@Presubmit +@RunWith(WindowTestRunner.class) +public class FrameRateSelectionPriorityTests extends WindowTestsBase { + + @Test + public void basicTest() { + final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow"); + assertNotNull("Window state is created", appWindow); + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // Priority doesn't change. + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + // Call the function a few times. + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + + // Since nothing changed in the priority state, the transaction should not be updating. + verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET); + } + + @Test + public void testApplicationInFocusWithoutModeId() { + final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow"); + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + assertEquals(appWindow.getDisplayContent().getDisplayPolicy().getRefreshRatePolicy() + .getPreferredModeId(appWindow), 0); + + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // Priority stays MAX_VALUE. + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + // Application is in focus. + appWindow.mToken.mDisplayContent.mCurrentFocus = appWindow; + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // Priority changes to 1. + assertEquals(appWindow.mFrameRateSelectionPriority, 1); + verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), 1); + } + + @Test + public void testApplicationInFocusWithModeId() { + final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow"); + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + // Application is in focus. + appWindow.mToken.mDisplayContent.mCurrentFocus = appWindow; + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // Priority changes. + assertEquals(appWindow.mFrameRateSelectionPriority, 1); + // Update the mode ID to a requested number. + appWindow.mAttrs.preferredDisplayModeId = 1; + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // Priority changes. + assertEquals(appWindow.mFrameRateSelectionPriority, 0); + + // Remove the mode ID request. + appWindow.mAttrs.preferredDisplayModeId = 0; + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // Priority changes. + assertEquals(appWindow.mFrameRateSelectionPriority, 1); + + // Verify we called actions on Transactions correctly. + verify(appWindow.getPendingTransaction(), never()).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET); + verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), 0); + verify(appWindow.getPendingTransaction(), times(2)).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), 1); + } + + @Test + public void testApplicationNotInFocusWithModeId() { + final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow"); + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + final WindowState inFocusWindow = createWindow(null, TYPE_APPLICATION, "inFocus"); + appWindow.mToken.mDisplayContent.mCurrentFocus = inFocusWindow; + + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // The window is not in focus. + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + // Update the mode ID to a requested number. + appWindow.mAttrs.preferredDisplayModeId = 1; + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // Priority changes. + assertEquals(appWindow.mFrameRateSelectionPriority, 2); + + verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET); + verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), 2); + } + + @Test + public void testApplicationNotInFocusWithoutModeId() { + final WindowState appWindow = createWindow(null, TYPE_APPLICATION, "appWindow"); + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + final WindowState inFocusWindow = createWindow(null, TYPE_APPLICATION, "inFocus"); + appWindow.mToken.mDisplayContent.mCurrentFocus = inFocusWindow; + + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // The window is not in focus. + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + // Make sure that the mode ID is not set. + appWindow.mAttrs.preferredDisplayModeId = 0; + appWindow.updateFrameRateSelectionPriorityIfNeeded(); + // Priority doesn't change. + assertEquals(appWindow.mFrameRateSelectionPriority, RefreshRatePolicy.LAYER_PRIORITY_UNSET); + + verify(appWindow.getPendingTransaction()).setFrameRateSelectionPriority( + appWindow.getSurfaceControl(), RefreshRatePolicy.LAYER_PRIORITY_UNSET); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java index f5d08dcfcb77..eda1fb8839a5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java +++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java @@ -250,4 +250,9 @@ public class StubTransaction extends SurfaceControl.Transaction { return this; } + @Override + public SurfaceControl.Transaction setFrameRateSelectionPriority(SurfaceControl sc, + int priority) { + return this; + } } diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java index 8ed4ee594d73..fee6d3fc4795 100644 --- a/telephony/java/android/telephony/SmsManager.java +++ b/telephony/java/android/telephony/SmsManager.java @@ -25,11 +25,12 @@ import android.annotation.RequiresPermission; import android.annotation.SuppressAutoDoc; import android.annotation.SystemApi; import android.annotation.TestApi; -import android.app.ActivityThread; import android.app.PendingIntent; +import android.compat.Compatibility; +import android.compat.annotation.ChangeId; +import android.compat.annotation.EnabledAfter; import android.compat.annotation.UnsupportedAppUsage; import android.content.Context; -import android.content.pm.PackageManager; import android.database.CursorWindow; import android.net.Uri; import android.os.Build; @@ -423,7 +424,7 @@ public final class SmsManager { String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, - true /* persistMessage*/, ActivityThread.currentPackageName()); + true /* persistMessage*/, null); } /** @@ -633,7 +634,7 @@ public final class SmsManager { String destinationAddress, String scAddress, String text, PendingIntent sentIntent, PendingIntent deliveryIntent) { sendTextMessageInternal(destinationAddress, scAddress, text, sentIntent, deliveryIntent, - false /* persistMessage */, ActivityThread.currentPackageName()); + false /* persistMessage */, null); } private void sendTextMessageInternal( @@ -676,7 +677,7 @@ public final class SmsManager { ISms iSms = getISmsServiceOrThrow(); if (iSms != null) { iSms.sendTextForSubscriberWithOptions(subId, - ActivityThread.currentPackageName(), destinationAddress, + null, destinationAddress, scAddress, text, sentIntent, deliveryIntent, persistMessage, finalPriority, expectMore, finalValidity); @@ -698,7 +699,7 @@ public final class SmsManager { ISms iSms = getISmsServiceOrThrow(); if (iSms != null) { iSms.sendTextForSubscriberWithOptions(getSubscriptionId(), - ActivityThread.currentPackageName(), destinationAddress, + null, destinationAddress, scAddress, text, sentIntent, deliveryIntent, persistMessage, finalPriority, expectMore, finalValidity); @@ -920,7 +921,7 @@ public final class SmsManager { String destinationAddress, String scAddress, ArrayList<String> parts, ArrayList<PendingIntent> sentIntents, ArrayList<PendingIntent> deliveryIntents) { sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, - deliveryIntents, true /* persistMessage*/, ActivityThread.currentPackageName()); + deliveryIntents, true /* persistMessage*/, null); } /** @@ -937,8 +938,9 @@ public final class SmsManager { * subscription. * </p> * - * @param packageName serves as the default package name if - * {@link ActivityThread#currentPackageName()} is null. + * @param packageName serves as the default package name if the package name that is + * associated with the user id is null. + * * @hide */ @SystemApi @@ -948,9 +950,7 @@ public final class SmsManager { @NonNull List<String> parts, @Nullable List<PendingIntent> sentIntents, @Nullable List<PendingIntent> deliveryIntents, @NonNull String packageName) { sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, - deliveryIntents, true /* persistMessage*/, - ActivityThread.currentPackageName() == null - ? packageName : ActivityThread.currentPackageName()); + deliveryIntents, true /* persistMessage*/, packageName); } private void sendMultipartTextMessageInternal( @@ -1051,7 +1051,7 @@ public final class SmsManager { String destinationAddress, String scAddress, List<String> parts, List<PendingIntent> sentIntents, List<PendingIntent> deliveryIntents) { sendMultipartTextMessageInternal(destinationAddress, scAddress, parts, sentIntents, - deliveryIntents, false /* persistMessage*/, ActivityThread.currentPackageName()); + deliveryIntents, false /* persistMessage*/, null); } /** @@ -1213,7 +1213,7 @@ public final class SmsManager { ISms iSms = getISmsServiceOrThrow(); if (iSms != null) { iSms.sendMultipartTextForSubscriberWithOptions(subId, - ActivityThread.currentPackageName(), destinationAddress, + null, destinationAddress, scAddress, parts, sentIntents, deliveryIntents, persistMessage, finalPriority, expectMore, finalValidity); } @@ -1235,7 +1235,7 @@ public final class SmsManager { ISms iSms = getISmsServiceOrThrow(); if (iSms != null) { iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(), - ActivityThread.currentPackageName(), destinationAddress, + null, destinationAddress, scAddress, parts, sentIntents, deliveryIntents, persistMessage, finalPriority, expectMore, finalValidity); } @@ -1366,7 +1366,7 @@ public final class SmsManager { public void onSuccess(int subId) { try { ISms iSms = getISmsServiceOrThrow(); - iSms.sendDataForSubscriber(subId, ActivityThread.currentPackageName(), + iSms.sendDataForSubscriber(subId, null, destinationAddress, scAddress, destinationPort & 0xFFFF, data, sentIntent, deliveryIntent); } catch (RemoteException e) { @@ -1492,7 +1492,6 @@ public final class SmsManager { private void resolveSubscriptionForOperation(SubscriptionResolverResult resolverResult) { int subId = getSubscriptionId(); boolean isSmsSimPickActivityNeeded = false; - final Context context = ActivityThread.currentApplication().getApplicationContext(); try { ISms iSms = getISmsService(); if (iSms != null) { @@ -1514,14 +1513,14 @@ public final class SmsManager { return; } // We need to ask the user pick an appropriate subid for the operation. - Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for package " - + context.getPackageName()); + Log.d(TAG, "resolveSubscriptionForOperation isSmsSimPickActivityNeeded is true for calling" + + " package. "); try { // Create the SMS pick activity and call back once the activity is complete. Can't do // it here because we do not have access to the activity context that is performing this // operation. // Requires that the calling process has the SEND_SMS permission. - getITelephony().enqueueSmsPickResult(context.getOpPackageName(), + getITelephony().enqueueSmsPickResult(null, new IIntegerConsumer.Stub() { @Override public void accept(int subId) { @@ -1539,6 +1538,13 @@ public final class SmsManager { } } + /** + * To check the SDK version for SmsManager.sendResolverResult method. + */ + @ChangeId + @EnabledAfter(targetSdkVersion = Build.VERSION_CODES.P) + private static final long GET_TARGET_SDK_VERSION_CODE_CHANGE = 145147528L; + private void sendResolverResult(SubscriptionResolverResult resolverResult, int subId, boolean pickActivityShown) { if (SubscriptionManager.isValidSubscriptionId(subId)) { @@ -1546,7 +1552,8 @@ public final class SmsManager { return; } - if (getTargetSdkVersion() <= Build.VERSION_CODES.P && !pickActivityShown) { + if (!Compatibility.isChangeEnabled(GET_TARGET_SDK_VERSION_CODE_CHANGE) + && !pickActivityShown) { // Do not fail, return a success with an INVALID subid for apps targeting P or below // that tried to perform an operation and the SMS disambiguation dialog was never shown, // as these applications may not have been written to handle the failure case properly. @@ -1559,19 +1566,6 @@ public final class SmsManager { } } - private static int getTargetSdkVersion() { - final Context context = ActivityThread.currentApplication().getApplicationContext(); - int targetSdk; - try { - targetSdk = context.getPackageManager().getApplicationInfo( - context.getOpPackageName(), 0).targetSdkVersion; - } catch (PackageManager.NameNotFoundException e) { - // Default to old behavior if we can not find this. - targetSdk = -1; - } - return targetSdk; - } - private static ITelephony getITelephony() { ITelephony binder = ITelephony.Stub.asInterface( TelephonyFrameworkInitializer @@ -1657,7 +1651,7 @@ public final class SmsManager { ISms iSms = getISmsService(); if (iSms != null) { success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(), - ActivityThread.currentPackageName(), + null, status, pdu, smsc); } } catch (RemoteException ex) { @@ -1698,7 +1692,7 @@ public final class SmsManager { ISms iSms = getISmsService(); if (iSms != null) { success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(), - ActivityThread.currentPackageName(), + null, messageIndex, STATUS_ON_ICC_FREE, null /* pdu */); } } catch (RemoteException ex) { @@ -1741,7 +1735,7 @@ public final class SmsManager { ISms iSms = getISmsService(); if (iSms != null) { success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(), - ActivityThread.currentPackageName(), + null, messageIndex, newStatus, pdu); } } catch (RemoteException ex) { @@ -1793,7 +1787,7 @@ public final class SmsManager { if (iSms != null) { records = iSms.getAllMessagesFromIccEfForSubscriber( getSubscriptionId(), - ActivityThread.currentPackageName()); + null); } } catch (RemoteException ex) { // ignore it @@ -2617,7 +2611,7 @@ public final class SmsManager { try { ISms iccSms = getISmsServiceOrThrow(); return iccSms.createAppSpecificSmsToken(getSubscriptionId(), - ActivityThread.currentPackageName(), intent); + null, intent); } catch (RemoteException ex) { ex.rethrowFromSystemServer(); @@ -2737,7 +2731,7 @@ public final class SmsManager { try { ISms iccSms = getISmsServiceOrThrow(); return iccSms.createAppSpecificSmsTokenWithPackageInfo(getSubscriptionId(), - ActivityThread.currentPackageName(), prefixes, intent); + null, prefixes, intent); } catch (RemoteException ex) { ex.rethrowFromSystemServer(); @@ -2828,7 +2822,7 @@ public final class SmsManager { ISms iccISms = getISmsServiceOrThrow(); if (iccISms != null) { return iccISms.checkSmsShortCodeDestination(getSubscriptionId(), - ActivityThread.currentPackageName(), null, destAddress, countryIso); + null, null, destAddress, countryIso); } } catch (RemoteException e) { Log.e(TAG, "checkSmsShortCodeDestination() RemoteException", e); @@ -2864,7 +2858,7 @@ public final class SmsManager { ISms iSms = getISmsService(); if (iSms != null) { smsc = iSms.getSmscAddressFromIccEfForSubscriber( - getSubscriptionId(), ActivityThread.currentPackageName()); + getSubscriptionId(), null); } } catch (RemoteException ex) { // ignore it @@ -2898,7 +2892,7 @@ public final class SmsManager { ISms iSms = getISmsService(); if (iSms != null) { return iSms.setSmscAddressOnIccEfForSubscriber( - smsc, getSubscriptionId(), ActivityThread.currentPackageName()); + smsc, getSubscriptionId(), null); } } catch (RemoteException ex) { // ignore it diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java index 36f541f0a81d..b42ce35aa79c 100644 --- a/telephony/java/android/telephony/SubscriptionManager.java +++ b/telephony/java/android/telephony/SubscriptionManager.java @@ -2232,6 +2232,7 @@ public class SubscriptionManager { } else { logd("putPhoneIdAndSubIdExtra: no valid subs"); intent.putExtra(PhoneConstants.PHONE_KEY, phoneId); + intent.putExtra(EXTRA_SLOT_INDEX, phoneId); } } diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index 13aad7eee7b0..56ca8c7790cb 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -37,7 +37,6 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.WorkerThread; -import android.app.ActivityThread; import android.app.PendingIntent; import android.compat.Compatibility; import android.compat.annotation.ChangeId; @@ -380,8 +379,17 @@ public class TelephonyManager { // effort and get the context from the current activity thread. if (mContext != null) { return mContext.getOpPackageName(); + } else { + ITelephony telephony = getITelephony(); + if (telephony == null) return null; + try { + return telephony.getCurrentPackageName(); + } catch (RemoteException ex) { + return null; + } catch (NullPointerException ex) { + return null; + } } - return ActivityThread.currentOpPackageName(); } private String getFeatureId() { diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl index cdb95a8193b4..a8e76b9d7902 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -2087,6 +2087,11 @@ interface ITelephony { int getRadioHalVersion(); /** + * Get the current calling package name. + */ + String getCurrentPackageName(); + + /** * Returns true if the specified type of application (e.g. {@link #APPTYPE_CSIM} is present * on the UICC card. * @hide diff --git a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt index 99a26dc80288..3c55237ce443 100644 --- a/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +++ b/tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt @@ -53,36 +53,38 @@ object ProtoLogTool { val executor = newThreadPool() - command.javaSourceArgs.map { path -> - executor.submitCallable { - val transformer = SourceTransformer(command.protoLogImplClassNameArg, - command.protoLogCacheClassNameArg, processor) - val file = File(path) - val text = injector.readText(file) - val outSrc = try { - val code = tryParse(text, path) - if (containsProtoLogText(text, command.protoLogClassNameArg)) { - transformer.processClass(text, path, packagePath(file, code), code) - } else { + try { + command.javaSourceArgs.map { path -> + executor.submitCallable { + val transformer = SourceTransformer(command.protoLogImplClassNameArg, + command.protoLogCacheClassNameArg, processor) + val file = File(path) + val text = injector.readText(file) + val outSrc = try { + val code = tryParse(text, path) + if (containsProtoLogText(text, command.protoLogClassNameArg)) { + transformer.processClass(text, path, packagePath(file, code), code) + } else { + text + } + } catch (ex: ParsingException) { + // If we cannot parse this file, skip it (and log why). Compilation will + // fail in a subsequent build step. + injector.reportParseError(ex) text } - } catch (ex: ParsingException) { - // If we cannot parse this file, skip it (and log why). Compilation will fail - // in a subsequent build step. - injector.reportParseError(ex) - text + path to outSrc } - path to outSrc + }.map { future -> + val (path, outSrc) = future.get() + outJar.putNextEntry(ZipEntry(path)) + outJar.write(outSrc.toByteArray()) + outJar.closeEntry() } - }.map { future -> - val (path, outSrc) = future.get() - outJar.putNextEntry(ZipEntry(path)) - outJar.write(outSrc.toByteArray()) - outJar.closeEntry() + } finally { + executor.shutdown() } - executor.shutdown() - val cacheSplit = command.protoLogCacheClassNameArg.split(".") val cacheName = cacheSplit.last() val cachePackage = cacheSplit.dropLast(1).joinToString(".") @@ -153,30 +155,32 @@ ${updates.replaceIndent(" ")} val executor = newThreadPool() - command.javaSourceArgs.map { path -> - executor.submitCallable { - val file = File(path) - val text = injector.readText(file) - if (containsProtoLogText(text, command.protoLogClassNameArg)) { - try { - val code = tryParse(text, path) - builder.findLogCalls(code, path, packagePath(file, code)) - } catch (ex: ParsingException) { - // If we cannot parse this file, skip it (and log why). Compilation will fail - // in a subsequent build step. - injector.reportParseError(ex) + try { + command.javaSourceArgs.map { path -> + executor.submitCallable { + val file = File(path) + val text = injector.readText(file) + if (containsProtoLogText(text, command.protoLogClassNameArg)) { + try { + val code = tryParse(text, path) + builder.findLogCalls(code, path, packagePath(file, code)) + } catch (ex: ParsingException) { + // If we cannot parse this file, skip it (and log why). Compilation will + // fail in a subsequent build step. + injector.reportParseError(ex) + null + } + } else { null } - } else { - null } + }.forEach { future -> + builder.addLogCalls(future.get() ?: return@forEach) } - }.forEach { future -> - builder.addLogCalls(future.get() ?: return@forEach) + } finally { + executor.shutdown() } - executor.shutdown() - val out = injector.fileOutputStream(command.viewerConfigJsonArg) out.write(builder.build().toByteArray()) out.close() diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index a9621fc6fb34..b2fbb401dde5 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -856,18 +856,6 @@ public class WifiConfiguration implements Parcelable { /** * @hide - * For debug: date at which the config was last updated - */ - public String updateTime; - - /** - * @hide - * For debug: date at which the config was last updated - */ - public String creationTime; - - /** - * @hide * The WiFi configuration is considered to have no internet access for purpose of autojoining * if there has been a report of it having no internet access, and, it never have had * internet access in the past. @@ -1493,12 +1481,6 @@ public class WifiConfiguration implements Parcelable { private String mConnectChoice; /** - * The system timestamp when we records the connectChoice. This value is obtained from - * System.currentTimeMillis - */ - private long mConnectChoiceTimestamp = INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP; - - /** * Used to cache the temporary candidate during the network selection procedure. It will be * kept updating once a new scan result has a higher score than current one */ @@ -1601,25 +1583,6 @@ public class WifiConfiguration implements Parcelable { mConnectChoice = newConnectChoice; } - /** - * get the timeStamp when user select a choice over this configuration - * @return returns when current connectChoice is set (time from System.currentTimeMillis) - * @hide - */ - public long getConnectChoiceTimestamp() { - return mConnectChoiceTimestamp; - } - - /** - * set the timeStamp when user select a choice over this configuration - * @param timeStamp, the timestamp set to connectChoiceTimestamp, expected timestamp should - * be obtained from System.currentTimeMillis - * @hide - */ - public void setConnectChoiceTimestamp(long timeStamp) { - mConnectChoiceTimestamp = timeStamp; - } - /** Get the current Quality network selection status as a String (for debugging). */ @NonNull public String getNetworkStatusString() { @@ -1902,7 +1865,6 @@ public class WifiConfiguration implements Parcelable { setCandidate(source.getCandidate()); setCandidateScore(source.getCandidateScore()); setConnectChoice(source.getConnectChoice()); - setConnectChoiceTimestamp(source.getConnectChoiceTimestamp()); setHasEverConnected(source.getHasEverConnected()); } @@ -1919,7 +1881,6 @@ public class WifiConfiguration implements Parcelable { if (getConnectChoice() != null) { dest.writeInt(CONNECT_CHOICE_EXISTS); dest.writeString(getConnectChoice()); - dest.writeLong(getConnectChoiceTimestamp()); } else { dest.writeInt(CONNECT_CHOICE_NOT_EXISTS); } @@ -1938,10 +1899,8 @@ public class WifiConfiguration implements Parcelable { setNetworkSelectionBSSID(in.readString()); if (in.readInt() == CONNECT_CHOICE_EXISTS) { setConnectChoice(in.readString()); - setConnectChoiceTimestamp(in.readLong()); } else { setConnectChoice(null); - setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP); } setHasEverConnected(in.readInt() != 0); } @@ -2165,9 +2124,6 @@ public class WifiConfiguration implements Parcelable { } if (mNetworkSelectionStatus.getConnectChoice() != null) { sbuf.append(" connect choice: ").append(mNetworkSelectionStatus.getConnectChoice()); - sbuf.append(" connect choice set time: ") - .append(logTimeOfDay( - mNetworkSelectionStatus.getConnectChoiceTimestamp())); } sbuf.append(" hasEverConnected: ") .append(mNetworkSelectionStatus.getHasEverConnected()).append("\n"); @@ -2179,12 +2135,6 @@ public class WifiConfiguration implements Parcelable { sbuf.append(" numNoInternetAccessReports "); sbuf.append(this.numNoInternetAccessReports).append("\n"); } - if (this.updateTime != null) { - sbuf.append(" update ").append(this.updateTime).append("\n"); - } - if (this.creationTime != null) { - sbuf.append(" creation ").append(this.creationTime).append("\n"); - } if (this.validatedInternetAccess) sbuf.append(" validatedInternetAccess"); if (this.ephemeral) sbuf.append(" ephemeral"); if (this.osu) sbuf.append(" osu"); @@ -2731,8 +2681,6 @@ public class WifiConfiguration implements Parcelable { allowAutojoin = source.allowAutojoin; numNoInternetAccessReports = source.numNoInternetAccessReports; noInternetAccessExpected = source.noInternetAccessExpected; - creationTime = source.creationTime; - updateTime = source.updateTime; shared = source.shared; recentFailure.setAssociationStatus(source.recentFailure.getAssociationStatus()); mRandomizedMacAddress = source.mRandomizedMacAddress; |